拖放功能简单实现之DragAndDrop

Android示例项目集合
2021-05-17 14:29 · 阅读时长5分钟
小课

在查看官方文档之前,我一直以为在Android实现拖放功能应该要处理不少问题,比如追踪手势、更新View的位置等等,但是实际上Android SDK已经把拖放功能的接口封装得足够简单易用,如果再加上Jetpack DragAndDrop库,就只需要根据业务把参数设置好就行了,完全不用关心拖放的实现。

  • 在应用内拖放效果
拖放功能简单实现之DragAndDrop
  • 在应用间拖放效果
拖放功能简单实现之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的好处有两点

  • 记录了当前触摸点,可以通过DragShadowBuilder.onProvideShadowMetrics回调设置拖动视图的锚点,提升用户体验。
  • 处理了拖放与当前View已有的OnTouchListener和OnLongClickListener的兼容,需要自己调用。

通过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日
拖放拖拽OnDragListenerDragstartDragAndDropJetpack DragAndDrop