ふるすたっくえんじにあの日記

ASP .NET MVC (C#)、.NET Framework、iOS (Objective-c) アプリ、Androidアプリ (Java)、AWSあたり

【Android】SimpleRecyclerViewAdapter

めずらしくあんどろいだーーーーーー
ねいてぃぶはらくちんでよいね!!!最高!ねむい!体調悪い!つらい!でも納期も時間も待ってくれない!

はい、RecyclerViewAdapterね。簡単なやつならこうしましょう。



app/build.gradle

抜粋です。databindingも使うのでね。

apply plugin: 'kotlin-kapt'
android {
    dataBinding {
        enabled = true
    }
}
dependencies {
    ext.android_support_version = "27.1.1"
    implementation "com.android.support:recyclerview-v7:$android_support_version"
}



SimpleRecyclerViewAdapter.kt

おもむろに以下をじっそうしましょう。

package hoge;

import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import java.lang.reflect.ParameterizedType

abstract class SimpleRecyclerViewAdapter<V : View, I : Any?>(defaultItems: ArrayList<I>? = null) : RecyclerView.Adapter<SimpleRecyclerViewAdapter<V, I>.ItemViewHolder>() {

    protected val isEmpty get() = !items.any()

    private val items: ArrayList<I> = arrayListOf()

    init {
        defaultItems?.let { items.addAll(it) }
    }

    fun removeAll() {
        items.clear()
        notifyDataSetChanged()
    }

    fun addItem(item: I) {
        items.add(item)
        notifyItemInserted(items.count())
    }

    fun removeItem(item: I) {
        val index = items.indexOf(item)
        items.removeAt(index)
        notifyItemRemoved(index)
    }

    fun updateItem(position: Int, item: I) {
        items[position] = item
        notifyItemChanged(position)
    }

    final override fun getItemCount() = items.count()

    final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(onCreateItemView(parent.context).apply {
        layoutParams = RecyclerView.LayoutParams(
                RecyclerView.LayoutParams.MATCH_PARENT,
                RecyclerView.LayoutParams.WRAP_CONTENT
        )
    })

    @Suppress("UNCHECKED_CAST")
    final override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        (holder.itemView as? V)?.let {
            onBindItemView(it, items[position], position)
        }
    }

    @Suppress("UNCHECKED_CAST")
    protected open fun onCreateItemView(context: Context) =
            ((javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<*>)
                    .constructors.first().newInstance(context) as V

    protected abstract fun onBindItemView(itemView: V, item: I, position: Int)

    inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view)
}



使い方

view_hoge_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textViewTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
HogeListItemView.kt
package hoge

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import hoge.R
import kotlinx.android.synthetic.main.view_hoge_list_item.view.*

internal class HogeListItemView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
    : LinearLayout(context, attrs, defStyleAttr) {

    init {
        LayoutInflater.from(context).inflate(R.layout.view_hoge_list_item, this)
    }

    fun setTitle(title: String) {
        textViewTitel.text = title
    }
}



HogeFragment.kt

省略。Bindingのサンプル書くのめんどい。

HogeFragmentVM.kt
package hoge

import android.content.Context
import hoge.SimpleRecyclerViewAdapter
import hoge.HogeListItemView

internal class HogeFragmentVM() {
    val recyclerViewAdapter = object : SimpleRecyclerViewAdapter<HogeListItemView, String>(arrayListOf<String>("Hogeeeeee", "Aaaaaaaaaaa")) {
        override fun onBindItemView(itemView: HogeListItemView, item: String, position: Int) {
            itemView.setTitle(item)
        }
    }
}
fragment_hoge.xml

抜粋。

<?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">

    <data>

        <variable
            name="vm"
            type="hoge.HogeFragmentVM" />
    </data>
    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:recyclerViewAdapter="@{vm.recyclerViewAdapter}" />
</layout>


onBindItemViewだけoverrideすればいいから簡単ですね。はい。いじょー