炊きたてのご飯が食べたい

定時に帰れるっていいね。自宅勤務できるっていいね。子どもと炊きたてのご飯が食べられる。アクトインディでは積極的にエンジニアを募集中です。

Kotlin + RecyclerView で OnItemClick を実装する


アクトインディ Advent Calendar 2016 20日目の記事になります。子どもとおでかけ情報アプリ「いこーよ」は、マップ上で簡単におでかけ先を探せる検索アプリです。記事を見てくれたパパさん、ママさん、ぜひ一度使ってみてください^^

iko-yo.net

本日の記事では Kotlin での RecyclerView の実装方法について紹介したいと思います。ListView では、リストの要素をタップした時の処理は OnItemClickListener に処理を書くと思いますが RecyclerView には OnItemClickListener をセットすることができない為、独自にタップした時の処理を実装する必要があります。

今回は RecyclerView の Adapter にメソッドを引数として渡す方法で実装してみたいと思います。サンプルのソースは Github に公開しています。KotlinRecyclerViewSample

やりたい事

f:id:t-namikata:20161220095848g:plain

  • MainActivity で RecyclerView のアイテムをクリックすると DetailActivity に遷移する
  • タップしたアイテムのタイトルが DetailActivity に表示される

実装方法

  1. RecyclerView の Adapter を作成する
  2. MainActivity で RecyclerView をセットアップする

1. RecyclerView の Adapter を作成する

RecyclerView の Adapter を作成します。ポイントはコンストラクタの引数に itemClick を宣言しているところです。今回の例では item をタップした時の処理は MainActivity でメソッドを定義し Adapter の引数として渡すことで、Activity の遷移の実装を行なっています。itemClick には List の要素の itemName を渡すようにしているので、 MainActivity から DetailActivity に遷移する際に必要となる itemName をメソッドを定義する MainActivity で取得できるようになっています。

class ItemListAdapter(val items: List<String>, val itemClick: (String) -> Unit) :
        RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
        return ViewHolder(view = view, itemClick = itemClick)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.setUp(items[position])
    }

    override fun getItemCount(): Int {
        return this.items.count()
    }

    class ViewHolder(view: View, val itemClick: (String) -> Unit) : RecyclerView.ViewHolder(view) {
        private val textView: TextView by bindView(R.id.item_text_view)

        fun setUp(itemName: String) {
            this.textView.text = itemName
            this.itemView.setOnClickListener { itemClick(itemName) }
        }
    }
}

item.xml は以下のようになっています。

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

    <TextView
        android:id="@+id/item_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp" />

    <View
        android:layout_alignParentBottom="true"
        android:background="@android:color/black"
        android:alpha="0.1"
        android:layout_width="match_parent"
        android:layout_height="1dp" />
</RelativeLayout>
  1. MainActivity で RecyclerView をセットアップする

あとは Adapter をセットする時にリストをタップした時の処理を引数に渡してあげることで完成です。

class MainActivity : AppCompatActivity() {
    private val recyclerView: RecyclerView by bindView(R.id.recycler_view)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val adapter = ItemListAdapter(items = listOf("Apple", "Pineapple", "Pen")) { itemName ->
            val intent = Intent(this, DetailActivity::class.java)
            intent.putExtra("itemName", itemName)
            this.startActivity(intent)
        }
        this.recyclerView.adapter = adapter
    }
}
class DetailActivity : AppCompatActivity() {
    private val textView: TextView by bindView(R.id.text_view)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detail)

        this.title = "DetailActivity"
        this.textView.text = intent.getStringExtra("itemName")
    }
}