续一,用RecyclerView来实现苹果后台样式的卡片布局

       不知道有没有人有疑问,按照之前的做法的却可以做到竖向拖动,横向删除的ListView了。才发现RecyclerView本身并不提供Item的点击事件,那该怎么办呢?先不急,可以先看看之前提过的类ItemTouchHlper。看看这个类是怎么让这名复杂的操作变得这样简单的。


可以看到,里面有一个属性实现了接口OnItemTouchListener,接口定义了三个方法:

OnInterceptTouchEvent,OnTouchEvent,OnRequestDisallowInterceptTouchEvent

看到这就很明显了,RecyclerView向外暴露了他的这三个方法的入口。分别是:

触摸事件拦截,触摸事件,和申请取消时间拦截,一般重写ViewGroup的时候主要的事件处理方法都提供了,难怪可以在不继承RecyclerView的情况下处理复杂的拖弋事件了。

在后面的绑定事件中,RecyclerView.addItemTouchListener()添加了ItemTouchListener对象。同理可知,也可以通过添加ItemTouchListener对象进行点击事件的监听了。


      看了源码才发现,平凡底下别有洞天。在这里就不再展开论述。

      在方便的同时也引起了我的沉思,在没有对原控件RecyclerView进行修改封装的情况下,RecyclerView发生了巨大的变化。这不能不感叹程序架构起到了巨大的作用。在开发程序的过程中,开发设计人员一直都希望程序的耦合性尽可能的低。就好像人干了坏事后都想把自己外面带,俗称“甩锅”。其实这跟干坏事没关系,又比如很多人都会买外置USB插排。有时候鼠标键盘或者U盘要经常插拔,USB插口就很容易发生松动。如果是USB插排的USB插口松动了,换一个就可以,便宜。要是电脑本机的USB松了,要换就得换主板了,代价可想而知。所以在程序设计的时候就要尽可能的减低模块间的依赖关系。上述是一个很好的例子。我也模仿写了一个例子:

public class ListItemTouchHelper implements RecyclerView.OnItemTouchListener{

    private CallBack callBack;
    private RecyclerView recyclerView;
    private GestureDetector gestureDetector;

    private int touchSlop;
    private RecyclerView.ViewHolder Selected;
    private RecyclerView.ViewHolder PreSelected;

    private float origPointX;
    private float origPointY;
    private float xyProportion;

    private int ActivityPointerID = -1;

    public ListItemTouchHelper(@NonNull CallBack callBack){
        this.callBack = callBack;
    }

    public void attRecyclerView(@NonNull RecyclerView recyclerView){//绑定RecylerView
        if (this.recyclerView != null && recyclerView.equals(this.recyclerView)) {
            return;
        }else if(this.recyclerView != null && !recyclerView.equals(this.recyclerView)){
            destory();
        }
        this.recyclerView = recyclerView;
        this.recyclerView.addOnItemTouchListener(this);
        gestureDetector = new GestureDetector(this.recyclerView.getContext(),listener);
        touchSlop = ViewConfiguration.get(recyclerView.getContext()).getScaledTouchSlop();
        DisplayMetrics d = recyclerView.getContext().getResources().getDisplayMetrics();
        xyProportion = d.widthPixels * 1.0f/d.heightPixels;
    }

    private void destory(){//销毁旧的事件监听
        this.recyclerView.removeOnItemTouchListener(this);
        this.recyclerView = null;
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        gestureDetector.onTouchEvent(e);;
        int action = e.getAction();
        if(action == MotionEvent.ACTION_DOWN){
            ActivityPointerID = MotionEventCompat.getPointerId(e,0);
            origPointX = MotionEventCompat.getX(e,0);
            origPointY = MotionEventCompat.getY(e,0);
        }else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            selected(null);
            ActivityPointerID = -1;
        }else if(action == MotionEvent.ACTION_MOVE){
            canSelect(e);
        }
        return Selected != null;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        gestureDetector.onTouchEvent(e);
        if(e.getAction() == MotionEvent.ACTION_UP){
            selected(null);
        }
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}


    //判断Item的选中事件
    private boolean canSelect(MotionEvent event){
        int action = MotionEventCompat.getActionMasked(event);
        if(action != MotionEvent.ACTION_MOVE) return false;
        if(recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) return false;
        RecyclerView.ViewHolder holder = findViewHolder(event);
        if(holder == null) return false;
        int index = MotionEventCompat.findPointerIndex(event,ActivityPointerID);
        float x = MotionEventCompat.getX(event,index);
        float y = MotionEventCompat.getY(event,index);
        float dx = x - origPointX;
        float dy = y - origPointX;
        float absdx = Math.abs(dx);
        float absdy = Math.abs(dy);
        if(absdx < touchSlop && absdy < touchSlop) return false;
        if(absdx < absdy * xyProportion) return false;
        ActivityPointerID = MotionEventCompat.getPointerId(event,0);
        selected(holder);
        return true;
    }

    private void selected(RecyclerView.ViewHolder holder){
        callBack.selectChange(recyclerView,Selected,holder);
        Selected = holder;
    }

    private GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener(){

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            int x = (int)MotionEventCompat.getX(e,0);
            int y = (int)MotionEventCompat.getY(e,0);
            RecyclerView.ViewHolder holder = findViewHolder(e);
            callBack.singleTap(holder,x,y);
            return super.onSingleTapUp(e);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if(Selected != null)
                callBack.scroll(Selected,distanceX);
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if(Selected != null)
                callBack.fing(Selected,velocityX);
            return super.onFling(e1, e2, velocityX, velocityY);
        }
    };

    //根据事件获取事件下的ViewHolder对象
    private RecyclerView.ViewHolder findViewHolder(MotionEvent event){
        float x = MotionEventCompat.getX(event,0);
        float y = MotionEventCompat.getY(event,0);
        View view = recyclerView.findChildViewUnder(x,y);
        if(view == null) return null;
        return recyclerView.getChildViewHolder(view);
    }

    //事件回调接口
    public interface CallBack{

        public void selectChange(RecyclerView parent,RecyclerView.ViewHolder old_holder,RecyclerView.ViewHolder holder);

        public void scroll(RecyclerView.ViewHolder holder,float distanceX);

        public void fing(RecyclerView.ViewHolder holder,float VelocityX);

        public void singleTap(RecyclerView.ViewHolder holder,float x,float y);

    }
}
这个例子是实现上篇那个滑动显示取消和删除按钮的ListView的案例



在实现Fragment的OnCreateView方法的时候,就几句短短的代码完结了。简洁明了,一目了然。

       机器用的是机器语言,但一般人看不懂,所以就有开发语言的诞生了,通过编译器编译成机器能看懂的机器语言。所以编写代码的过程中非常强调代码的可读性,所以代码的简洁就显得非常重要了。对于可读性,我大学的导师曾经跟我们做过一次讨论,讨论的议题就是关于代码注释的问题。其中有观点说,写注释会使得代码变得不简洁,而且很多用注释的框架,就会使得代码会变得相当混乱,如果不用注释也能让别人看得懂你的代码,那么写代码注释就不重要了。这个观点就见仁见智了。



附上我的代码吧:https://github.com/rj11304/CardPager



后续:http://blog.csdn.net/rj113/article/details/66510609

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值