GridViewのようにRecyclerViewを使って格子状に表示して、ドラッグ&ドロップとスワイプで削除を行うことができます
2021.2.1
RecyclerViewでGrid表示
RecyclerView からItemTouchHelperを設定すれば、ドラッグアンドドロップやスワイプ削除ができるので、それを使ってGrid表示をさせてみます
ItemTouchHelper.SimpleCallbackが簡単で使いやすい
![[Android] RecyclerViewとItemTouchHelperでGridの実装 1x1.trans - [Android] RecyclerViewとItemTouchHelperでGridの実装](https://akira-watson.com/wp-content/themes/simplicity2/images/1x1.trans.gif)
Grid表示
前に画像とテキストを設定したRecyclerViewのコードを元にして作成してきます
データセットは要素を削除したり可変長となるのでArrayListで作ります
RecyclerViewでは実はListViewのように縦方向のスクロールをデフォルトで設定しているのですが、それを変更することでGridになります
具体的には、LinearLayoutManagerからGridLayoutManagerに変更
また上下方向と左右方向へのスクロールの変更もできます
| 1 2 3 4 5 6 | GridLayoutManager (     Context context,     int spanCount, // The number of columns or rows in the grid.     int orientation, // HORIZONTAL or VERTICAL.     boolean reverseLayout // When set to true, layouts from end to start ) | 
2個並びの縦方向に設定してみます
| 1 2 | recyclerView.setLayoutManager(     new GridLayoutManager(this,  2, RecyclerView.VERTICAL, false)); | 
CardViewのwidgetをタグにします
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <androidx.cardview.widget.CardView     ...     <LinearLayout         ...         <ImageView             ...          />         <TextView             ...         />     </LinearLayout> </androidx.cardview.widget.CardView> | 
ライブラリにcardviewを追加
build.gradle
| 1 2 3 4 5 | dependencies {     ...     implementation 'androidx.recyclerview:recyclerview:1.2.1'     implementation "androidx.cardview:cardview:1.0.0" } | 
onMove()はGridなので上下だけでなく左右も動けるように
UP, DOWN, LEFt, RIGHTを可動域とします
ここでスワイプと重なるので左右で削除か移動か分かりにくくなる可能性はあります
実際は長押しで移動ですが、削除はスワイプではなくChipなどで分かりやすくした方がいいかもしれません
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ItemTouchHelper itemTouchHelper = new ItemTouchHelper(     new ItemTouchHelper.SimpleCallback(             // onMove     ItemTouchHelper.UP | ItemTouchHelper.DOWN |             ItemTouchHelper.LEFT  | ItemTouchHelper.RIGHT,             // onSwipe     ItemTouchHelper.LEFT  | ItemTouchHelper.RIGHT) {     @Override     public boolean onMove(             ...     }     @Override     public void onSwiped(             ...     } }); | 
サンプルコード
これをRcyclerViewに組み合わせてまとめていきます
MainActivity.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | //package your.package.name; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.GridLayoutManager; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MainActivity extends AppCompatActivity {     private static final String[] names = {         "Bellflower", "Bougainvillea", "Cosmos", "Cosmos field",         "Delphinium", "Flowers", "Lotus", "Spring Flowers"     };     // それぞれの画像ファイルをdarawableに入れます     // ArrayListにコピーするためintからInteger型にしました     private static final Integer[] photos = {         R.drawable.bellflower, R.drawable.bougainvillea,         R.drawable.cosmos, R.drawable.cosmos_field,         R.drawable.delphinium, R.drawable.flowers,         R.drawable.lotus, R.drawable.spring_flowers     };     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         RecyclerView recyclerView = findViewById(R.id.my_recycler_view);         // use this setting to improve performance if you know that changes         // in content do not change the layout size of the RecyclerView         recyclerView.setHasFixedSize(true);         // use a linear layout manager         recyclerView.setLayoutManager(                 new GridLayoutManager(this,  2, RecyclerView.VERTICAL, false));         // 配列をArrayListにコピー         List<String> itemNames = new ArrayList<>(Arrays.asList(names));         List<Integer> itemImages = new ArrayList<>(Arrays.asList(photos));         // specify an adapter (see also next example)         MyAdapter adapter = new MyAdapter(itemImages, itemNames);         recyclerView.setAdapter(adapter);         RecyclerView.ItemDecoration itemDecoration =             new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);         recyclerView.addItemDecoration(itemDecoration);         ItemTouchHelper itemTouchHelper = new ItemTouchHelper(                 new ItemTouchHelper.SimpleCallback(                         ItemTouchHelper.UP | ItemTouchHelper.DOWN |                         ItemTouchHelper.LEFT  | ItemTouchHelper.RIGHT,                         ItemTouchHelper.LEFT  | ItemTouchHelper.RIGHT                 ) {                 @Override                 public boolean onMove(@NonNull RecyclerView recyclerView,                                       @NonNull RecyclerView.ViewHolder viewHolder,                                       @NonNull RecyclerView.ViewHolder target) {                     final int fromPos = viewHolder.getAbsoluteAdapterPosition();                     final int toPos = target.getAbsoluteAdapterPosition();                     adapter.notifyItemMoved(fromPos, toPos);                     return true;                 }                 @Override                 public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {                     itemImages.remove(viewHolder.getAbsoluteAdapterPosition());                     itemNames.remove(viewHolder.getAbsoluteAdapterPosition());                     adapter.notifyItemRemoved(viewHolder.getAbsoluteAdapterPosition());                 }             });         itemTouchHelper.attachToRecyclerView(recyclerView);     } } | 
 
アダプターです
MyAdapter.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | //package your.package.name; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import java.util.List; public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {     private final List<Integer> iImages;     private final List<String> iNames;     // Provide a reference to the views for each data item     // Complex data items may need more than one view per item, and     // you provide access to all the views for a data item in a view holder     static class ViewHolder extends RecyclerView.ViewHolder {         // each data item is just a string in this case         ImageView imageView;         TextView textView;         ViewHolder(View v) {             super(v);             imageView = v.findViewById(R.id.image_view);             textView = v.findViewById(R.id.text_view);         }     }     // Provide a suitable constructor (depends on the kind of dataset)     MyAdapter(List<Integer> itemImages, List<String> itemNames) {         this.iImages = itemImages;         this.iNames = itemNames;     }     // Create new views (invoked by the layout manager)     @Override     @NonNull     public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {         // create a new view         View view = LayoutInflater.from(parent.getContext())                 .inflate(R.layout.grid_view, parent, false);         // set the view's size, margins, paddings and layout parameters         return new ViewHolder(view);     }     // Replace the contents of a view (invoked by the layout manager)     @Override     public void onBindViewHolder(@NonNull ViewHolder holder, int position) {         // - get element from your dataset at this position         // - replace the contents of the view with that element         holder.imageView.setImageResource(iImages.get(position));         holder.textView.setText(iNames.get(position));     }     // Return the size of your dataset (invoked by the layout manager)     @Override     public int getItemCount() {         return iNames.size();     } } | 
activity_main.xml
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?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">     <!-- A RecyclerView with some commonly used attributes -->     <androidx.recyclerview.widget.RecyclerView         android:id="@+id/my_recycler_view"         android:scrollbars="vertical"         android:layout_width="match_parent"         android:layout_height="match_parent"         app:layout_constraintBottom_toBottomOf="parent"         app:layout_constraintLeft_toLeftOf="parent"         app:layout_constraintRight_toRightOf="parent"         app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> | 
リスト要素のレイアウト
grid_view.xml
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView     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="wrap_content"     app:cardCornerRadius="10dp"     app:cardElevation="5dp"     app:contentPadding="10dp"     app:cardUseCompatPadding="true">     <LinearLayout         android:orientation="vertical"         android:layout_width="match_parent"         android:layout_height="wrap_content"         tools:ignore="UseCompoundDrawables">         <ImageView             android:id="@+id/image_view"             android:layout_width="wrap_content"             android:layout_height="160dp"             android:contentDescription="@string/description" />         <TextView             android:id="@+id/text_view"             android:textSize="18sp"             android:textColor="@android:color/black"             android:textAlignment="center"             android:layout_width="match_parent"             android:layout_height="wrap_content"/>     </LinearLayout> </androidx.cardview.widget.CardView> | 
gradleの追加設定、バージョンは適宜合わせてください
build.gradle
| 1 2 3 4 5 | dependencies {     ...     implementation 'androidx.recyclerview:recyclerview:1.2.1'     implementation "androidx.cardview:cardview:1.0.0" } | 
strings.xml
| 1 2 3 4 | <resources>     <string name="app_name">Your App Name</string>     <string name="description">picture</string> </resources> | 
これで実行してみます
![[Android] RecyclerViewとItemTouchHelperでGridの実装 1x1.trans - [Android] RecyclerViewとItemTouchHelperでGridの実装](https://akira-watson.com/wp-content/themes/simplicity2/images/1x1.trans.gif)
References:
ItemTouchHelper
リストとカードの作成
ItemTouchHelper.SimpleCallback
GridLayoutManager
