Android RecyclerView + ItemTouchHelper - 드래그 앤 드롭, 스와이프
* 참고
아래 소스대로 구현시 Activity 에서 item 값을 가져오고 싶을 경우에 사용 하면 됩니다.
String aa = ((TextView) mRecyclerView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.tv_name)).getText().toString();
* 1 : array 번호
* name : tab_item.xml 에서 가져올 요소 이름
주의할 점은, 화면을 벗어난 item 의 정보를 가져올 경우 null 값이 반환 되어 오류가 발생됩니다.
그럴땐 아래와 같이 사용하면 됩니다.
for(int i = 0; i<Objects.requireNonNull(mRecyclerView.getAdapter()).getItemCount(); i++) {
if (mRecyclerView.findViewHolderForLayoutPosition(i) != null) {
View childView = Objects.requireNonNull(mRecyclerView.findViewHolderForLayoutPosition(i)).itemView;
TextView tv_name = childView.findViewById(R.id.tv_name);
String name = tv_name.getText().toString();
Toast.makeText(getBaseContext(), "아이템 NAME : " + name, Toast.LENGTH_SHORT).show();
}
}
그럼 살펴보도록 합니다.
[출처] https://jroomstudio.tistory.com/27
RecyclerView + ItemTouchHelper -> Drag and Drop과 swipe 구현



activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19  | <?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">         android:id="@+id/rv_tab_list"         android:layout_width="match_parent"         android:layout_height="match_parent"         tools:listitem="@layout/tab_item"         app:layout_constraintBottom_toBottomOf="parent"         app:layout_constraintEnd_toEndOf="parent"         app:layout_constraintStart_toStartOf="parent"         app:layout_constraintTop_toTopOf="parent" />  | 
tools:listitem -> 리사이클러뷰에 추가 될 레이아웃을 지정한다.
tab_item.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 33 34  | <?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:minHeight="60dp"     android:orientation="horizontal"     android:paddingEnd="20dp"     android:paddingStart="20dp">     <TextView         android:id="@+id/name"         android:layout_width="0dp"         android:layout_height="wrap_content"         android:layout_weight="2"         android:textColor="@android:color/primary_text_light"         android:textSize="20sp"         android:text="TAB NAME" />     <FrameLayout         android:id="@+id/drag_handle"         android:layout_width="wrap_content"         android:layout_height="wrap_content">         <ImageView             android:layout_width="30dp"             android:layout_height="30dp"             android:layout_gravity="center"             android:src="@drawable/ic_drag_handle" />     </FrameLayout> </LinearLayout>  | 

TabItem.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  | public class TabItem {     private String name;     private int number;     public TabItem(String name, int number){         this.name = name;         this.number = number;     }     public int getNumber() {         return number;     }     public void setNumber(int number) {         this.number = number;     }     public String getName() {         return name;     }     public void setName(String name) {         this.name = name;     } }  | 
아이템 레이아웃에 셋팅 될 Tab name과 리스트 순번을 모델 객체가 저장하고 반환한다.
ItemTouchHelperListener.java 인터페이스
1 2 3 4  | public interface ItemTouchHelperListener {     boolean onItemMove(int form_position, int to_position);     void onItemSwipe(int position); }  | 
RecylcerView의 Adapter 클래스에서 상속받는다.
onItemMove -> 아이템의 현재 위치와 이동 위치를 입력받아 아이템 리스트에의 위치를 수정하도록 구현
onItemSwipe -> 아이템의 포지션값을 받아 해당 아이템을 Swipe할때 로직을 구현
ItemTouchHelperCallback.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  | public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {     private ItemTouchHelperListener listener;     public ItemTouchHelperCallback(ItemTouchHelperListener listener) { this.listener = listener; }     @Override     public int getMovementFlags(@NonNull RecyclerView recyclerView,                                 @NonNull RecyclerView.ViewHolder viewHolder) {         return makeMovementFlags(drag_flags,swipe_flasg);         /* 
        참고하실 부분은 onMove와 onSwipe중 하나만 사용하겠다라고 하신다면 
        getMovementFlags에서 return을 해주는 makeMovementFlags함수의 인자로 0을 넣어주시면 됩니다.
        예를 들면, 
        onMove만 사용(onSwipe 사용안함) - return makeMovementFlags(drag_flags,0);
        onSwipe만 사용(onMove 사용안함) - return makeMovementFlags(0,swipe_flags);
        출처: https://everyshare.tistory.com/27 [에브리셰어]
        */     }     @Override     public boolean onMove(@NonNull RecyclerView recyclerView,                           @NonNull RecyclerView.ViewHolder viewHolder,                           @NonNull RecyclerView.ViewHolder target) {         return listener.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());     }     @Override     public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {         listener.onItemSwipe(viewHolder.getAdapterPosition());     }     @Override     public boolean isLongPressDragEnabled() {         return true;     } } http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter  | 
ItemTouchHelperCallback 생성자
-> 해당 클래스를 생성할 때 ItemTouchHelperListener를 입력받아 멤버 인스턴스로 지정하고 ItemTouchHelper.Callback이 지원하는 여러 메소드를 오버라이딩 하여 필요에 따라 사용한 후 결과값들을 반환해 준다. 아이템 위치변경 , 스와이프 , 롱클릭 등 다양한 기능을 지원한다.
getMovementFlags
-> 리사이클러뷰와 리사이클러뷰 뷰홀더를 입력받는다.
-> drag 위치와 swipe 위치를 ItemTouchHelper에서 받아 셋팅한다.
-> makeMovementFlags() 메소드로 drag위치와 swipe 위치를 입력하여 현재 위치값을 int로 반환해준다.
onMove
-> 리사이클러뷰,viewHolder, target(viewHolder 중 선택된 아이템)을 입력받아 움직임을 감지한다.
-> ItemTouchHelperListener의 onItemMove메소드로 해당 아이템의 움직임을 감지한다.
-> onItemMove 메소드는 아이템이 움직이고 있는 가를 판별하고 boolean 값으로 반환한다.
onSwiped
-> 리사이클러뷰의 뷰홀더와 움직일 방향을 입력받는다.
-> ItemTouchHelperListner의 onItemSwipe메소드에 움직일 방향을 입력하여 swipe를 구현한다.
isLongPressDragEnabled()
-> true를 반환하도록 설정하면 롱클릭을 감지한다.
TabListAdapter.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  | public class TabListAdapter extends RecyclerView.Adapter<TabListAdapter.ItemViewHolder>                             implements ItemTouchHelperListener{     private ArrayList<TabItem> items = new ArrayList<>();     public TabListAdapter(){}     @NonNull     @Override     public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {         LayoutInflater inflater = LayoutInflater.from(parent.getContext());         View view = inflater.inflate(R.layout.tab_item, parent, false);         return new ItemViewHolder(view);     }     @Override     public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {     }     @Override     public int getItemCount() {         return items.size();     }     public void setItems(ArrayList<TabItem> itemList){         items = itemList;         notifyDataSetChanged();     }     @Override     public boolean onItemMove(int form_position, int to_position) {         TabItem item = items.get(form_position);         items.add(to_position,item);         item.setNumber(to_position);         notifyItemMoved(form_position, to_position);         return true;     }     @Override     public void onItemSwipe(int position) {         notifyItemRemoved(position);     }     public class ItemViewHolder extends RecyclerView.ViewHolder {         TextView tabName;         public ItemViewHolder(@NonNull View itemView) {             super(itemView);             tabName = itemView.findViewById(R.id.name);         }         public void onBind(TabItem item,int position){             tabName.setText(item.getName());             item.setNumber(position);         }     } }  | 
-> RecyclerView.Adapter 를 상속받는다.
Adapter에는 RecyclerView.ViewHolder를 상속받은 내부 클래스를 구현하고 제네릭으로 지정하여 상속받아야 한다.
-> ItemTouchHelperListener를 상속받아 onItemMove과 onItemSwipe를 오버라이딩하여 행동을 구현해준다.
-> TabItem 모델을 제네릭으로 지정한 ArrayList를 생성한다.
--------------------------------------------------------------
RecyclerView 상속 오버라이딩 메소드
onCreateViewHolder
-> 리사이클러뷰에 추가될 item 레이아웃을 연결한다.
-> ItemViewHolder 클래스에 View(item레이아웃)를 입력한다.
onBindViewHolder
-> ItemViewHolder와 아이템의 리스트상 위치를 입력받는다.
-> ItemViewHolder 내부에 구현한 onBind 메소드에 아이템 리스트에서 포지션값으로 아이템을 선택하여 입력한다.
getItemCount
-> items의 전체 갯수 숫자를 반환한다.
setItems
-> 메인액티비티에서 TabItem 객체를 생성한 후에 리스트를 입력하여 어댑터의 멤버 items에 매치시킨다.
-> notifyDataSetChanged메소드로 데이터가 셋팅되었음을 알린다.
--------------------------------------------------------------
ItemTouchHelperListener 오버라이딩 메소드
onItemMove
-> 아이템의 리스트상 현재위치와 움직일 위치를 입력받느다.
-> 입력받은 값으로 아이템의 이동을 구현한다.
-> notifyItemMoved 메소드로 데이터가 이동함을 알린다.
onItemSwipe
-> 포지션값을 입력받는다.
-> 포지션값으로 아이템리스트의 해당 포지션 아이템을 삭제한다.
-> notifyItemRemoved 메소드로 데이터가 삭제되었음을 알린다.
ItemViewHolder 클래스
ItemViewHolder
-> 아이템 레이아웃의 name TextView 와 연결한다.
onBind
-> TabItem객체에 셋팅된 값으로 각각의 레이아웃에 셋팅 한다.
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  | public class MainActivity extends AppCompatActivity {     private RecyclerView mRecyclerView;     private TabListAdapter mAdapter;     private ItemTouchHelper mItemTouchHelper;     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         mRecyclerView = (RecyclerView) findViewById(R.id.rv_tab_list);         LinearLayoutManager manager = new LinearLayoutManager(getApplicationContext());         manager.setOrientation(LinearLayoutManager.VERTICAL);         mRecyclerView.setLayoutManager(manager);         mAdapter = new TabListAdapter();         mRecyclerView.setAdapter(mAdapter);         mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback(mAdapter));         mItemTouchHelper.attachToRecyclerView(mRecyclerView);         ArrayList<TabItem> items = new ArrayList<>();         TabItem item1 = new TabItem("SUBSCRIBE",0);         TabItem item2 = new TabItem("BEST",0);         TabItem item3 = new TabItem("MUSIC",0);         TabItem item4 = new TabItem("SPORTS",0);         TabItem item5 = new TabItem("GAME",0);         TabItem item6 = new TabItem("MOVIE",0);         TabItem item7 = new TabItem("NEWS",0);         TabItem item8 = new TabItem("LIVE",0);         items.add(item1);         items.add(item2);         items.add(item3);         items.add(item4);         items.add(item5);         items.add(item6);         items.add(item7);         items.add(item8);         mAdapter.setItems(items);     } } http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter  | http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs | 
-> 리사이클러뷰를 생성한다.
-> 리사이클러뷰에 LinearLayoutManager를 활용해 속성을 지정한다.
-> 리사이클러뷰에 TabListAdpater를 셋팅한다.
-> 어댑터를 입력한 ItemTouchHelperCallback 클래스를 ItemTouchHelper 생성자에 입력하여 생성한다.
-> TouchHelper 의 attachToRecyclerView 메소드를 활용해 Touch를 구현할 리사이클러뷰를 연결한다.
-> TabItem 을 제네릭으로 받는 ArrayList를 생성하고 임의의 값을 셋팅한다.
-> 어댑터의 setItems 메소드에 해당 ArrayList를 입력한다.
[출처] https://jroomstudio.tistory.com/27
'프로그래밍 > Android (Java)' 카테고리의 다른 글
| 안드로이드 진동 기능 사용하기 (0) | 2020.12.18 | 
|---|---|
| 안드로이드 모든 TextView, Button 폰트 일괄 변경 (Custom Font) (0) | 2020.12.18 | 
| activity 간 데이터 전달 (0) | 2020.12.17 | 
| 안드로이드 CDT (CountDownTimer) 반복 작업을 종료하는 두 가지 방법 (0) | 2020.12.14 | 
| 안드로이드 네트워크 연결 여부 확인하기 (0) | 2020.12.14 | 







