只需一根手指,用户就可以移动或复制照片和其他内容。他们可以将内容从一个位置拖到另外一个,再松开手指放下它。
按住选中的内容会使得它好像抬升并黏附到手指上。拖动内容时,动画和其他一些视觉指引会告诉用户可以把它放到哪里。如果某个地方无法放置,或者不能移动只能复制,则系统也会显示对应的徽标告知用户。更多开发者指南,在 UIKit 中查看 Drag and Drop。
源头和目的地 (Source and Destinations)
拖放操作是指将选中的内容从一个地方移动到另一个地方。这些地点可以在同一个容器中—比如文本区域 (text view) 里;也可以在不同的容器当中,比如在分屏视图 (split view) 两侧的两个文本区域里。举例来说,在备忘录当中,用户可以把一段文字拖动到同一篇笔记里的不同位置。而在提醒事项当中,用户可以把单个的提醒项目从一个列表拖动到另一个列表。
在 iPad 上,拖放操作的来源和目的地也可以在不同的应用当中,这使得夸应用的操作成为可能。比如,你可以把网页中的图片从 Safari 浏览器拖动到邮件应用当中。当你在拖动内容时,用户可以通过多任务处理功能访问其他应用。你可以退回到主屏幕,或者从屏幕底部上滑呼出程序坞。
✏️ 注意 在应用之间使用拖放会复制内容,而不是移动内容。
支持拖放 (Supporting Drag and Drop)
拖放是一项高效、符合直觉的功能。用户会希望它能够在系统中得到广泛的应用。如果你的应用包含或能够制作文本、照片、视频、音频内容,或者其中有其他用户可能想要移动、复制或插入的内容,那么你的应用就应该支持拖放操作。
让拖放对于所有的可选择和可编辑内容生效。可选择内容应该可以被拖动,同时可编辑的内容也应该接受拖放过来的内容。同时,你也需要你的应用在这些区域支持复制和粘贴。
情况合适时,应当允许拖放内容到控件上。总体来说,可以输入数据或进行选择的控件,也应该接受拖放来的内容。
尽可能使用标准化的文本视图 (text views) 和文本域 (text fields)。这些系统提供的元素包含了对拖放的支持。更多相关信息,查看文本域和文本视图。更多开发信息,可以查看 UITextField 和 UITextView。
为了提升效率,可以考虑支持多个对象的拖放。在许多应用中,用户可能在用一只手指拖动对象的同时,使用另一只手指点击选择更多的对象。这些对象以叠放的形式出现在第一个选中的项目下方,跟随手指一起移动。用户可以把这些对象作为一个群组拖放到他们想要的地方。举例来说,主屏幕就支持多个应用图标一起被拖放到一个文件夹当中。照片应用就提供了一个选择模式,以便让用户在拖动内容之前可以选中多个对象。
考虑对于你的应用而言,在其中拖放内容对应的实际操作到底是移动还是复制。总的来说,如果拖放操作的来源和目的地在同一容器当中(比如在一份文档中拖动文字),则应该使用移动;如果容器不同,则应该使用复制(比如在文档之间或应用之间拖移)。然而,这并不是一定的。无论如何,拖放操作应该符合直觉。在提醒事项当中为了符合用户预期,在列表之间拖动事件产生的效果是移动而非复制。不过,在应用之间进行拖放最终执行的总是复制。
尽可能允许用户撤销拖放操作。一般来说,如果用户不经意间把内容拖到了错误的目的地,那么他们应该能够撤销这一操作,或回退到操作之前的状态。这意味着放下的内容应当被删除。如果内容是从别处移动过来的,则应该把内容放回原来的位置。
考虑支持弹开载入 (spring loading)。如果开启了弹开载入,对于按钮或分段选择器这样的控件来说,用户无需放下内容,只要把拖动的内容悬停在控件上面,就可以进行操作。举例来说,在邮件应用中,选中的信息可以被拖动悬停到导航栏的返回按钮上,从而完成返回操作。不要让弹开载入成为激活某个控件的唯一方式。它的作用是锦上添花。在大多数情况下,一个支持弹开载入的操作也会支持点击。更多开发者指南,查看UISpring-LoadedInteraction。
提供被拖动的内容 (Providing Dragged Content)
必要的话,可以定制拖动对象的预览。一般来说,用户手指下被拖动的对象应该呈半透明状,以便指示其状态。这种样式可以体现出前因后果,表达拖动状态,使得用户能够看到拖动内容下面的目的地。
尽可能提供被拖移数据的多种不同保真度的替身。举例来说,如果你要提供一张数据图,你的应用可以按顺序提供一个 PDF 格式的矢量文件替身,一个无损的 PNG 图片,和一个压缩过的,无透明度的 JPEG 图片。这样一来,目的地的应用就可以选择它能够导入的最高清晰度的替身。
尽可能提供信息最为丰富的,原生类型的内容对象。举例来说,一个允许人们拖动图表的应用应该首先展示原生的图表对象。而后,它也应该提供替身,比如图片格式的图表,以便不支持原生格式的应用导入。
如果你应用中的内容传输起来非常耗时或会占用大量资源,你需要植入一个文件提供 (file provider) 扩展。文件提供扩展可以处理传输过程,并且即使你的应用中间停止运行,它仍然能保证传输成功。需要注意的是,只有在用户放下内容后,传输过程才会开始。更多开发者指南,查看 NSFileProviderExtension 。
如果应用中的文件传输需要一些时间,展示进度信息。如果有一些需要下载的文件,或者文件较大复制需要时间,便需要展示进度信息。至少你应该提供内容的总大小,以便目的地应用可以计算传输所需的剩余时间,并用合适的进度指示器来展示。更多开发者指南,查看 NSProgress 。
接受拖放的内容 (Accepting Dropped Content)
使用视觉线索来标记潜在的拖放目的地,同时预览放下内容的效果。高亮、插入指针 (insertion point indicators),还有动画都是表达潜在目的地的好方法。当被拖动的内容略过某个视图,他可以微弱地闪烁并改变颜色;已经存在的文字段落可以移动到别处,为拖来的图片留出空间。如果屏幕上存在多个可能的目的地,那么在同一时刻只应当突出一个。如果来源和目的地存在于同一容器,高亮操作可能就没有必要了。除非内容被完全拖出来源容器,而后又重新被拖动回来。如果内容已经被放下,或者不再悬停在目的地上方,则对潜在目的地的高亮也应该取消。
在恰当的时候,自动滚动目的地的内容。当内容被拖到了目的地的边界以外,你的应用可能需要决定到底是滚动目的地容器中的内容,还是让用户把选中项拖到完全不同的目的地。如果你的应用允许用户继续拖移,那么最好定义一个区域,当用户拖动到对象悬停在这个区域时,使得下面的视图自动滚动。举例来说,当一些选中的内容被拖动到邮件邮件编辑页面的顶部或底部,而编辑区内已经有的文字又比较长,那么编辑区域内的内容就会开始滚动。标准化的文字视图和文本域会自动支持这种行为。
对于接收到的内容,尽可能提取和展示信息最为丰富的版本。举例来说,你的应用可能接收到同一个图表的多种格式的文件。如果你的应用支持图表,那么它就可以提取并显示原生的图表文件。如果你的应用不支持图表,它可以提取并展示图表的图片版本。
对于拖放的内容,只提取其中可用的、相关的部分。比如说,如果用户把联系人信息拖放到了邮件消息的编辑区里,其中只需要填入名字和电子邮箱地址即可,并不需要一并吧联系人地址信息也拖放过来。
在列表视图 (table view) 和集合视图 (collection view) 中,一旦放下内容,立即展示占位符。在拖放内容完成传输之前,占位符临时出现,标记内容最终会落到的位置。
如果放下的内容需要时间传输,展示进度信息。默认情况下,如果一个跨应用传输数据的进程需要较长时间,系统会自动在应用中展示一个模态警告 (app-modal alert) 。你可以定制进度的样式,比如在列表视图和集合视图里,就可以在占位符上显示进度指示器。这样,用户仍然可以正常使用应用中其他的功能。需要注意的是,只有在用户放下内容之后,传输进程才会开始。
如果放下的内容会触发一个进程,提供对应的反馈。当用户把内容放到控件上,可能会触发一个任务。向网站上传视频就是一个很好的例子。这个时候,软件应该告诉用户这项任务已经开始,并在过程中向用户反馈它的进度。
如果拖放失败,通知用户。由于文件传输中止等原因,放下的文件可能无法成功插入目的地。这个时候,你的软件需要告知用户这次拖放没有成功。
为放下的内容赋予恰当的样式。如果来源和目的地都支持相同的一系列字体属性,那么被放下的内容也应该保持原先的字形 (font) 、字体 (typeface) 、字号和其他属性。另一种选择是让放下的文字跟随目的地的样式设置。
在某些用户无法立即撤销拖放操作的情形下,考虑提供某种巧妙、符合直觉的退出方式。举例来说,一个分享类应用,在它发布用户拖入的内容之前,会先打开一个临时的分享页面。这个分享页面可以展示状态等额外信息,也可以提供取消按钮。当某张图片被拖入到一个分享的照片流时,它可能会展现出这样的行为。