RecyclerView の基本的な使い方

ここではマテリアルデザインにおける主要 UI コンポーネントである RecyclerView の基本的な利用方法について説明します。

RecyclerView は従来の ListView の代わりとなるものです。

要はリストです。すなわち、基本的に同種類の情報を並べるために利用します。

ここでは非常に単純な例を紹介します。

尚、開発環境は Android Studio を利用しています。

これまで Eclipse + ADT 等を利用してきた方も、なるべく速やかに Android Studio に移行していきましょう。

RecyclerView の利用方法

次の動画のような状況を考えます。

以下ではこのようなリストの実現方法を説明します。

つまり、始めに A, B, C という文字が表示されている。それぞれの要素を押すと要素が削除される。メニューの "ADD ITEM" というボタンを押すと、 最上部に要素 "X" が追加される、というものです。

ビルドファイル設定

前述の通り RecyclerView はサポートライブラリ v7 で利用可能になります。

ここでは Android Studio を利用することを前提としていますが、サポートライブラリ v7 を利用するために、ビルドファイル build.gradle にて以下を記述します。

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])    
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.android.support:recyclerview-v7:21.0.+'
}

Android Studio build.gradle

リソース

メインのアクティビティのレイアウトは次の通り。RelativeLayout に RecyclerView がひとつ含まれています。

res/layout/activity_main.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView1"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

RecyclerView は ListView に代わるものにあたるわけですが、そのリスト内の項目ひとつひとつは、 今回は TextView をひとつ含むだけです。この TextView に "A", "B", ... などの文字を表示します。

res/layout/my_row1.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="100dp">
    <TextView
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:id="@+id/textView1"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_marginTop="10dp"
        android:textSize="30sp"/>
</RelativeLayout>

メニューは今回は "ADD ITEM" というボタンを表示するだけの目的ですから、メニュー項目はひとつだけです。

res/menu/menu_main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">
    <item
        android:id="@+id/action_addItem"
        android:title="Add Item"
        android:orderInCategory="200"
        app:showAsAction="ifRoom"/>
</menu>

コード

MainActivity.java

package com.keicode.android.test.recycleviewtest1;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import java.util.ArrayList;


public class MainActivity extends ActionBarActivity {

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private ArrayList<String> mDataset;

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

        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView1);
        mRecyclerView.setHasFixedSize(true);
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mDataset = new ArrayList<>();
        mDataset.add("A");
        mDataset.add("B");
        mDataset.add("C");
        mAdapter = new MyAdapter(mDataset);
        mRecyclerView.setAdapter(mAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();
        if(id == R.id.action_addItem){
            addItem();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    protected void addItem(){
        mDataset.add(0, "X");
        mAdapter.notifyItemInserted(0);
    }
}

RecyclerView のインスタンスを取得したら、レイアウトマネージャーを設定します。 ここでは LinearLayoutManager を作成してリサイクラービューに設定しています。LinearLayoutManager の代わりに GridLayoutManager を利用すると、グリッドタイプのレイアウトが直ちに実現できます。

データソースは String の ArrayList としています。それを受取るアダプターを後述のように定義し、RecyclerView のアダプターとしてセットします。

このアダプターの実装は次の通りです。

MyAdapter.java

RecyclerView のデータアダプターは RecyclerView.Adapter<ViewHolder> から派生して作成します。ViewHolder クラスは静的ネストクラス (static nested class) として定義しましょう。

package com.keicode.android.test.recycleviewtest1;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ItemViewHolder> {

    ArrayList<String> mDataset;

    public static class ItemViewHolder extends RecyclerView.ViewHolder {

        public TextView mTextView;

        public ItemViewHolder(View v){
            super(v);
            mTextView = (TextView)v.findViewById(R.id.textView1);
        }
    }

    public MyAdapter(ArrayList<String> mDataset){
        this.mDataset = mDataset;
    }

    @Override
    public ItemViewHolder onCreateViewHolder(
        ViewGroup parent,
        int viewType){
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.my_row1,
                        parent,
                        false);
        return new ItemViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ItemViewHolder holder, int position) {
        final String data;
        data = mDataset.get(position);
        holder.mTextView.setText(mDataset.get(position));
        holder.mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                removeFromDataset(data);
            }
        });
    }

    @Override
    public int getItemCount() {
        return mDataset.size();
    }

    protected void removeFromDataset(String data){
        for(int i=0; i<mDataset.size(); i++){
            if(mDataset.get(i).equals(data)){
                mDataset.remove(i);
                notifyItemRemoved(i);
                break;
            }
        }
    }
}

ViewHolder でリスト項目毎の UI 要素の参照を取得しておく、というところだけ新しい感じがしますが、 基本的にはListView の基本的な利用方法を知っている方には難しくないと思います。

データアダプターの notifyItemRemoved メソッド、notifyItemInserted メソッド等を呼び出すことで、ビルトインのアニメーション効果が利用できます。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門