引言
今天,就来实现一下RecyclerView的重排序,即拖拽每个ItemView能完成重新布局,当然少不了DataBinding做数据绑定,Kotlin再加上ItemBinding写起来代码量也能精简不少,,一起来看看吧。话不多说,先上效果。
效果
分步实现
-
第一步:添加依赖
//Databinding
kapt "com.android.databinding:compiler:3.1.4"
// recyclerView的Databinding套装-ItemBinding用到
implementation 'me.tatarka.bindingcollectionadapter2:bindingcollectionadapter:4.0.0'
implementation 'me.tatarka.bindingcollectionadapter2:bindingcollectionadapter-recyclerview:4.0.0'
-
第二步:两个布局文件
主布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="viewModel"
type="com.example.mykotlindemo.viewmodel.Kotlin06ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".display.Kotlin06">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@color/green"
android:gravity="center"
android:text="RecyclerView拖拽效果"
android:textColor="@color/white"
android:textSize="20sp"
tools:ignore="MissingConstraints" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mRecycler"
adapter="@{viewModel.adapter}"
android:layout_width="match_parent"
android:layout_height="0dp"
app:itemBinding="@{viewModel.itemBinding}"
app:items="@{viewModel.items}"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
app:spanCount="3"
tools:itemCount="9"
tools:listitem="@layout/item_view_06" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
RecyclerView的ItemView布局:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.example.mykotlindemo.entity.Good" />
<variable
name="viewModel"
type="com.example.mykotlindemo.viewmodel.Kotlin06ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_margin="5dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvTitle"
android:layout_width="100dp"
android:layout_height="100dp"
android:textColor="@color/white"
android:text="@{item.name}"
android:gravity="center"
android:textSize="18sp"
tools:text="apple"
android:padding="20dp"
android:background="@color/gray"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
-
第三步:Activity书写业务逻辑
class Kotlin06 : AppCompatActivity() {
private lateinit var binding:ActivityKotlin06Binding
private lateinit var viewModel:Kotlin06ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this,R.layout.activity_kotlin06);
viewModel = ViewModelProviders.of(this).get(Kotlin06ViewModel::class.java)
binding.viewModel = viewModel
binding.lifecycleOwner = this
//主要的三句代码,借助ItemTouchHelper类
val callback = ItemTouchHelperCallback()
val helper = ItemTouchHelper(callback)
helper.attachToRecyclerView(binding.mRecycler)
}
}
-
第四步:ViewModel加载数据,通过itemBinding绑定数据到RecyclerView
app:items="@{viewModel.items}"
app:itemBinding="@{viewModel.itemBinding}"
/**
* @data on 3/31/21 5:18 PM
* @auther KC
* @describe
*/
class Kotlin06ViewModel:ViewModel(){
var adapter = GoodsSortAdapter()
var items = ObservableArrayList<Good>()
var itemBinding = ItemBinding.of<Good>(BR.item, R.layout.item_view_06)
.bindExtra(BR.viewModel, this)
init {
initData()
}
fun initData(){
items.add(Good("苹果"))
items.add(Good("栗子"))
items.add(Good("李"))
items.add(Good("火龙果"))
items.add(Good("芒果"))
items.add(Good("香蕉"))
items.add(Good("柿子"))
items.add(Good("圣女果"))
items.add(Good("荔枝"))
}
}
-
第五步:实体类DataBean
/**
* @data on 3/31/21 6:39 PM
* @auther KC
* @describe
*/
data class Goods(val goodsList: List<Good>)
data class Good(val name: String)
-
第六步:定义接口及Item移动方法
/**
* @data on 3/31/21 7:00 PM
* @auther KC
* @describe
*/
interface OnItemMoveListener {
/**
* Item移动后 触发
*/
fun onItemMove(fromPosition: Int, toPosition: Int)
}
-
第七步:写ItemTouchHelperCallback类,继承自ItemTouchHelper的Callback接口
/**
* @data on 3/31/21 5:20 PM
* @auther KC
* @describe RecyclerView拖拽重排序
*/
class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val manager = recyclerView.layoutManager
val dragFlags = if (manager is GridLayoutManager || manager is StaggeredGridLayoutManager) {
ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
} else {
ItemTouchHelper.UP or ItemTouchHelper.DOWN
}
val swipeFlags = 0
return makeMovementFlags(dragFlags, swipeFlags)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
if (recyclerView.adapter is OnItemMoveListener) {
val listener = recyclerView.adapter as OnItemMoveListener?
listener!!.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
}
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { }
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
if (actionState !== ItemTouchHelper.ACTION_STATE_IDLE) {
val title = viewHolder!!.itemView.findViewById<TextView>(R.id.tvTitle)
title.setTextColor(Color.parseColor("#FF7028"))
title.setBackgroundColor(Color.WHITE)
}
super.onSelectedChanged(viewHolder, actionState)
}
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
val title = viewHolder.itemView.findViewById<TextView>(R.id.tvTitle)
title.setTextColor(Color.parseColor("#333333"))
title.setBackgroundColor(Color.parseColor("#eeeeee"));
}
}
-
第八步:书写Adapter实现重排序,同样绑定到RecyclerView上
adapter="@{viewModel.adapter}"
/**
* @data on 3/31/21 6:38 PM
* @auther KC
* @describe
*/
class GoodsSortAdapter : BindingRecyclerViewAdapter<Good>() , OnItemMoveListener {
var items = ArrayList<Good>()
override fun onBindBinding(
binding: ViewDataBinding,
variableId: Int,
layoutRes: Int,
position: Int,
item: Good
) {
super.onBindBinding(binding, variableId, layoutRes, position, item)
items.add(item)
Log.d(
"onBindBinding",
"position:::--->" + position + "<---title:::" + item.name
)
}
override fun onItemMove(fromPosition: Int, toPosition: Int) {
val item:Good = items[fromPosition]
items.removeAt(fromPosition)
items.add(toPosition, item)
notifyItemMoved(fromPosition, toPosition)
}
}