Android TV RecyclerView Item Move
文章目录
在 Android TV 中如何实现 RecyclerView
item 间的位置互换?
这里主要利用 RecyclerView
的 ItemAnimator
进行实现交互效果,以及利用 Adapter
的 notifyItemMoved
方法实现数据更新。
因为是 Android TV,主要的交互方式是遥控器,所以无法利用 ItemTouchHelper
进行协助实现位置交互的功能,那主要从以下几步进行:
- 重写
RecyclerView
的focusSearch
方法,focus 变化时触发位置互换; Adapter
中调用notifyItemMoved
实现数据更新;
focusSearch 方法修改
public View focusSearch(View focused, int direction) {
Adapter adapter = getAdapter();
View itemView = findContainingItemView(focused);
if (itemView != null && isSwapMode()) {
return swapItemsIfNeeded(itemView, direction);
}
return super.focusSearch(focused, direction);
}
private View swapItemsIfNeeded(View focused, int direction) {
int position = getChildAdapterPosition(focused);
ItemAnimator animator = getItemAnimator();
if ((animator == null || !animator.isRunning())
&& canMoveInDirection(position, direction)) {
int spanCount = getSpanCount();
switch (direction) {
case FOCUS_LEFT:
moveItem(position, position - 1);
break;
case FOCUS_UP:
moveItem(position, position - spanCount);
break;
case FOCUS_RIGHT:
moveItem(position, position + 1);
break;
case FOCUS_DOWN:
moveItem(position, position + spanCount);
break;
default:
break;
}
}
return focused;
}
private boolean canMoveInDirection(int position, int direction) {
int spanCount = getSpanCount();
LayoutManager m = getLayoutManager();
assert m != null;
if (direction == FOCUS_LEFT) {
return position % spanCount > 0;
} else if (direction == FOCUS_UP) {
return position - spanCount > 0;
} else if (direction == FOCUS_RIGHT) {
return !(position % spanCount >= (spanCount - 1) ||
position >= m.getItemCount() - 1);
} else if (direction == FOCUS_DOWN) {
return position + spanCount <= m.getItemCount() - 1;
}
return false;
}
private int getSpanCount() {
int spanCount = 1;
LayoutManager m = getLayoutManager();
if (m instanceof GridLayoutManager) {
spanCount = ((GridLayoutManager) m).getSpanCount();
}
return spanCount;
}
private void moveItem(int fromPosition, int toPosition) {
Adapter adapter = getAdapter();
if (adapter instanceof XXXAdapter) {
((XXXAdapter) adapter).moveItem(fromPosition, toPosition);
}
}
其中 XXXAdapter
是 Adapter
实现类,主要用于数据更新
XXXAdapter 实现数据更新
public void moveItem(int from, int to) {
Info info = data.remove(from);
data.add(to, info);
// 该方法会触发到 SimpleItemAnimator 的 animateMove 方法
// 利用 animateMove 实现平滑的移动效果
// RecyclerView.ItemAnimator 的实现不在这里详细阐述,有兴趣可以去看 DefaultItemAnimator 的实现
notifyItemMoved(from, to);
}
通过调用 notifyItemMoved
以及和 RecyclerView.ItemAnimator
的结合实现,达到平滑位置交换的效果。
参考
stackoverflow: https://stackoverflow.com/questions/54236100/how-do-i-move-grid-items-on-android-tv
文章作者 Brook
上次更新 2021-06-09