在查看官方文档之前,我一直以为在Android实现拖放功能应该要处理不少问题,比如追踪手势、更新View的位置等等,但是实际上Android SDK已经把拖放功能的接口封装得足够简单易用,如果再加上Jetpack DragAndDrop库,就只需要根据业务把参数设置好就行了,完全不用关心拖放的实现。
在没有使用Jetpack DragAndDrop
之前,一般会监听View的长按事件OnLongClickListener,当长按触发之后开始处理拖放逻辑,其实DragStartHelper内部也是这样。
v.setOnLongClickListener { view ->
//设置拖放需要传递的数据,可传递类型可参考ClipData
val data = ClipData.newPlainText("", text)
//View拖动的效果绘制,可通过重写onDrawShadow自定义
val shadowBuilder = View.DragShadowBuilder(view)
//开始拖动
view.startDragAndDrop(data, shadowBuilder, view, View.DRAG_FLAG_GLOBAL)
true
}
当调用startDragAndDrop之后,会触发OnDragListener回调,我们可以在这里实现业务逻辑,比如说当开始拖动时隐藏原来位置的View。
v.setOnDragListener { view, dragEvent ->
when (dragEvent.action) {
//当拖动开始时,隐藏当前view
DragEvent.ACTION_DRAG_ENTERED -> view.visibility = View.INVISIBLE
}
true
}
另外用于接收拖动的View也会触发OnDragListener回调,可以在回调中处理业务逻辑,比如更改背景或者闪烁,暗示用户此处可以拖放。
1container.setOnDragListener { view, dragEvent ->
2 when (dragEvent.action) {
3 //当有View开始拖动时,将当前container背景改成红色
4 DragEvent.ACTION_DRAG_STARTED -> {
5 container.setBackgroundColor(Color.RED)
6 }
7 //拖动结束时,恢复container背景为白色
8 DragEvent.ACTION_DRAG_ENDED -> {
9 container.setBackgroundColor(Color.WHITE)
10 }
11 //拖动View到当前container内时,通过DragEvent拿到数据
12 DragEvent.ACTION_DROP -> {
13 val data = dragEvent.clipData
14 ...
15 }
16 }
17 true
18}
上面就是实现拖放功能需要处理的逻辑,总结下来就两步,一是触发拖动,调用startDragAndDrop,二是监听拖动事件调用setOnDragListener。
当使用Jetpack DragAndDrop
之后,由于DragStartHelper在内部处理了长按事件,无需单独设置,用法如下
DragStartHelper(v) { view, _ ->
//触发拖放
val data = ClipData.newPlainText("", word)
val shadowBuilder = View.DragShadowBuilder(view)
view.startDragAndDrop(data, shadowBuilder, view, 0)
true
}.attach()
看上去好像没有简化什么,DragStartHelper的好处有两点
通过DropHelper来处理接收拖动的业务逻辑,也就是上面代码中container相关的业务逻辑。
1DropHelper.configureView(
2 activity,
3 container,
4 arrayOf( //配置触发容器高亮数据类型
5 "text/plain",
6 "image/*",
7 "application/x-arc-uri-list"
8 ),
9 DropHelper.Options.Builder()
10 .setHighlightColor(Color.RED)//设置拖动容器的高亮颜色
11 .build()
12) { view, payload ->
13 //处理数据
14 val data = payload.clip
15 ...
16}
DropHelper将监听拖动事件和高亮效果封装在一起,使得调用变得更加紧凑,另外它针对container中存在EditText的情况进行了特殊处理,参考:Options.Builder#addInnerEditTexts,还有一点,它支持多窗口模式,不同窗口之间进行拖动。
完整的示例代码如下
参考: DragStartHelper
注释文件 | 大小 | 修改时间 |
---|---|---|
app | 2022年04月13日 | |
build.gradle | 161 B | 2022年04月13日 |
gradle/wrapper | 2022年04月13日 | |
gradle.properties | 1 kB | 2022年04月13日 |
gradlew | 6 kB | 2022年04月13日 |
gradlew.bat | 3 kB | 2022年04月13日 |
local.properties | 345 B | 2022年04月13日 |
README.md | 1 kB | 2022年04月13日 |
settings.gradle | 466 B | 2022年04月13日 |