Scollerview与Recyclerview 嵌套拖拽处理

##做便签选择功能,类似熊猫直播的常用频道选择,遇到了Scollerview嵌套Recyclerview无法触发拖拽处理##
* 一开始想着直接用哒神的库直接调用,结果出来发现scollerview嵌套无法拖拽了,上网查了好多都是无解,后来无奈直接自己重写ItemTouchHelperCallback粘性回调处理了

先看下效果图吧

mahua

实现思路

1.首先先做个接口

public interface ItemTouchHelperAdapter {
    boolean onItemMove(int fromPosition, int toPosition);
    void onItemDismiss(int position);
}

2.写对应的ItemTouchHelperCallback

public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private ItemTouchHelperAdapter adapter;

    public ItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        this.adapter = adapter;
    }

    /**
     * 返回true,开启长按拖拽
     * @return
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    /**
     * 返回true,开启swipe事件
     * @return
     */
    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }

    /**
     * getMovementFlags、onMove、onSwiped是必须要实现的三个方法
     *
     */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            //适用GridLayoutManager类型和LinearLayoutManager类型。
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager) {
                //拖拽的方向。
                int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                //侧滑的方向:left right。
                return makeMovementFlags(dragFlags, swipeFlags);
            } else if (layoutManager instanceof LinearLayoutManager) {
                //线性方向分为:水平和垂直方向。
                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
                if (linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) {
                    int dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                    int swipeFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                    return makeMovementFlags(dragFlags, swipeFlags);
                } else {
                    //拖拽的方向。
                    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                    //侧滑的方向:left right。
                    int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                    return makeMovementFlags(dragFlags, swipeFlags);
                }
            }
        return makeMovementFlags(0, 0);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        /**
         * 回调
         */
        adapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        /**
         * 回调
         */
        adapter.onItemDismiss(viewHolder.getAdapterPosition());

    }
}

3.之后就可以写adapter添加自己的回调了(具体看源码吧)

  @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        mOnItemMoveLin.onItemMoveing(fromPosition,toPosition);
        return true;
    }

4.在主页面设置helper与recyclerview的关联

 ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(mMenuAdapter_new);
        helper = new ItemTouchHelper(callback);
        helper.attachToRecyclerView(recycler_view_new);

其他就没啥重要的了可以下载源码了看了

点我下载源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
功能树形结构 RecyclerView支持滑动删除支持长按拖拽支持单个 view 点击或长按时拖拽可开启并更改滑动删除背景色可自由指定滑动删除和拖拽操作的方向展开关闭全部分组下载Demo:下载截图使用方法添加jitpack库//build.gradle(Project:)  allprojects {       repositories {     ...      maven { url 'https://www.jitpack.io' }      }     }添加依赖 //build.gradle(Module:)dependencies {    compile 'com.github.goweii:SwipeDragTreeRecyclerView:v1.2.0'  }在xml布局文件中使用官方RecyclerView<android.support.v7.widget.RecyclerView android:id="@ id/swipe_drag_tree_recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" > </android.support.v7.widget.RecyclerView>继承 TreeState 增加几个静态变量,用于标识 item 的类别当然,你的数据应该存放在 TreeState 中public class TestTreeState extends TreeState {     public static final int TYPE_ONE = 1;     public static final int TYPE_TEO = 2;     public static final int TYPE_THREE = 3;     public static final int TYPE_FOUR = 4; }用你的 adapter 继承 BaseSwipeDragTreeAdapter 实现几个方法putTypeLayoutViewIds(int viewType, int layoutId, int[] viewIds, int[] clickFlags) 这4个参数的含义为:putTypeStartDragViewIds(int viewType, @IdRes int[] viewIds, int[] startDragFlags) 如果你想让某一个 view 在点击或者长按时实现拖拽,而不是在长按整个 item 时,应该调用这个方法完成配置viewType 类别 继承 TreeState 增加的静态变量layoutId 布局idviewIds 布局中需要用到的 view 的 idclickFlags 设置 view 是否需要点击事件,设置为 null 时默认不开启长按和单击, ClickFlag 为 adapter 的静态内部类,你直接使用即可viewType 布局类型viewIds 拖拽操作的 view 的 idstartDragFlags 拖拽标志,StartDragFlag 为 adapter 的静态内部类,你直接使用即可initIds() 在这个方法中你应该调用下面2个方法完成相关初始化bindData(BaseViewHolder holder, TypeData data) 你应该调用 holder.getItemViewType() 方法得到自定义的 item 的类别,依据类别判断 holder 绑定的数据类型,然后调用 holder 的 getView 方法获取 view 实例进行数据绑定public class TestBaseSwipeDragTreeAdapter extends BaseSwipeDragTreeAdapter {     private final int mOrientationType;     public TestBaseSwipeDragTreeAdapter(int orientationType) {         super();         mOrientationType = orientationType;     }     @Override     public void initIds() {         putTypeLayoutViewIds(TestTreeState.TYPE_ONE, R.layout.item1_swipe_drag_tree_recycler_view,                 new int[]{R.id.item1_sdtrv_tv}, null);         putTypeLayoutViewIds(TestTreeState.TYPE_TEO, R.layout.item2_swipe_drag_tree_recycler_view,                 new int[]{R.id.item2_sdtrv_tv}, null);         putTypeLayoutViewIds(TestTreeState.TYPE_THREE, R.layout.item3_swipe_drag_tree_recycler_view,                 new int[]{R.id.item3_sdtrv_tv}, null);         putTypeLayoutViewIds(TestTreeState.TYPE_FOUR, R.layout.item4_swipe_drag_tree_recycler_view,                 new int[]{R.id.item4_sdtrv_tv}, null);         putTypeLayoutViewIds(TestTreeState.TYPE_LEAF, R.layout.item5_swipe_drag_tree_recycler_view,                 new int[]{R.id.item5_sdtrv_tv}, null);         putTypeStartDragViewIds(TestTreeState.TYPE_ONE,                 new int[]{R.id.item1_sdtrv_tv}, null);         putTypeStartDragViewIds(TestTreeState.TYPE_TEO,                 new int[]{R.id.item2_sdtrv_tv}, null);         putTypeStartDragViewIds(TestTreeState.TYPE_THREE,                 new int[]{R.id.item3_sdtrv_tv}, null);         putTypeStartDragViewIds(TestTreeState.TYPE_FOUR,                 new int[]{R.id.item4_sdtrv_tv}, null);         putTypeStartDragViewIds(TestTreeState.TYPE_LEAF,                 new int[]{R.id.item5_sdtrv_tv}, null);     }     @Override     protected void bindData(BaseViewHolder holder, TypeData data) {         SwipeDragTreeViewHolder viewHolder = (SwipeDragTreeViewHolder) holder;         switch (holder.getItemViewType()) {             case TestTreeState.TYPE_ONE:                 TextView textView0 = (TextViewviewHolder.getView(R.id.item1_sdtrv_tv);                 textView0.setText((String) data.getData());                 break;             case TestTreeState.TYPE_TEO:                 TextView textView1 = (TextViewviewHolder.getView(R.id.item2_sdtrv_tv);                 textView1.setText((String) data.getData());                 break;             case TestTreeState.TYPE_THREE:                 TextView textView2 = (TextViewviewHolder.getView(R.id.item3_sdtrv_tv);                 textView2.setText((String) data.getData());                 break;             case TestTreeState.TYPE_FOUR:                 TextView textView3 = (TextViewviewHolder.getView(R.id.item4_sdtrv_tv);                 textView3.setText((String) data.getData());                 break;             case TestTreeState.TYPE_LEAF:                 TextView textView4 = (TextViewviewHolder.getView(R.id.item5_sdtrv_tv);                 textView4.setText((String) data.getData());                 break;             default:                 break;         }     } }在你的 activity 中调用 init() 方法为适配器绑定数据mSwipeDragTreeRecyclerView.setLayoutManager(getLayoutManager()); mSwipeDragTreeRecyclerView.setAdapter(mTestBaseSwipeDragTreeAdapter); mTestBaseSwipeDragTreeAdapter.init(mDatas);Adapter 相关方法说明init(ArrayList datas)给适配器绑定数据isMemoryExpandState()获取分组关闭后是否记忆子分组的展开状态setMemoryExpandState(boolean memoryExpandState)设置分组关闭后是否记忆子分组的展开状态isAllExpand()获取是否已经展开所有分组expandAll()展开所有分组collapseAll()关闭所有分组getPositions(int position)获取该 holder 位置所显示数据在树形结构数据中所处的位置setOnExpandChangeListener(OnExpandChangeListener onExpandChangeListener)设置 item 展开状态改变监听器notifyItemSwipe(int position)更新数据滑动删除,在监听器中调用更新数据notifyItemDrag(int currentPosition, int targetPosition)更新数据拖拽移动,在监听器中调用更新数据setOnItemSwipeListener(SwipeDragCallback.OnItemSwipeListener onItemSwipeListener)设置滑动删除监听器,应该调用 notifyItemSwipe 方法更新数据显示setOnItemDragListener(SwipeDragCallback.OnItemDragListener onItemDragListener)设置 item 拖拽监听器,应该调用 notifyItemDrag 方法更新数据显示setItemViewSwipeEnabled(boolean itemViewSwipeEnabled)设置开启关闭滑动删除setLongPressDragEnabled(boolean longPressDragEnabled)设置开启关闭长按拖拽setSwipeBackgroundColorEnabled(boolean swipeBackgroundColorEnabled)设置开启关闭滑动删除背景色isItemViewSwipeEnabled()获取是否开启滑动删除isLongPressDragEnabled()获取是否开启长按拖拽isSwipeBackgroundColorEnabled()获取是否开启滑动删除背景色setSwipeBackgroundColor(@ColorInt int swipeBackgroundColor)设置滑动删除背景色颜色setCustomSwipeFlag(int customSwipeFlag)设置可以滑动删除的方向,默认为垂直于滚动方向的2个方向setCustomDragFlag(int customDragFlag)设置可以拖拽的方向,线性布局默认为平行于滚动方向的2个方向,网格和流布局默认为上下左右4个方向都可以setOnItemViewClickListener(OnItemViewClickListener onItemViewClickListener)设置 itemView 点击监听器setOnItemViewLongClickListener(OnItemViewLongClickListener onItemViewLongClickListener)设置 itemView 长按监听器setOnCustomViewClickListener(OnCustomViewClickListener onCustomViewClickListener)设置 item 子 view 点击监听器,需要在适配器的 initIds() 方法中开启setOnCustomViewLongClickListener(OnCustomViewLongClickListener onCustomViewLongClickListener)设置 item 子 view 长按监听器,需要在适配器的 initIds() 方法中开启注意发现 bug 请联系 QQ302833254
RecyclerView 嵌套 RecyclerView 可以用来实现一些复杂的列表布局,比如类似于网格布局的效果。实现的方法可以分为两种:使用 RecyclerView.Adapter 实现和使用 RecyclerView.LayoutManager 实现。 1. 使用 RecyclerView.Adapter 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 Adapter 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 Adapter 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerAdapter> innerAdapters; public void setInnerAdapters(List<InnerAdapter> innerAdapters) { this.innerAdapters = innerAdapters; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setAdapter(innerAdapters.get(position)); } @Override public int getItemCount() { return innerAdapters.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); innerRecyclerView.setLayoutManager(new LinearLayoutManager(itemView.getContext(), RecyclerView.HORIZONTAL, false)); } } } ``` 在内层 RecyclerView 的 Adapter 中,需要重写 onCreateViewHolder 方法,创建内层 RecyclerViewViewHolder,同时需要重写 onBindViewHolder 方法,将数据绑定到内层 RecyclerViewViewHolder 上。 ```java public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.InnerViewHolder> { private List<String> data; public void setData(List<String> data) { this.data = data; } @NonNull @Override public InnerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_inner, parent, false); return new InnerViewHolder(view); } @Override public void onBindViewHolder(@NonNull InnerViewHolder holder, int position) { holder.textView.setText(data.get(position)); } @Override public int getItemCount() { return data.size(); } static class InnerViewHolder extends RecyclerView.ViewHolder { TextView textView; public InnerViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ``` 2. 使用 RecyclerView.LayoutManager 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 LayoutManager 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 LayoutManager 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerLayoutManager> innerLayoutManagers; public void setInnerLayoutManagers(List<InnerLayoutManager> innerLayoutManagers) { this.innerLayoutManagers = innerLayoutManagers; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setLayoutManager(innerLayoutManagers.get(position)); } @Override public int getItemCount() { return innerLayoutManagers.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); } } } ``` 在内层 RecyclerView 的 LayoutManager 中,需要重写 generateDefaultLayoutParams 方法,设置内层 RecyclerView 的布局参数,同时需要重写 canScrollHorizontally 和 canScrollVertically 方法,判断内层 RecyclerView 是否可以滑动。 ```java public class InnerLayoutManager extends LinearLayoutManager { public InnerLayoutManager(Context context) { super(context); } @Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override public boolean canScrollHorizontally() { return false; } @Override public boolean canScrollVertically() { return false; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值