KotlinパッケージRecyclerView Adapterの実例教程


前言
Kotlinはますます流行っています。Googleのおかげで発展しています。今のプロジェクトはKotlinを使っています。簡単な文法飴は確かに多くのコードを減らすことができます。
AdapterのパッケージGitHubにはたくさんありますが、パッケージの多くは素晴らしいです。はい、使いやすいです。パッケージの力が大きくて柔軟性とコードの複雑性が上がります。誰が知っていますか?もちろんパッケージも簡単です。
ここではKotlinの簡単な文法を使って再度処理してカプセル化しました。
まず見てから使います
シングルタイプの使用

val adapter=recyclerView.setUp(users, R.layout.item_layout, { holder, item ->
   var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
   binding.nameText.text = item.name
   ...
  })
マルチタイプの使用

recyclerView.setUP(users,
    listItems = *arrayOf(
      ListItem(R.layout.item_layout, { holder, item ->
       var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
       binding?.nameText?.text = item.name
       ...
      }, {
       Snackbar.make(window.decorView, it.name, Snackbar.LENGTH_SHORT).show()
      }),
      ListItem(R.layout.item_layout2, { holder, item ->
       val nameText: TextView = holder.getView(R.id.nameText)
       nameText.text = item.name
       ...
      }, {

      })
    ))
使用はこのように簡単です。コードはオーバーパッケージですか?
Adapterの基質

abstract class AbstractAdapter<ITEM> constructor(protected var itemList: List<ITEM>)
 : RecyclerView.Adapter<AbstractAdapter.Holder>() {

 override fun getItemCount() = itemList.size

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
  val view = createItemView(parent, viewType)
  val viewHolder = Holder(view)
  val itemView = viewHolder.itemView
  itemView.setOnClickListener {
   val adapterPosition = viewHolder.adapterPosition
   if (adapterPosition != RecyclerView.NO_POSITION) {
    onItemClick(itemView, adapterPosition)
   }
  }
  return viewHolder
 }


 fun update(items: List<ITEM>) {
  updateAdapterWithDiffResult(calculateDiff(items))
 }

 private fun updateAdapterWithDiffResult(result: DiffUtil.DiffResult) {
  result.dispatchUpdatesTo(this)
 }

 private fun calculateDiff(newItems: List<ITEM>) =
   DiffUtil.calculateDiff(DiffUtilCallback(itemList, newItems))

 fun add(item: ITEM) {
  itemList.toMutableList().add(item)
  notifyItemInserted(itemList.size)
 }

 fun remove(position: Int) {
  itemList.toMutableList().removeAt(position)
  notifyItemRemoved(position)
 }

 final override fun onViewRecycled(holder: Holder) {
  super.onViewRecycled(holder)
  onViewRecycled(holder.itemView)
 }

 protected open fun onViewRecycled(itemView: View) {
 }

 protected open fun onItemClick(itemView: View, position: Int) {
 }

 protected abstract fun createItemView(parent: ViewGroup, viewType: Int): View

 class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
  private val views = SparseArray<View>()

  fun <T : View> getView(viewId: Int): T {
   var view = views[viewId]
   if (view == null) {
    view = itemView.findViewById(viewId)
    views.put(viewId, view)
   }
   return view as T
  }
 }
}
サブクラスの実現とRecyclerViewの拡張

class SingleAdapter<ITEM>(items: List<ITEM>,
       private val layoutResId: Int,
       private val bindHolder: (Holder, ITEM) -> Unit)
 : AbstractAdapter<ITEM>(items) {

 private var itemClick: (ITEM) -> Unit = {}

 constructor(items: List<ITEM>,
    layoutResId: Int,
    bindHolder: (Holder, ITEM) -> Unit,
    itemClick: (ITEM) -> Unit = {}) : this(items, layoutResId, bindHolder) {
  this.itemClick = itemClick
 }

 override fun createItemView(parent: ViewGroup, viewType: Int): View {
  var view = parent inflate layoutResId
  if (view.tag?.toString()?.contains("layout/") == true) {
   DataBindingUtil.bind<ViewDataBinding>(view)
  }
  return view
 }

 override fun onBindViewHolder(holder: Holder, position: Int) {
  bindHolder(holder, itemList[position])
 }

 override fun onItemClick(itemView: View, position: Int) {
  itemClick(itemList[position])
 }
}


class MultiAdapter<ITEM : ListItemI>(private val items: List<ITEM>,
          private val bindHolder: (Holder, ITEM) -> Unit)
 : AbstractAdapter<ITEM>(items) {

 private var itemClick: (ITEM) -> Unit = {}
 private lateinit var listItems: Array<out ListItem<ITEM>>

 constructor(items: List<ITEM>,
    listItems: Array<out ListItem<ITEM>>,
    bindHolder: (Holder, ITEM) -> Unit,
    itemClick: (ITEM) -> Unit = {}) : this(items, bindHolder) {
  this.itemClick = itemClick
  this.listItems = listItems
 }

 override fun createItemView(parent: ViewGroup, viewType: Int): View {
  var view = parent inflate getLayoutId(viewType)
  if (view.tag?.toString()?.contains("layout/") == true) {
   DataBindingUtil.bind<ViewDataBinding>(view)
  }
  return view
 }

 private fun getLayoutId(viewType: Int): Int {
  var layoutId = -1
  listItems.forEach {
   if (it.layoutResId == viewType) {
    layoutId = it.layoutResId
    return@forEach
   }
  }
  return layoutId
 }

 override fun getItemViewType(position: Int): Int {
  return items[position].getType()
 }

 override fun onBindViewHolder(holder: Holder, position: Int) {
  bindHolder(holder, itemList[position])
 }

 override fun onItemClick(itemView: View, position: Int) {
  itemClick(itemList[position])
 }
}


fun <ITEM> RecyclerView.setUp(items: List<ITEM>,
        layoutResId: Int,
        bindHolder: (AbstractAdapter.Holder, ITEM) -> Unit,
        itemClick: (ITEM) -> Unit = {},
        manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context)): AbstractAdapter<ITEM> {
 val singleAdapter by lazy {
  SingleAdapter(items, layoutResId, { holder, item ->
   bindHolder(holder, item)
  }, {
   itemClick(it)
  })
 }
 layoutManager = manager
 adapter = singleAdapter
 return singleAdapter
}


fun <ITEM : ListItemI> RecyclerView.setUP(items: List<ITEM>,
           manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context),
           vararg listItems: ListItem<ITEM>): AbstractAdapter<ITEM> {

 val multiAdapter by lazy {
  MultiAdapter(items, listItems, { holder, item ->
   var listItem: ListItem<ITEM>? = getListItem(listItems, item)
   listItem?.bindHolder?.invoke(holder, item)
  }, { item ->
   var listItem: ListItem<ITEM>? = getListItem(listItems, item)
   listItem?.itemClick?.invoke(item)
  })
 }
 layoutManager = manager
 adapter = multiAdapter
 return multiAdapter
}

private fun <ITEM : ListItemI> getListItem(listItems: Array<out ListItem<ITEM>>, item: ITEM): ListItem<ITEM>? {
 var listItem: ListItem<ITEM>? = null
 listItems.forEach {
  if (it.layoutResId == item.getType()) {
   listItem = it
   return@forEach
  }
 }
 return listItem
}

class ListItem<ITEM>(val layoutResId: Int,
      val bindHolder: (holder: AbstractAdapter.Holder, item: ITEM) -> Unit,
      val itemClick: (item: ITEM) -> Unit = {})


interface ListItemI {
 fun getType(): Int
}
コアコードは全部なく、リリースするつもりもないです。直接cloneでプロジェクトを導入するのが一番いい方法です。複雑ではないので、いつでも変更できます。
上記の多種類の使用を見ると、普通のLayoutとData Binding Layoutをサポートしていることが分かります。これも本庫の特色です。余分な処理は必要ありません。
1.普通のLayoutはこのように処理します。

ListItem(R.layout.item_layout2, { holder, item ->
       val nameText: TextView = holder.getView(R.id.nameText)
       nameText.text = item.name
      }
HolderでViewを操作しています。中にはキャッシュがあります。

DataBinding Layout
ListItem(R.layout.item_layout, { holder, item ->
       var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
       binding.nameText.text = item.name
      }
自分でどれの中のLayoutかを知っていれば、対応すればいいのか、Holderの処理方式もData Binding Layoutを処理できるのか、分かります。
ここで教えてください。どうして直接KotlinのLayout Viewで検索するのですか?
そのコードは簡単に見えますが、今のStudioはこれに対するサポートがあまりよくないです。よく売れます。プログラマーは赤いのを見てイライラします。好きならば実現も簡単ですが、Viewの拡張に変えて返してもいいです。自分で試してみてもいいですよ。
ここでは不変の部分をカプセル化しただけなので、頭や足などの機能を多く追加していません。クリックすると、イベントが内蔵されています。もちろん、イベントをクリックしてItemTouchHelperを使ってもいいです。
このように毎回大きな串を書かなくてもいいです。喜んでポット茶を入れて、息を吹きかけてもいいですか?
他のライブラリはItem多重できますが、よろしいですか?
えっと、?いいですよ
たとえば

val item: (AbstractAdapter.Holder, User) -> Unit = { holder, user ->

  }
たとえば

ListItem(R.layout.item_layout, { holder, item ->
       var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
      }, {//    
       Snackbar.make(window.decorView, it.name, Snackbar.LENGTH_SHORT).show()
      })
同じではないですか?場所を定義してセットすればいいです。多重化も難しいです。Kotlin文法の大法がいいとしか言えません。
はい、この倉庫はここまで紹介します。ありがとうございます。
コードアドレス
参照リンク
霊感は次のおかみさんから来ましたが、基本的に書き直しました。
https://github.com/armcha/Kadapter
締め括りをつける
以上はこの文章の全部の内容です。本文の内容は皆さんの学習や仕事に対して一定の参考となる学習価値を持っています。質問があれば、メッセージを書いて交流してください。ありがとうございます。