# Recycler View ItemTouchHelper & onSaveInsrance事件用法- kotlin
[延續recyclerView程式碼](https://hackmd.io/JfbNEXvpQ0aruQfy9MXgCA)
1. 在OnePieceAdapter.kt檔案, OnePieceAdapter類別底下新增巢狀類別,[程式碼第66行]inner class ItemDragHelperCallback
2. [程式碼第11行]定義一個attachiToRecyclerView涵式將TouchHelper跟RecyclerView綁在一起
```kotlin=
class OnePieceAdapter() : RecyclerView.Adapter<OnePieceAdapter.ViewHolder>(){
var fruit : MutableList<OnePiece> = mutableListOf()
private var itemClickListener : ItemClickListener ?= null
private val mItemDragHelperCallback = ItemDragHelperCallback()
//触摸辅助类 可以用于主动调用删除
private val mItemTouchHelper = ItemTouchHelper(mItemDragHelperCallback)
init {
//Log.d("類別初始化", "init執行了")
}
open fun attachiToRecyclerView(recyclerView :RecyclerView){
mItemTouchHelper.attachToRecyclerView(recyclerView)
}
fun reload(list: List<OnePiece>){
fruit.clear()
fruit.addAll(list)
notifyDataSetChanged()
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
//viewHolder定義要顯示在recyclerView的layout元件
val fruitImage = view.findViewById<ImageView>(R.id.fruitImage)
val fruitName = view.findViewById<TextView>(R.id.fruitName)
fun bindData(data: OnePiece){
fruitImage.setImageResource(data.imageId)
fruitName.text = data.name
//設定圖片clicker監聽
fruitImage.setOnClickListener(){
itemClickListener?.showClick(data)
}
}
}
//期望取得綁定viewHolder的資料
open fun getCheckedItems(): ArrayList<OnePiece> {
val checkedItems :ArrayList<OnePiece> = ArrayList<OnePiece>()
for (i in 0 until fruit.size) {
if (fruit.isNotEmpty()) {
//checkedItems.add(fruit[i])
checkedItems.add(OnePiece(fruit[i].name, fruit[i].imageId))
Log.d("取得修改後資料", "${checkedItems[i]}")
}
}
return checkedItems
}
fun setToshowClickListener(listener : ItemClickListener){ //用以呼叫的
itemClickListener = listener
} //set方法,可以供Activity或Fragment呼叫
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
//把要顯示在recyclerView的view inflate出來
//Log.d("onCreateViewHolder", "onCreateViewHolder準備執行")
val view = LayoutInflater.from(parent.context).inflate(R.layout.fruit_item, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return fruit.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindData(fruit[position])
}
//======================
inner class ItemDragHelperCallback: ItemTouchHelper.Callback() {
override fun getMovementFlags(
//此處return可以滑動的方向值
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
var swipe = 0
var move = 0
recyclerView.let{
if(recyclerView.layoutManager is GridLayoutManager){
//如果Grid layout支持上下左右滑動
move = ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT
} else if (recyclerView.layoutManager is LinearLayoutManager){
//支持上下滑動
move = ItemTouchHelper.UP or ItemTouchHelper.DOWN
//支持左右滑動刪除
swipe = ItemTouchHelper.START or ItemTouchHelper.END
}
}
return ItemTouchHelper.Callback.makeMovementFlags(move, swipe)
}
override fun onMove(
//此處return 是否可以拖動 布林值
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val fromPos = viewHolder.adapterPosition
val toPos = target.adapterPosition
fruit.let {
val from = fruit[fromPos]
fruit.removeAt(fromPos)
Log.d("移除選擇要移動的物件", "${fruit}")
fruit.add(toPos,from)
Log.d("插入移動完成的物件", "${fruit}")
notifyItemMoved(fromPos,toPos)
return true
}
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
//用於滑動刪除
fruit.let {
var position : Int = viewHolder.adapterPosition
it.removeAt(position)
notifyItemRemoved(position)
}
}
override fun isLongPressDragEnabled(): Boolean {
return super.isLongPressDragEnabled()
}
override fun isItemViewSwipeEnabled(): Boolean {
return super.isItemViewSwipeEnabled()
}
//加入滑動刪除的效果圖片
@SuppressLint("ResourceType")
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
var RecyclerViewSwipeDecorator = RecyclerViewSwipeDecorator.Builder(c,recyclerView,viewHolder,dX,dY,actionState,isCurrentlyActive)
RecyclerViewSwipeDecorator.let {
it.addBackgroundColor(ContextCompat.getColor(recyclerView.context,android.R.color.holo_red_dark))
it.addActionIcon(R.drawable.ic_baseline_delete_24)
}
.create()
.decorate()
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
//設計拖曳動畫
super.onSelectedChanged(viewHolder, actionState)
if(actionState != ItemTouchHelper.ACTION_STATE_IDLE){
viewHolder?.let {
if(viewHolder is ViewHolder){
viewHolder.fruitImage!!.visibility = View.VISIBLE
}
}
}
}
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
viewHolder?.let {
if(viewHolder is ViewHolder){
//viewHolder.fruitImage!!.visibility = View.GONE
}
}
}
}
}
```
3. mainActivity.kt, [程式碼第26行]呼叫attachiToRecyclerView綁定recyclerView ,就完成recyclerView拖曳功能了
##### 接下來說明旋轉螢幕之後,如何保存recyclerView的狀態
1. 首先將data class 加上宣告
```kotlin=
@Parcelize
data class OnePiece(val name: String, val imageId: Int) : Parcelable
```
2. [程式碼第43行]onSaveInstanceState 這邊來儲存我們旋轉螢幕過程把資料保存下來
3. [程式碼第45行]透過linearLayoutManager內建的onSaveInstance()方法保存recyclerView目前滑動到哪個位置
4. [程式碼第48行]透過自己定義的涵式getCheckedItems取得我們拖曳改變List順序後的資料並保存
5. [程式碼第16~24行]判斷是否要重新生成資料或者取用被保留下來的資料
```kotlin=0
private const val BUNDLE_RECYCLER_LAYOUT = "recycler_layout"
private const val BUNDLE_JSON_LIST = "json_list"
class MainActivity : AppCompatActivity() {
//定義要綁定給Adapter的資料
lateinit var fruitList : ArrayList<OnePiece>
lateinit var recyclerView : RecyclerView
lateinit var adapter : OnePieceAdapter
lateinit var linearLayoutManager: LinearLayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recyclerView)
linearLayoutManager = LinearLayoutManager(this)
adapter = OnePieceAdapter()
if(savedInstanceState == null){
Log.d("第一次執行onCreate", "savedInstanceState 是null的")
fruitList = initFruits()
} else {
Log.d("第一次執行onCreate", "savedInstanceState 不是null")
val savedRecyclerLayoutState = savedInstanceState.getParcelable<Parcelable>(BUNDLE_RECYCLER_LAYOUT)!!
fruitList = savedInstanceState.getParcelableArrayList<OnePiece>(BUNDLE_JSON_LIST)!!
linearLayoutManager.onRestoreInstanceState(savedRecyclerLayoutState)
}
//綁itemTouchHelper
adapter.attachiToRecyclerView(recyclerView)
//adapter.getCheckedItems()
adapter.setToshowClickListener(object: ItemClickListener{
override fun showClick(data: OnePiece) {
toShwo()
}
})
//布局Layout Manager & 設定adapter給recyclerView
recyclerView.adapter = adapter
recyclerView.layoutManager = linearLayoutManager
//使用內建的分隔線↓
recyclerView.addItemDecoration(DividerItemDecoration(this@MainActivity,LinearLayoutManager.VERTICAL))
//重新載入資料給adapter
adapter.reload(fruitList)
}
//保存Recyclerview實例
override fun onSaveInstanceState(outState: Bundle) {
//↓保存recyclerView位置資訊
outState.putParcelable(BUNDLE_RECYCLER_LAYOUT,linearLayoutManager.onSaveInstanceState())
Log.d("存存存", "${adapter.getCheckedItems()}")
//保存recyclerView資料變更後的List
outState.putParcelableArrayList(BUNDLE_JSON_LIST,adapter.getCheckedItems())
super.onSaveInstanceState(outState)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
}
@SuppressLint("ShowToast")
private fun toShwo() {
Toast.makeText(this@MainActivity, "hello",Toast.LENGTH_SHORT).show()
}
private fun initFruits(): ArrayList<OnePiece> {
val create_fruitList = arrayListOf<OnePiece>()
repeat(2) {
create_fruitList.add(OnePiece("魯夫", R.drawable.luffy))
create_fruitList.add(OnePiece("布魯克",R.drawable.brook))
create_fruitList.add(OnePiece("佛朗基",R.drawable.frank))
create_fruitList.add(OnePiece("基拉",R.drawable.killer))
create_fruitList.add(OnePiece("喬巴", R.drawable.chopper))
create_fruitList.add(OnePiece("娜美", R.drawable.nami))
create_fruitList.add(OnePiece("羅賓", R.drawable.robin))
create_fruitList.add(OnePiece("香吉", R.drawable.sanji))
create_fruitList.add(OnePiece("烏索普", R.drawable.sogeking))
create_fruitList.add(OnePiece("德瑞克", R.drawable.xdrike))
create_fruitList.add(OnePiece("拖拉法爾加-羅", R.drawable.trafalg))
create_fruitList.add(OnePiece("儸儸諾亞-索隆", R.drawable.zoro))
}
return create_fruitList
}
}
```
###### tags: `recycler view` `kotlin` `Android` `ItemTouchHelper`