RecyclerViewの実装方法についてまとめてみた
ネットでRecyclerViewを検索して出てくるサンプルコードをビルドしても全然成功しませんでした。
そんなに残っていないのなら自分が残してやろうということでRecycerViewについてまとめようと思いました。
(それに仕事で使わないといけないからね)
RecyclerViewって何?
Android開発では昔、ListViewまでの実装をやったことがありました。
ですが、最近のAndroidではListViewはあまり使わないらしくRecyclerViewを使うことが多いらしいです。
ListViewでの実装はそこまで大変ではなかったのですが、ネットで検索してもまともなRecyclerViewのサンプルコードがありませんでしたので自分でテンプレを作ることにしました。
RecyclerViewはListViewの上位版みたいな感じでわたし的にはiOSのUICollectionView的なイメージでしかありません。
多量のリストデータを表示するのに適しているそうで、画面部品を再利用する形で効率よくスクロールできるように作られています。
テンプレ用ソースコードについて
public class ScrollListActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scroll_list);
android.support.v7.widget.Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setLogo(R.mipmap.ic_launcher);
setSupportActionBar(toolbar);
CollapsingToolbarLayout toolbarLayout = findViewById(R.id.toolbarLayout);
toolbarLayout.setTitle(getString(R.string.toolbar_title));
toolbarLayout.setExpandedTitleColor(Color.WHITE);
toolbarLayout.setCollapsedTitleTextColor(Color.LTGRAY);
RecyclerView lvMenu = findViewById(R.id.lvMenu);
LinearLayoutManager layout = new LinearLayoutManager(ScrollListActivity.this);
lvMenu.setLayoutManager(layout);
List<Map<String,Object>> menuList = createTeishokuList();
RecyclerListAdapter adapter = new RecyclerListAdapter(menuList);
lvMenu.setAdapter(adapter);
}
private List<Map<String, Object>> createTeishokuList() {
List<Map<String, Object>> menuList = new ArrayList<>();
Map<String, Object> menu = new HashMap<>();
menu.put("name", "から揚げ定食");
menu.put("price", 800);
menu.put("desc", "若鳥のから揚げにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "ハンバーグ定食");
menu.put("price", 850);
menu.put("desc", "手ごねハンバーグにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
//以下データ登録の繰り返し。
menu = new HashMap<>();
menu.put("name", "生姜焼き定食");
menu.put("price", 850);
menu.put("desc", "すりおろし生姜を使った生姜焼きにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "ステーキ定食");
menu.put("price", 1000);
menu.put("desc", "国産牛のステーキにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "野菜炒め定食");
menu.put("price", 750);
menu.put("desc", "季節の野菜炒めにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "とんかつ定食");
menu.put("price", 900);
menu.put("desc", "ロースとんかつにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "ミンチかつ定食");
menu.put("price", 850);
menu.put("desc", "手ごねミンチカツにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "チキンカツ定食");
menu.put("price", 900);
menu.put("desc", "ボリュームたっぷりチキンカツにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "コロッケ定食");
menu.put("price", 850);
menu.put("desc", "北海道ポテトコロッケにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "焼き魚定食");
menu.put("price", 850);
menu.put("desc", "鰆の塩焼きにサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
menu = new HashMap<>();
menu.put("name", "焼肉定食");
menu.put("price", 950);
menu.put("desc", "特性たれの焼肉にサラダ、ご飯とお味噌汁が付きます。");
menuList.add(menu);
return menuList;
}
private class RecyclerListViewHolder extends RecyclerView.ViewHolder {
public TextView _tvMenuName;
public TextView _tvMenuPrice;
public RecyclerListViewHolder(View itemView) {
super(itemView);
_tvMenuName = itemView.findViewById(R.id.tvMenuName);
_tvMenuPrice = itemView.findViewById(R.id.tvMenuPrice);
}
}
private class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListViewHolder> {
private List<Map<String, Object>> _listData;
public RecyclerListAdapter(List<Map<String, Object>> listData) {
_listData = listData;
}
// ビューホルダーオブジェクトを生成するメソッド
@Override
public RecyclerListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(ScrollListActivity.this);
View view = inflater.inflate(R.layout.row, parent, false);
RecyclerListViewHolder holder = new RecyclerListViewHolder(view);
return holder;
}
// ビューホルダー内の各画面部品に表示するデータを割り当てるメソッド
@Override
public void onBindViewHolder(RecyclerListViewHolder holder, int position) {
Map<String, Object> item = _listData.get(position);
String menuName = (String)item.get("name");
int menuPrice = (Integer)item.get("price");
String menuPriceStr = String.valueOf(menuPrice);
holder._tvMenuName.setText(menuName);
holder._tvMenuPrice.setText(menuPriceStr);
}
// データの件数を返すメソッド
@Override
public int getItemCount() {
return _listData.size();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="180dp"
android:elevation="10dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
android:background="@color/colorPrimary"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/lvMenu"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email"/>
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tvMenuName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:textSize="18sp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tvMenuPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tv_menu_unit"
android:textSize="14sp"/>
</LinearLayout>
</LinearLayout>
RecyclerViewを使う上で重要なクラス・メソッドについて
private class RecyclerListViewHolder extends RecyclerView.ViewHolder {}
RecyclerView.ViewHolder クラスを継承したViewHolderクラスを作成する必要があります。
iOS的なイメージではUITableViewCell
のようなViewクラスの生成でしょうか。
各アイテムの画面部品を保持しているオブジェクトでビューホルダーと呼ぶのだそうです。
private class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListViewHolder> {}
こちらがRecyclerViewには独自のAdapterが存在していないため自分でカスタムして実装する必要があるのだそうです。recyclerView.Adapterは抽象クラスのため、次の3つのメソッドを実装している必要があるそうです。
- onCreateViewHolder()
- onBindViewHolder()
- getItemCount()
onCreateViewHolder: ビューホルダオブジェクトを生成するメソッド
onBindViewHolder: ビューホルダ内の各画面部品に表示データを入れるメソッド
getItemCount: データの件数を返すメソッド
スクリーンショットについて
UITableViewCellのような区切り線の実装について
スクリーンショットを見てみるとRecyclerviewの場合はUITableViewCellのような区切り線はデフォルトでは実装されないそうです。
区切り線を入れるためには別にDividerItemDecoration
クラスが別に必要です。
実装の仕方はActivityのprotected void onCreate(Bundle savedInstanceState)
メソッドの一番下に下記の2行を追加するだけです。
// 区切り線用のオブジェクトを生成する
DividerItemDecoration decoration = new DividerItemDecoration(ScrollListActivity.this, layout.getOrientation());
lvMenu.addItemDecoration(decoration);
これで区切り線が表示されるようになります。
クリックイベントについて
さらにRecyclerViewを実際にタップして何かアクションを処理する場合には
private class ItemClickListener implements View.OnClickListener
を実装するだけです。
このプライベートクラスメソッドに処理を書いて、次のところにセットしましょう。
// ビューホルダーオブジェクトを生成するメソッド
@Override
public RecyclerListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(ScrollListActivity.this);
View view = inflater.inflate(R.layout.row, parent, false);
view.setOnClickListener(new ItemClickListener()); // <- ココに追加
RecyclerListViewHolder holder = new RecyclerListViewHolder(view);
return holder;
}
これでクリックイベントが反応するようになります。