https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf
-
View.OnDragListener, GestureDetectors, onInterceptTouchEvent 등을 활용하는 방법이 주로 사용되고 있다. 하지만 이들은 복잡하다.
-
ItemTouchHelper 라는 녀석이 있다. 이 녀석은 Android Support Lib 에서 제공해주는 녀석으로 이 녀석을 쓰면 Drag&Drop, Swipe to dismiss 등을 아주 쉽게 구현할 수 있다.
ItemTouchHelper 는 RecyclerView.ItemDecoration 의 subclass 이다.
ItemDecoration 을 상속했다는 것은 LayoutManager 와 Adapter 에 쉽게 merge 할 수 있다는 것을 의미한다.
-
ItemTouchHelper 를 사용하기 위해서는 ItemTouchHelper.Callback 을 구현해야 한다.
이 녀석은 move 와 swipe events 에 대한 callback 을 받는다. view 의 selection 상태라던지 default animation 구현 등도 가능하다.
ItemTouchHelper.SimpleCallback 이라는 기본구현된 Callback 도 제공된다.
-
ItemTouchHelper 에서 drag&drop 과 swipe-to-dismiss 를 구현하기 위해 implement 해야 하는 함수들은 아래와 같다.
// 아래 3개 함수는 기능의 enability 에 대한 설정
getMovementFlags(RecyclerView, ViewHolder)
isLongPressDragEnabled()
isItemViewSwipeEnabled()
// 아래 2개 함수는 data 를 refresh 하기 위한 함수
onMove(RecyclerView, ViewHolder, ViewHolder)
onSwiped(ViewHolder, int)
-
@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); }
getMovementFlags() 는 어떤 direction 으로 drag 와 swipe 를 support 할 것인지를 결정하는 역할을 한다.
ItemTouchHelper.makeMovementFlag(int, int) 를 통해 drag 를 지원할 방향과 swipe 를 지원할 방향을 지정해준다.
위의 코드에서는 UP, DOWN 에 대한 drag 를 지원하고, LEFT(START), RIGHT(END) 에 대한 swipe 를 지원한다.
-
@Override public boolean isLongPressDragEnabled() { return true; }
long press 를 했을 때 drag 를 지원하려면 true 를 return 해야 한다.
long press 없이 직접 drag 를 시작시키려면 ItemTouchHelper.startDrag(RecyclerView.ViewHolder) 를 호출해주면 된다.
-
@Override public boolean isItemViewSwipeEnabled() { return true; }
swipe 를 지원하려면 이 함수에서 true 를 return 해주어야 한다.
ItemTouchHelper.startSwipe(RecyclerView.ViewHoler) 를 호출하면 swipe 를 직접 수행시킬 수도 있다.
-
@Override public void onItemDismiss(int position) { mItems.remove(position); mAdapter.notifyItemRemoved(position); }
onItemDismiss 는 swipe 를 통해 view 가 사라졌을 때 불리는 callback 이다.
-
@Override public boolean onItemMove(int fromPosition, int toPosition) { if (fromPosition < toPosition) { for (int i = fromPosition; i < toPosition; i++) { Collections.swap(mItems, i, i + 1); } } else { for (int i = fromPosition; i > toPosition; i--) { Collections.swap(mItems, i, i - 1); } } notifyItemMoved(fromPosition, toPosition); return true; }
onItemMove 는 drag 를 통해 item 의 위치가 변경되었을 때 불린다.
-
준비가 다 되었다면 이제 준비한 ItemTouchHelper with Callback 을 recyclerView 에 붙여주어야 한다.
ItemTouchHelper.Callback callback = new MyItemTouchHelperCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView);
-
Drag 할 때 View 가 Select 되었다는 것을 보여주기 위해서는 ItemTouchHelper.Callback 의 다음 함수들을 구현해주면 된다.
onSelectedChanged(ViewHolder, int)
drag 시에는 ACTION_STATE_DRAG 가, swipe 일때는 ACTION_STATE_SWIPE 가 전달된다.
참고로 drag 가 끝나거나 swipe 가 끝났을 때는 ACTION_STATE_IDLE 이 전달된다.
clearView(RecyclerView, ViewHolder)
drag 된 view 가 drop 되었거나 swipe 가 cancel 되거나 complete 되었을 때 불린다.
-
RecyclerView.ItemDecoration ( ItemTouchHelper 의 super class ) 의 onChildDraw() 를 override 하여 child view drawing 에 관여할 수 있다.
@Override public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { float width = (float) viewHolder.itemView.getWidth(); float alpha = 1.0f - Math.abs(dX) / width; viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } }
-
끝! 아주 Easy.
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[android] custom lint 만들기 (0) | 2020.07.31 |
---|---|
[android] Direct Share since MOS (0) | 2020.07.30 |
[Java] Generational Concurrent GC 에 대해 알아보자 (0) | 2020.07.28 |
[android] ART 의 JIT (Just-In-Time) Compiler 에 대해 알아보자 (0) | 2020.07.27 |
[android] App 이 kill 되면 Alarm 이나 Job 은 어떻게 될끼? (0) | 2020.07.26 |
댓글