前言
在之前的博客里,说明了 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
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17466471.html