RecyclerView の使い方、4シリーズ目です。
1シリーズ目:【Android】簡潔に RecyclerView を使う。 - 山崎屋の技術メモ
2シリーズ目:【Android】イメージを含んだリッチな行を持つ RecyclerView - 山崎屋の技術メモ
3シリーズ目:【Android】RecyclerView、行をドラッグして並び替え - 山崎屋の技術メモ
前回(3シリーズ目)は行自体を長押ししてドラッグという方法で並び替えを行いました。
今回はつまみ(ハンドル)をドラッグして並び替えを行います。行の長押しドラッグは無効にします。
つまみ(ハンドル)とは ↓↓↓ のようなイメージです。
完成形はこちらです。
それでは始めましょう。
Empty Activity のテンプレートを使用した NewProject を作成しておいてください。
イメージリソースの準備
プラスボタン(btn_add.png)、マイナスボタン(btn_minus.png)、つまみ(ハンドル)(ic_baseline_drag_handle_24.xml)のイメージは準備しておいてください。
ic_launcher_background.xml と ic_launcher_foreground.xml はプロジェクト作成時に自動で追加されたものです。
依存関係を追加
recyclerview のライブラリを依存関係に追加します。
モジュールの build.gradle の dependencies ブロックに次の一文を追加します。
implementation 'androidx.recyclerview:recyclerview:1.1.0'
1 行のレイアウト xml を作成
リストの 1 行を表すレイアウト xml を追加します。
counter_row.xml
<?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:gravity="center_vertical" android:orientation="horizontal" android:padding="10dp"> <!-- 並び替えつまみ(ハンドル) --> <androidx.appcompat.widget.AppCompatImageButton android:id="@+id/handle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dp" android:padding="0dp" android:src="@drawable/ic_baseline_drag_handle_24" /> <!-- マイナスボタン --> <androidx.appcompat.widget.AppCompatImageButton android:id="@+id/btn_minus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="0dp" android:adjustViewBounds="true" android:foreground="?android:attr/selectableItemBackground" android:padding="0dp" android:src="@drawable/btn_minus" /> <!-- テキスト --> <TextView android:id="@+id/counter_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center_vertical|center_horizontal" android:text="1,000" android:textSize="40sp" /> <!-- プラスボタン --> <androidx.appcompat.widget.AppCompatImageButton android:id="@+id/btn_plus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_margin="0dp" android:adjustViewBounds="true" android:foreground="?android:attr/selectableItemBackground" android:padding="0dp" android:src="@drawable/btn_add" /> </LinearLayout>
activity_main.xml を修正
RecyclerView を使うように修正します。
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
Adapter クラスを作成
RecycleView と データをつなぐためのアダプタを作成します。
MyAdapter.java
package org.yyama.recyclerviewsample4; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private String[] myDataset; public static class MyViewHolder extends RecyclerView.ViewHolder { public TextView textView; public MyViewHolder(View v) { super(v); textView = v.findViewById(R.id.counter_num); textView.setTextSize(30); // つまみ(ハンドル)がタッチされたら、ドラッグできるようにする v.findViewById(R.id.handle).setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { MainActivity mc = (MainActivity) v.getContext(); mc.getItemTouchHelper().startDrag(MyViewHolder.this); } return false; } }); } } public MyAdapter(String[] myDataset) { this.myDataset = myDataset; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.counter_row, parent, false); MyViewHolder vh = new MyViewHolder(v); return vh; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.textView.setText(myDataset[position]); } @Override public int getItemCount() { return myDataset.length; } }
MainActivity.java を修正
最後に MainActivity を修正し RecyclerView にデータをセットします。
package org.yyama.recyclerviewsample4; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private ItemTouchHelper itemTouchHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); String[] myDataset = {"aaa","bbb","ccc"}; final RecyclerView.Adapter mAdapter = new MyAdapter(myDataset); recyclerView.setAdapter(mAdapter); RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL); recyclerView.addItemDecoration(itemDecoration); // ドラックアンドドロップの操作を実装する itemTouchHelper = new ItemTouchHelper( // 上、下のドラッグを処理する Callback を作成する。スワイプは処理しない new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.ACTION_STATE_IDLE) { @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { final int fromPos = viewHolder.getAdapterPosition(); final int toPos = target.getAdapterPosition(); mAdapter.notifyItemMoved(fromPos, toPos); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { } // 行の長押しではドラッグできないようにする @Override public boolean isLongPressDragEnabled (){ return false; } }); // recyclerView と itemTouchHelper を紐づける itemTouchHelper.attachToRecyclerView(recyclerView); } public ItemTouchHelper getItemTouchHelper() { return itemTouchHelper; } }
全体構成
モジュール、リソースの最終構成です。
まとめ
RecyclerView の並べ替えはデフォルトで行の長押し→ドラッグです。
今回は行の長押し→ドラッグは無効にし、つまみ(ハンドル)をドラッグして並べ替えする方法を紹介しました。
それでは!