GridViewのようにRecyclerViewを使って格子状に表示して、ドラッグ&ドロップとスワイプで削除を行うことができます
2021.2.1
RecyclerViewでGrid表示
RecyclerView からItemTouchHelperを設定すれば、ドラッグアンドドロップやスワイプ削除ができるので、それを使ってGrid表示をさせてみます
ItemTouchHelper.SimpleCallbackが簡単で使いやすい
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> |
これで実行してみます
References:
ItemTouchHelper
リストとカードの作成
ItemTouchHelper.SimpleCallback
GridLayoutManager