[Android]RecyclerViewのクリックイベント

投稿者:

ListViewでは、setOnItemClickListener()でアイテムがクリックされたときのイベントを拾うことができた。RcyclerViewはどうかというと、残念ながらそういう仕組みが備わってはいない。なのでクリックイベントを拾いたい場合は自分で実装しなければならない。

RcyclerViewのクリックイベントは、Adapterで生成したViewにView.OnClickListenerを設定すればOKだ。
方法は二つある。

AdapterのonCreateViewHolder()で実装

ViewHolderで保持するViewにOnClickListenerを設定する方法。

class SampleRecyclerAdapter extends RecyclerView.Adapter<SampleRecyclerAdapter.SampleViewHolder> {
    //メンバ変数
    String[] itemDatas; //リストのデータを保持する変数

    //コンストラクタ
    SampleRecyclerAdapter(String[] itemDatas) {
        this.itemDatas = itemDatas;
    }

    @NonNull
    @Override
    public SampleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        //onCreateViewHolder()ではリスト一行分のレイアウトViewを生成する
        //作成したViewはViewHolderに格納してViewHolderをreturnで返す

        //レイアウトXMLからViewを生成
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.listitem_recyclerview1, viewGroup, false);

        //ViewHolderを生成
        final SampleViewHolder holder = new SampleViewHolder(view);

        //クリックイベントを登録
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Toast.makeText(v.getContext(), itemDatas[position], Toast.LENGTH_SHORT).show();
            }
        });

        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull final SampleViewHolder sampleViewHolder, int position) {
        //onBindViewHolder()ではデータとレイアウトの紐づけを行なう
        sampleViewHolder.text01.setText(itemDatas[position]);
    }

    @Override
    public int getItemCount() {
        //データ個数を返す
        return itemDatas.length;
    }

    /* ViewHolder(インナークラス) */
    class SampleViewHolder extends RecyclerView.ViewHolder {
        TextView text01;

        SampleViewHolder(@NonNull View itemView) {
            super(itemView);
            text01 = itemView.findViewById(R.id.text01);
        }
    }
}

AdapterのonBindViewHolder()で実装

各アイテムのViewが実際に生成されるたびにOnClickListenerを設定する方法。

class SampleRecyclerAdapter extends RecyclerView.Adapter<SampleRecyclerAdapter.SampleViewHolder> {
    //メンバ変数
    String[] itemDatas; //リストのデータを保持する変数

    //コンストラクタ
    SampleRecyclerAdapter(String[] itemDatas) {
        this.itemDatas = itemDatas;
    }

    @NonNull
    @Override
    public SampleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        //レイアウトXMLからViewを生成
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.listitem_recyclerview1, viewGroup, false);

        //ViewHolderを生成
        final SampleViewHolder holder = new SampleViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull final SampleViewHolder sampleViewHolder, int position) {
        //onBindViewHolder()ではデータとレイアウトの紐づけを行なう
        sampleViewHolder.text01.setText(itemDatas[position]);
        //クリックイベントを登録
        final int p = position;
        sampleViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(v.getContext(), itemDatas[p], Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        //データ個数を返す
        return itemDatas.length;
    }

    /* ViewHolder(インナークラス) */
    class SampleViewHolder extends RecyclerView.ViewHolder {
        TextView text01;

        SampleViewHolder(@NonNull View itemView) {
            super(itemView);
            text01 = itemView.findViewById(R.id.text01);
        }
    }
}

実行結果

どちらの方法も実行結果は同じになる。

イベント処理本体をAdapterの外に出す

しかし、Adapterの内部にクリック時の処理を書いてしまうのはなんとなくモヤモヤした気分になる。Adapter本来の機能ではないコードがAdapter内部に居座って可読性が悪くなってしまうからだ。できるならクリックイベントの中身はコールバック等でAdapterの外に出してしまうのが良策だと思う。

例えばこんな感じに↓

public class MainActivity extends AppCompatActivity {
    //リストに表示するデータ
    private final static String[] listDatas = {
            "ONE","TWO","THREE","FOUR",
            "FIVE","SIX","SEVEN","EIGHT",
            "NINE","TEN","ELEVEN","TWELVE",
            "THIRTEEN","FOURTEEN","FIFTEEN","SIXTEEN",
            "SEVENTEEN","EIGHTEEN","NINETEEN","TWENTY"    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final RecyclerView recyclerView = findViewById(R.id.recyclerview1);
        //LayoutManagerを設定
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL); //縦方向に設定
        recyclerView.setLayoutManager(layoutManager);
        //ItemDecorationを設定
        DividerItemDecoration itemDecoration = new DividerItemDecoration(this, layoutManager.getOrientation());
        recyclerView.addItemDecoration(itemDecoration);

        //アダプタのセット
        final SampleRecyclerAdapter adapter = new SampleRecyclerAdapter(listDatas){
            // onItemClick()をオーバーライドして
            // クリックイベントの処理を記述する
            @Override
            void onItemClick(View view, int position, String itemData) {
                Toast.makeText(view.getContext(),itemData, Toast.LENGTH_SHORT).show();
            }
        };
        recyclerView.setAdapter(adapter);
    }

    /* -------------------------------------------------------
    * RecyclerViewのアダプタ
    * --------------------------------------------------------*/
    class SampleRecyclerAdapter extends RecyclerView.Adapter<SampleRecyclerAdapter.SampleViewHolder> {
        //メンバ変数
        String[] itemDatas; //リストのデータを保持する変数

        //コンストラクタ
        SampleRecyclerAdapter(String[] itemDatas) {
            this.itemDatas = itemDatas;
        }

        @NonNull
        @Override
        public SampleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
            //レイアウトXMLからViewを生成
            View view = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.listitem_recyclerview1, viewGroup, false);

            //ViewHolderを生成
            final SampleViewHolder holder = new SampleViewHolder(view);
            //クリックイベントを登録
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = holder.getAdapterPosition();
                    //処理はonItemClick()に丸投げ
                    onItemClick(v, position, itemDatas[position]);
                }
            });
            return holder;
        }

        @Override
        public void onBindViewHolder(@NonNull final SampleViewHolder sampleViewHolder, int position) {
            //onBindViewHolder()ではデータとレイアウトの紐づけを行なう
            sampleViewHolder.text01.setText(itemDatas[position]);
        }

        @Override
        public int getItemCount() {
            //データ個数を返す
            return itemDatas.length;
        }

        void onItemClick(View view, int position, String itemData) {
            //アダプタのインスタンスを作る際
            //このメソッドをオーバーライドして
            //クリックイベントの処理を設定する
        }


        /* ViewHolder(インナークラス) */
        class SampleViewHolder extends RecyclerView.ViewHolder {
            TextView text01;

            SampleViewHolder(@NonNull View itemView) {
                super(itemView);
                text01 = itemView.findViewById(R.id.text01);
            }
        }
    }
}

参考:
http://y-anz-m.blogspot.com/2016/11/recyclerview.html

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください