📝

Layoutタップ時にRecyclerViewもタップ対象とする方法

2020/10/12に公開

親のLayoutに android:clickable="true" してもRecyclerView領域タップに反応してくれない。そんなときの対応方法。

setAdapterの後に suppressLayout(true) をするだけでOK。
setLayoutFrozen(boolean) は Deprecated になりました。
https://developer.android.com/reference/kotlin/androidx/recyclerview/widget/RecyclerView#suppresslayout

recyclerView.adapter = ExampleAdapter()
recyclerView.suppressLayout(true)

タッチイベントやスクロールが無効になるので、当然RecyclerViewのアイテムがClickListener等のイベントを持っていても反応しなくなります。

setAdapterの後なのは、setAdapter内でfalseに設定されているためです。

// recyclerview-1.1.0-sources.jar
public void setAdapter(@Nullable Adapter adapter) {
    // bail out if layout is frozen
    setLayoutFrozen(false);
    setAdapterInternal(adapter, false, true);
    processDataSetCompletelyChanged(false);
    requestLayout();
}

@Deprecated
public void setLayoutFrozen(boolean frozen) {
    suppressLayout(frozen);
}

suppressLayout(true) の1行を追加するだけで良いですが、ソースコード上で行う必要があるためレイアウトXML上からは分からなくなってしまいます。なので私が実装する際にはCustomViewを作成しています。

package com.example.myapp

import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.RecyclerView

class SuppressRecyclerView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    @SuppressLint("PrivateResource") defStyleAttr: Int = R.attr.recyclerViewStyle
) : RecyclerView(context, attrs, defStyleAttr) {

    override fun setAdapter(adapter: Adapter<*>?) {
        super.setAdapter(adapter)
        suppressLayout(true)
    }
}
<com.example.myapp.SuppressRecyclerView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    tools:itemCount="3"
    tools:listitem="@layout/list_card" />

以上

Discussion