观心静

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

前言

  在之前的博客里,说明了 Android开发 拖拽DragShadowBuilder与OnDragListener使用讲解 Android开发 拖拽ViewDragHelper使用讲解 如何使用。 但是,后续jetpack系列又推出了DragAndDrop库。 DragAndDrop库是DragShadowBuilder的再封装。 DragAndDrop这个库封装后使用非常简单并且携带拖放的选中边框UI。当然简化的封装意味着UI设计与功能设计自由度上的减少。 这需要根据你的业务情况酌情选择直接使用DragShadowBuilder或者使用更简单的DragAndDrop。 个人实际体验DragAndDrop也可以跨进程分享,但是DragAndDrop其实更适合在富文本的图片文字内容的拖拽编辑的业务场景下。

  个人还是强烈建议你先了解 DragShadowBuilder: Android开发 拖拽DragShadowBuilder与OnDragListener使用讲解

  DragAndDrop官方文档地址: https://developer.android.google.cn/jetpack/androidx/releases/draganddrop?hl=zh-cn

依赖

dependencies {
    implementation("androidx.draganddrop:draganddrop:1.0.0")
}

一个简单的例子

  这是一个文本复制拖放的例子,从这个例子的代码量你就能体会到封装的有多简单。

效果图

代码

下面的代码中topEditText作为可拖动的内容,bottomEditText作为拖动内容的接收者。

请注意下面代码中的attach()方法很重要,请记得一点要添加上,attach的源码里就是包含了将添加的view设置长按开始拖动的监听。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(mBinding.root)
    initView()
}

private fun initView() {
    /**
     * 设置要拖动的View
     */
    DragStartHelper(mBinding.topEditText) { v, helper ->
        val dragdata = ClipData.newPlainText("content", mBinding.topEditText.text.toString())
        val shadow: View.DragShadowBuilder = View.DragShadowBuilder(v)
        v.startDragAndDrop(dragdata, shadow, null, 0)
        return@DragStartHelper true
    }.attach()

    /**
     * 设置要接受拖放内容的View
     */
    //配置拖动选中效果
    val option = DropHelper.Options.Builder()
        .setHighlightColor(resources.getColor(android.R.color.background_dark)) //设置拖动时选择放置位置的边框高亮颜色
        .setHighlightCornerRadiusPx(20) //设置拖动时选择放置位置的边框圆角半径
        .build()
    //支持的 MIME 类型
    val mimeTypeArray = arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)
    DropHelper.configureView(this, mBinding.bottomEditText, mimeTypeArray, option, object : OnReceiveContentListener {
        override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat {
            Log.e("zh", "onReceiveContent: view = ${view}")
            Log.e("zh", "onReceiveContent: payload = ${payload}")
            return payload
        }
    })
}

多EditText使用情况的addInnerEditTexts设置

体验一下addInnerEditTexts的效果

效果图

添加了addInnerEditTexts的editText高亮效果不同

代码

xml

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@null"
        android:padding="20dp"
        android:text="测试文本"
        android:gravity="center"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <LinearLayout
        android:id="@+id/bottomLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="50dp"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/text1">

        <EditText
            android:id="@+id/editText1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="20dp"
            android:text=""
            android:textSize="18sp"
            android:background="@drawable/shape_text_frame"
            android:layout_marginTop="30dp"/>

        <EditText
            android:id="@+id/editText2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/shape_text_frame"
            android:padding="20dp"
            android:text=""
            android:textSize="18sp"
            android:layout_marginTop="30dp"/>

        <EditText
            android:id="@+id/editText3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/shape_text_frame"
            android:padding="20dp"
            android:text=""
            android:textSize="18sp"
            android:layout_marginTop="30dp"/>

        <EditText
            android:id="@+id/editText4"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/shape_text_frame"
            android:padding="20dp"
            android:text=""
            android:textSize="18sp"
            android:layout_marginTop="30dp"/>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

代码

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(mBinding.root)
    initView()
}

private fun initView() {
    /**
     * 设置要拖动的View
     */
    DragStartHelper(mBinding.text1) { v, helper ->
        val dragdata = ClipData.newPlainText("content", mBinding.text1.text.toString())
        val shadow: View.DragShadowBuilder = View.DragShadowBuilder(v)
        v.startDragAndDrop(dragdata, shadow, null, 0)
        return@DragStartHelper true
    }.attach()

    /**
     * 设置要接受拖放内容的View
     */
    //配置拖动选中效果
    val option = DropHelper.Options.Builder()
        .setHighlightColor(resources.getColor(android.R.color.holo_blue_bright)) //设置拖动时选择放置位置的边框高亮颜色
        .setAcceptDragsWithLocalState(true)
        .addInnerEditTexts(mBinding.editText1)
        .build()
    //支持的 MIME 类型
    val mimeTypeArray = arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)
    DropHelper.configureView(this, mBinding.bottomLayout, mimeTypeArray, option, object : OnReceiveContentListener {
        override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat {
            Log.e("zh", "onReceiveContent: view = ${view}")
            Log.e("zh", "onReceiveContent: payload = ${payload}")
            return payload
        }
    })
}

列表交换位置效果

实现后其实ui效果没有使用DragShadowBuilder实现的方式好,但是胜在特别特别简单。选中的框框没想到怎么不显示,所以个人觉得DragAndDrop还是适合实现拖动富文本内容的功能。

效果图

代码

代码是使用RecyclerView.Adapter实现的,所以这里只展现RecyclerView.Adapter里的关键代码

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val binding = ItemTextBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    val viewHolder = ViewHolder(binding)

    DragStartHelper(binding.root) { v, helper ->
        val position = viewHolder.adapterPosition
        if (position == RecyclerView.NO_POSITION) {
            return@DragStartHelper false
        }
        //这里使用intent传递数据,实际上并不需要这么麻烦。因为intent传递数据适合在跨进程上使用。
        //这里只是为了展示intent传递数据的使用方式才故意写出来。
        val intent = Intent()
        intent.putExtra("position", position)
        val dragdata = ClipData.newIntent("oldPosition", intent)
        val shadow: DragShadowBuilder = DragShadowBuilder(v)
        v.startDragAndDrop(dragdata, shadow, null, 0)
        return@DragStartHelper true
    }.attach()

    val option = DropHelper.Options.Builder()
        .setHighlightColor(parent.context.resources.getColor(android.R.color.transparent))
        .setHighlightCornerRadiusPx(0)
        .setAcceptDragsWithLocalState(false)
        .build()
    val mimeTypeArray = arrayOf(ClipDescription.MIMETYPE_TEXT_INTENT)

    DropHelper.configureView(parent.context as Activity, binding.root, mimeTypeArray, option, object : OnReceiveContentListener {
            override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat {
                var dragViewPosition = parent.indexOfChild(view)
                var affectedViewPosition = payload.clip.getItemAt(0).intent.getIntExtra("position", 0)
                Log.e("zh", "dragViewPosition = ${dragViewPosition} ", )
                Log.e("zh", "affectedViewPosition = ${affectedViewPosition} ", )
                //交换我们数据List的位置
                Collections.swap(mList, dragViewPosition, affectedViewPosition)
                //更新AdapterItem的视图位置
                this@MainAdapter.notifyDataSetChanged()
                return payload
            }
        })

    return viewHolder
}

 

end

posted on 2023-06-08 17:03  观心静  阅读(367)  评论(0编辑  收藏  举报