国内生産 マウスコンピュータ 1x1.trans - [Android] RecyclerViewとItemTouchHelperでGridの実装


1x1.trans - [Android] RecyclerViewとItemTouchHelperでGridの実装
mouse A4 【3年保証】 ノートパソコン (Ryzen 5 7430U プロセッサ AMD Radeon グラフィックス 16GB メモリ 500GB SSD 14インチ フルHD Windows 11 ビジネス テレワーク) A4A5U01SR1SIW1104AZ
1x1.trans - [Android] RecyclerViewとItemTouchHelperでGridの実装

RecyclerViewでGrid表示

RecyclerView からItemTouchHelperを設定すれば、ドラッグアンドドロップやスワイプ削除ができるので、それを使ってGrid表示をさせてみます

ItemTouchHelper.SimpleCallback が簡単で使いやすい

1. Grid表示
2. サンプルコード

Grid表示

前に 画像とテキストを設定したRecyclerViewのコード を元にして作成してきます

データセットは要素を削除したり可変長となるのでArrayListで作ります

RecyclerViewでは実はListViewのように縦方向のスクロールをデフォルトで設定しているのですが、それを変更することでGridになります

具体的には、LinearLayoutManagerからGridLayoutManagerに変更
また上下方向と左右方向へのスクロールの変更もできます

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 implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation "androidx.cardview:cardview:1.0.0"

onMove()はGridなので上下だけでなく左右も動けるように
UP, DOWN, LEFt, RIGHTを可動域とします

ここでスワイプと重なるので左右で削除か移動か分かりにくくなる可能性はあります
実際は長押しで移動ですが、削除はスワイプではなくChipなどで分かりやすくした方がいいかもしれません

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(
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 (
. . .
}
} ) ;
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);
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 ) ;
}
}
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();
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 ( ) ;
}
}
<?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>
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 >
<?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>
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 >
implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation "androidx.cardview:cardview:1.0.0" <resources> <string name="app_name">Your App Name</string> <string name="description">picture</string> </resources>