RecyclerView实现长按、拖拉、滑动、选中、分割线

长按

  • RecyclerView没有提供监听点击事件的接口,没有mRecyclerView.setOn…,但是可以实现一个实现了RecyclerView.OnItemTouchListener接口的监听抽象类,然后调用RecyclerView的addOnItemTouchListener的方法给RecyclerView设置点击的监听。
  • 默认的时候,view的事件序列是会被TouchEvent截获的,而TouchEvent不提供双击和长按,想让view具备响应双击和长按,需要创建一个实现GestureDetector的接口的类,然后在TouchEvent里让这个类的实例来接收事件。所以,RecyclerView也一样,它需要在内部给自己创建一个这样的类,然后在自己的TouchEvent方法里接收事件序列。
  • 无论是给RecyclerView设置点击监听,还是为点击监听设置GestureDetecor,还是为GestureDetector设置回调,都只是让它们具备了基本的能力,具体的逻辑能力需要自己写。
    总的思路就是:
    1.为RecyclerView添加OnItemTouchListener,让RecyclerView具备事件分发
    2.为ReyeclerView的事件分发设置GestureDetector,让RecyclerView可以响应双击或者长按等
    3.在GestureDetector的具体实现里,结合RecyclerView的2个方法判断出具体的子项
    4.判断出具体的子项之后,用回调函数交给RecyclerView实例做处理;

点击事件监听类的实现:

  /**
 * Created by  on 2017/9/19.
 */

public abstract class OnRecyclerItemClickListener implements RecyclerView.OnItemTouchListener{

    private RecyclerView mRecyclerView;
    private GestureDetectorCompat mGestureDetectorCompat;

    /**
     * 在创建实例的时候,传进指定的RecyclerView实例
     * 同时使用实现了GestureDetector.SimpleOnGestureListener接口的类实例来创建GestureDetector
     * @param recyclerView
     */
    public OnRecyclerItemClickListener(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
        mGestureDetectorCompat = new GestureDetectorCompat(mRecyclerView.getContext(),new ItemTouchHelperGestureListener());
    }

    /**
     * 重写下面三个方法,让GestureDetector接收事件
     * @param rv
     * @param e
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetectorCompat.onTouchEvent(e);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetectorCompat.onTouchEvent(e);
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }

    /**
     * 需要调用者,也就是RecyclerView实例实现的抽象方法
     * @param viewHolder
     */
    public abstract void onItemClick(RecyclerView.ViewHolder viewHolder);
    public abstract void onLongClick(RecyclerView.ViewHolder viewHolder);

    /**
     * 实现一个GestureDetector,重写关于单点和长按方法
     */
    private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            //通过点击事件的坐标,用findChileViewUnder找到被点击的view
            View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(),e.getY());
            if (childViewUnder != null){
                //通过被点击的view,用getChildViewHolder找到被点击的viewHolder
                RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(childViewUnder);
                onItemClick(childViewHolder); //回调
            }
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View chileViewUnder = mRecyclerView.findChildViewUnder(e.getX(),e.getY());
            if (chileViewUnder != null){
                RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(chileViewUnder);
                onLongClick(childViewHolder);
            }
        }
    }
}

具体的使用:

public class Listener extends OnRecyclerItemClickListener{

            public Listener(RecyclerView recyclerView){
                super(recyclerView);
            }
            @Override
            public void onItemClick(RecyclerView.ViewHolder viewHolder) {
                //do someting;
            }

            @Override
            public void onLongClick(RecyclerView.ViewHolder viewHolder) {
                //do something;
            }
}
Listener listener = new Listener(mRecyclerView);
mRecyclerView.addOnItemTouchListener(listener);

或者使用匿名内部类的方式:

mRecyclerView.addOnItemTouchListener(new OnRecyclerItemClickListener(mRecyclerView) {
            @Override
            public void onItemClick(RecyclerView.ViewHolder viewHolder) {
                //do someting;
            }

            @Override
            public void onLongClick(RecyclerView.ViewHolder viewHolder) {
                //do something;
            }
        });

拖动、侧滑、选中

拖动可以使用ItemTouchHelper来实现,它的内部封装了很多的接口,包括拖动、侧滑、选中等等,我们只要将需要实现这些功能的view(不仅仅是RecyclerView)设置给它,然后自己实现接口里需要的逻辑就行了。
比如,实现回调接口类:

public class Call implements ItemTouchHelper.Callback{
    //@Override 重写需要的方法;
    ...
}

然后用这个类的实例来创建ItemTouchHelper实例,再将RecyclerView或者其他的view设置给ItemTouchHelper实例

ItemTouchHelper helper = new ItemTouchHelper(new Call());
helper.attachToRecyclerView(mRecyclerView);

ItemTouchHelper.Callback的重写例子:

/**
 * Created by  on 2017/9/19.
 */

public class ItemTouchCallback extends ItemTouchHelper.Callback {
    private NoteAdaper mNoteAdaper;
    public ItemTouchCallback(){
        super();
    }

    /**
     * 通过使用RecyclerView的适配器来操作RecyclerView
     * @param noteAdaper
     */
    public ItemTouchCallback(NoteAdaper noteAdaper){
        mNoteAdaper = noteAdaper;
    }

    /**
     * 这个方法用于决定哪些方向的滑动是允许的,或者说是可以引起响应的
     * @param recyclerView
     * @param viewHolder
     * @return  int 返回一个整型,标志是否允许滑动
     */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        //如果是线性的,设置拖拉方向为上和下,侧滑为左和右
        if (recyclerView.getLayoutManager() instanceof LinearLayoutManager){
            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
            return makeMovementFlags(dragFlags,swipeFlags);
        }else{  //如果是表格性的,设置上下左右四个方向
            if (recyclerView.getLayoutManager()instanceof GridLayoutManager){
                int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN
                        |ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                int swipeFlags = 0;  //0代表不滑动
                return makeMovementFlags(dragFlags,swipeFlags);
            }
        }
        return 0;
    }

    /**
     * 这个方法响应拖动事件
     * @param recyclerView
     * @param viewHolder  被拖动的viewHolder
     * @param target   位置被代替的viewHolder
     * @return
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

        int fromPostion = viewHolder.getAdapterPosition();
        int toPosition = target.getAdapterPosition();
        //如果子项是向下托拉,从拖拉位置开始的地方到目标位置的前一个位置,全部子项向后一个子项交换数据
        if (fromPostion < toPosition){
            for (int i = fromPostion; i < toPosition; i ++){
                Collections.swap(mNoteAdaper.getDataList(),i,i + 1);
            }
        }else { //如果子项是向上拖拉,从拖拉位置开始到目标位置的下一个位置,全部子项向前一个子项交换数据
            for (int i = fromPostion; i > toPosition; i--){
                Collections.swap(mNoteAdaper.getDataList(),i,i - 1);
            }
        }
        //上一步交换完数据,这一步交换视图
        mNoteAdaper.notifyItemMoved(fromPostion,toPosition);
        return true;
    }

    /**
     * 这个方法响应侧滑
     * @param viewHolder  被滑动的子项
     * @param direction  滑动方向,可以根据不同的方向做不同的事情
     */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        int adapterPosition = viewHolder.getAdapterPosition();  //获得被侧滑的子项位置
        mNoteAdaper.notifyItemRemoved(adapterPosition);  //视图清除
        mNoteAdaper.getDataList().remove(adapterPosition);  //数据清除
    }

    /**
     * 响应选中
     * @param viewHolder  被选中的子项
     * @param actionState  子项的选中状态,可以根据子项的选中状态做不同的处理
     */
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE){  //ItemTouchHelper.ACTION_STATE_IDLE 空闲状态
            viewHolder.itemView.setBackground(MyApplication.getContext().getDrawable(R.drawable.gray));
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    /**
     * 这个方法用于当拖动、侧滑、选中等等动作消失后,需要做的处理
     * @param recyclerView
     * @param viewHolder  被操作的子项
     */
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setBackground(MyApplication.getContext().getDrawable(R.drawable.white));
    }
}

使用例子:

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchCallback(mNoteAdaper));
    itemTouchHelper.attachToRecyclerView(mRecyclerView);

下滑线

方式1:
创建一个drawable对象,然后在子项布局的底部加一个ImageView,然后设置这个drawable对象为背景,drawable对象:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/gray"/>
    <size android:height="1px"/>
</shape>

方式2:
使用RecyclerView的addItemDecoration方法:

mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));

一个可以参考一下的便签app (还没完善全部功能)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值