一、需求
需求很明确,我需要滑动排序二级list的数据。
可伸缩和折叠使用的是BaseExpandableListAdapter,用法大家可自行百度查看。这里我主要讲解下,我是如何实现在二级菜单中实现滑动排序的,以及在开发过程中遇到的问题,以及我自己的解决办法,希望给读者一些启示。
二、过程
解决list的滑动排序问题,我能想到的解决办法,有三种,
- 通过RecyclerView + ItemTouchHelper;
- 通过OnDragListener,这种方式需要自己写自定义的ViewGroup;
- 通过ViewDragHelper。
由于项目原因,时间比较急,所以我选择的是第一种方式。
一开始,我的写法如下:
@Override
public View getChildView(int i, int i1, boolean b, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.device_action_list_item_child_copy, null);
}
RecyclerView rv = convertView.findViewById(R.id.recycler_view);
rv.setLayoutManager(new LinearLayoutManager(context));
Vector<String> stringVector = childData.get(i).get(i1);
Ap<String> ap = new Ap(context, stringVector);
rv.setAdapter(ap);
ItemTouchHelperCallBack callBack = new ItemTouchHelperCallBack();
ItemTouchHelper helper = new ItemTouchHelper(callBack);
callBack.set(ap, stringVector);
helper.attachToRecyclerView(rv);
return convertView;
}
class ItemTouchHelperCallBack extends ItemTouchHelper.Callback{
Ap<String> ap = null; Vector<String> datas = null;
public void set(Ap<String> ap, Vector<String> datas) {
this.ap = ap;
this.datas = datas;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFrlg = 0;
Log.e("TAG", "getMovementFlags");
if (recyclerView.getLayoutManager() instanceof GridLayoutManager){
dragFrlg = ItemTouchHelper.UP|ItemTouchHelper.DOWN|ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;
}else if(recyclerView.getLayoutManager() instanceof LinearLayoutManager){
dragFrlg = ItemTouchHelper.UP|ItemTouchHelper.DOWN;
}
return makeMovementFlags(dragFrlg,0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//滑动事件 下面注释的代码,滑动后数据和条目错乱,被舍弃
// Collections.swap(datas,viewHolder.getAdapterPosition(),target.getAdapterPosition());
// ap.notifyItemMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition());
//得到当拖拽的viewHolder的Position
int fromPosition = viewHolder.getAdapterPosition();
//拿到当前拖拽到的item的viewHolder
int toPosition = target.getAdapterPosition();
Log.e("TAG", "onMove fromPosition = " + fromPosition + "; toPosition = " + toPosition);
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(datas, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(datas, i, i - 1);
}
}
ap.notifyItemMoved(fromPosition, toPosition);
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//侧滑删除可以使用;
Log.e("TAG", "onSwiped");
}
@Override
public boolean isLongPressDragEnabled() {
Log.e("TAG", "isLongPressDragEnabled");
return true;
}
/**
* 长按选中Item的时候开始调用
* 长按高亮
* @param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
Log.e("TAG", "onSelectedChanged actionState=" + actionState);
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
// viewHolder.itemView.setBackgroundColor(Color.RED);
//获取系统震动服务//震动70毫秒
Vibrator vib = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
vib.vibrate(70);
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 手指松开的时候还原高亮
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
Log.e("TAG", "clearView");
viewHolder.itemView.setBackgroundColor(0);
ap.notifyDataSetChanged(); //完成拖动后刷新适配器,这样拖动后删除就不会错乱
}
}
device_action_list_item_child_copy.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
上面代码运行之后,发现滑动没问题,但在和折叠收缩的时候,遇到了比较尴尬的问题。
问题: 折叠后,再打开,发现,无法滑动。
分析了下,我发现,每次折叠之后,再打开二级菜单,会不断的重复生成ItemTouchHelperCallBack,之后,也正是由于这个原因,导致滑动没法正常使用。
查看代码
helper.attachToRecyclerView(rv);
在ItemTouchHelper.java中发现attachToRecyclerView方法在使用之前会先比较mRecyclerView,源码如下:
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
if (this.mRecyclerView != recyclerView) {
if (this.mRecyclerView != null) {
this.destroyCallbacks();
}
this.mRecyclerView = recyclerView;
if (recyclerView != null) {
Resources resources = recyclerView.getResources();
this.mSwipeEscapeVelocity = resources.getDimension(dimen.item_touch_helper_swipe_escape_velocity);
this.mMaxSwipeVelocity = resources.getDimension(dimen.item_touch_helper_swipe_escape_max_velocity);
this.setupCallbacks();
}
}
}
private void destroyCallbacks() {
this.mRecyclerView.removeItemDecoration(this);
this.mRecyclerView.removeOnItemTouchListener(this.mOnItemTouchListener);
this.mRecyclerView.removeOnChildAttachStateChangeListener(this);
int recoverAnimSize = this.mRecoverAnimations.size();
for(int i = recoverAnimSize - 1; i >= 0; --i) {
ItemTouchHelper.RecoverAnimation recoverAnimation = (ItemTouchHelper.RecoverAnimation)this.mRecoverAnimations.get(0);
this.mCallback.clearView(this.mRecyclerView, recoverAnimation.mViewHolder);
}
this.mRecoverAnimations.clear();
this.mOverdrawChild = null;
this.mOverdrawChildPosition = -1;
this.releaseVelocityTracker();
this.stopGestureDetection();
}
当this.mRecyclerView和传参的recyclerView不相等的时候,就会不断的setupCallbacks做回调操作,就会不断的去调用自己创建的ItemTouchHelperCallBack。这也就解释了为什么,我在收缩和展开之后会出现那样的现象。
既然知道了问题,那么要如何修改呢?
所以我将RecyclerView固定,当传进去的RecyclerView一样的时候,那么attachToRecyclerView方法就不会重复的去启动ItemTouchHelperCallBack回调。
之后我做的调整如下:
RecyclerView rv;
Ap<String> ap;
ItemTouchHelperCallBack callBack = new ItemTouchHelperCallBack();
ItemTouchHelper helper = new ItemTouchHelper(callBack);
@Override
public View getChildView(int i, int i1, boolean b, View convertView, ViewGroup viewGroup) {
// 尝试将这块改造成支持滑动的ListView
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.device_action_list_item_child_copy, null);
rv = convertView.findViewById(R.id.recycler_view);
rv.setLayoutManager(new LinearLayoutManager(context));
}
Vector<String> stringVector = childData.get(i).get(i1);
ap = new Ap(context, stringVector);
rv.setAdapter(ap);
callBack.set(ap, stringVector);
helper.attachToRecyclerView(rv);
return convertView;
}
修改后,测试通过,不管如何折叠收缩,滑动排序,都没有问题。
693



被折叠的 条评论
为什么被折叠?



