Android RecyclerView3 中 item 侧滑、拖住实现

 1.  Anroid 提供API关于 拖拽、侧滑

 Android ItemTouchHelper.Callback API认识:
    final ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);   callbak 使用ItemTouchHelper  包装
   传递给:  itemTouchHelper.attachToRecyclerView(mRecyclerView);


   // 设置用户监听动作方向,比如上下拖动、水平滑动
    @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        }
        // 当拖拽 item 移动的时候回调,回调以后可以用于数据交换
         @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder srcHolder, RecyclerView.ViewHolder targetViewHolder) {
        }
        // 当Item 侧滑的时候回调
           @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
         // 当Item 拖拽被选中的时候回调
          @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        
        }
        // 当item 被删除的时候回调
        // 比如交换位置,从原来位置删除,在新位置上绘制
        // 比如 item 侧滑被删除的时候

           @Override
        public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        }
        // 当child 绘制的时候
        // 比如拖动、侧滑,Item的状态需要不断的绘制

                @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        }
        // 是否允许长按拖拽效果,item默认支持返回true即可
          @Override
        public boolean isLongPressDragEnabled() {
            return true;
        }

2. 实现上下拖拽、并且松开以后刷新数据

2.1. 开启监听上下拖拽 ,实现 ItemTouchHelper.Callback 接口回调方法

 // 1. 用于监听那个方向的拖动
        //  先上、先下、左、右

        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            int up=  ItemTouchHelper.UP;
            int down = ItemTouchHelper.DOWN;
            int  left = ItemTouchHelper.LEFT;
            int right =ItemTouchHelper.RIGHT;

            // 我要监听拖拽的方向
            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            //  要监听 swiper 侧滑是哪个方向
            int swipeFlags= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

            int flasg = makeMovementFlags(dragFlags,swipeFlags);

            return flasg;
        }

 2. 设置item可以支持上下拖拽功能
    //  重写这个方法以后item那么就支持 长按拖拽了 

   // 3. 是否允许长按 拖拽效果
        @Override
        public boolean isLongPressDragEnabled() {
            return true;
        }

    // 不用上面item直接拖拽,使用item中的某一个imageView来实现拖拽效果,那么需要把ViewHolder中某一个控件的
   3. 那么如何设置按下item中的 imageView 实现拖拽 item的效果
    // 不用上面item直接拖拽,使用item中的某一个imageView来实现拖拽效果,
     那么需要监听到ViewHolder中某一个控件的被 MotionEvent.ACTION_DOWN ,把ViewHoldr传递给
      itemTouchHelper.attachToRecyclerView(mRecyclerView);
     MyAdapter 实现代码: 内层代码

 StartDragListener  startDragListener;
	  public void setStartDragListener(StartDragListener startDragListener) {
        this.startDragListener = startDragListener;
    }
	 @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position) {
        Log.e(TAG, "set value to item:" + position);
        holder.title.setText(datas.get(position));
        // 监听按下事件,一直按下,一直监听, 监听ImageView的按下时间
        holder.rv_main_image.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {

                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){

                    // 传递给谁
                    startDragListener.onStartDrag(holder);
                }

                return false;
            }
        });
    }

     MyActivity外出代码: 

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		
		      // 设置 按下ViewHolder中的ImageView实现 拖拽效果
        mMyAdapter.setStartDragListener(new StartDragListener() {
            @Override
            public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
                itemTouchHelper.startDrag(viewHolder);

            }
        });
		
       }

4. 如何在拖拽的时候刷新数据

 // 2.  ItemTouchHelper.Callback 当拖拽 Item 移动的时候回调
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder srcHolder, RecyclerView.ViewHolder targetViewHolder) {
// 相同条目不进行交换
            if(srcHolder.getItemViewType()!=targetViewHolder.getItemViewType()){
                return false;
            }
            // 回调把参数传递外外面去,在外面实现方法的回调
			// 返回在,外面执行方法的返回值
            boolean flag= itemTouchMoveListener.onItemMove(srcHolder.getAdapterPosition(),targetViewHolder.getAdapterPosition());
            return flag;
        }

5. MainActivity中 监听拖拽,交换数据

 MyItemTouchHelperCallback callback=new MyItemTouchHelperCallback();
        // 监听拖拽 刷新数据, 把拖拽位置传递出来
        callback.setItemTouchMoveListener(new ItemTouchMoveListener() {
            @Override
            public boolean onItemMove(int fromPositon, int toPosition) {
                //   数据交换
                Collections.swap(datas,fromPositon,toPosition);
                mMyAdapter.notifyItemMoved(fromPositon,toPosition);
                return true;
            }
        });
  

  效果图:

====================================================================== 
  设置选中的时候设置颜色,没有选中的时候去掉颜色

    //  Item  被选中回调
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            // 判断选中
            if(actionState != ItemTouchHelper.ACTION_STATE_IDLE ){
                viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getResources().getColor(R.color.colorPrimary));
            }
            // 松开的时候要复原
            super.onSelectedChanged(viewHolder, actionState);
        }
        // 松开的时候要复原
        @Override
        public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
          // 默认白色
            viewHolder.itemView.setBackgroundColor(Color.WHITE);
            super.clearView(recyclerView, viewHolder);
        }
======================================================================   
  侧滑动画设置:  回调函数onChildDraw【绘制ViewHolder的时候回调】
  
   @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            // 只是侧滑的时候起作用
            if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
            // dx 就是从 0- View.getWidth
                // 转化透明度 0 ~1
                // 1减去,那么就是 1-0了 , 不透明度1   显示  不透明度0,透明度0 不显示
                 float  alphaValue=  1- Math.abs(dX/viewHolder.itemView.getWidth());
                 Log.e("denganzhi1",alphaValue+"");
                 viewHolder.itemView.setAlpha(1);
                  // 属性动画就是简单
                 viewHolder.itemView.setScaleX(1);
                 viewHolder.itemView.setScaleY(1);
            }
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
  
  侧滑绘制以后有空白部分问题?
  引申: ListViwe 和 RecyclerView 都有复用问题,
  比如有 checkbox的时候ListView,如果一个item改变了checkbox,那么在滑动的时候该item的复用checkbox也会改变
  
  
   ****** 被复用的ViewHoder复用以后,要恢复默认属性
  解决实例1:当View隐藏的时候恢复该ViewHolder的默认数据:
  // 正确理解,当ViewHolder的View被删除的时候,
        // 如果交换位置,那么交换位置结束了,那么View从原来的位置删除,在新位置绘制
        // 松开的时候要复原
        @Override
        public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
          // 默认白色
            viewHolder.itemView.setBackgroundColor(Color.WHITE);
//            viewHolder.itemView.setAlpha(1);
//            // 属性动画就是简单
//            viewHolder.itemView.setScaleX(1);
//            viewHolder.itemView.setScaleY(1);
            super.clearView(recyclerView, viewHolder);
        }
  
  或者解决方案:

 @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            // 只是侧滑的时候起作用
            // dx 就是从 0- View.getWidth
            // 转化透明度 0 ~1
            // 1减去,那么就是 1-0了 , 不透明度1   显示  不透明度0,透明度0 不显示
            float  alphaValue=  1- Math.abs(dX/viewHolder.itemView.getWidth());
            if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
                 Log.e("denganzhi1",alphaValue+"");
                 viewHolder.itemView.setAlpha(1);
                  // 属性动画就是简单
                 viewHolder.itemView.setScaleX(1);
                 viewHolder.itemView.setScaleY(1);
            }

// 用完以后回复
            if(alphaValue==0){
                viewHolder.itemView.setAlpha(1);
                // 属性动画就是简单
                viewHolder.itemView.setScaleX(1);
                viewHolder.itemView.setScaleY(1);
            }
            // 隐藏以后调用super 删除View 
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
************************************************************************************************

   类视QQ的 条目侧滑一半效果实现:
  
  **** 未实现???
  // 判断是否超出或者达到 width/2, 那么让 setTranslationX位一半位置
            // 默认 在滑动的不断调用 super.onChildDraw去 绘制
            // 那么在 一半的时候不要调用super.onChildDraw 方法,那么就暂停在这里了
            if(Math.abs(dX) <= viewHolder.itemView.getWidth()/2 ){

                viewHolder.itemView.setTranslationX((-0.5f* viewHolder.itemView.getWidth()));
            }else{
                viewHolder.itemView.setTranslationX(dX);
            }
          //  super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

  **** 思路2:
   ItemView设置成功一个ViewPager,左右2个View
   
   
************************************************************************************************

3. 实现侧滑功能  

MyItemTouchHelperCallback 重写方法

 @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            int up=  ItemTouchHelper.UP;
            int down = ItemTouchHelper.DOWN;
            int  left = ItemTouchHelper.LEFT;
            int right =ItemTouchHelper.RIGHT;
            // 我要监听拖拽的方向
            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            //  要监听 swiper 侧滑是哪个方向
            int swipeFlags= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            int flasg = makeMovementFlags(dragFlags,swipeFlags);
            return flasg;
        }
		
		 // 7. 监听侧滑  
		   @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            // 侧滑回调,刷新数据
            itemTouchRemoveListener.onItemReMove(viewHolder.getAdapterPosition());

        }

   MainActivity 中实现回调,刷新数据

 // 自定义回调
        callback.setItemTouchRemoveListener(new ItemTouchRemoveListener() {
            @Override
            public boolean onItemReMove(int position) {
                datas.remove(position);
                mMyAdapter.notifyItemRemoved(position);
                return true;
            }
        });

发布了78 篇原创文章 · 获赞 74 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/dreams_deng/article/details/104734199
今日推荐