简单实现自定义横向滚动选择View优化

之前接到一个优化需求,ui嫌弃横向滚动卡顿,提了优化需求,我发现自定义view是来自郭霖的简单实现自定义横向滚动的文章,未读过的请看原文
现在发现的问题是

  1. 当前页面设置了最多显示3个,而原文只有滑动超过一个view的单位宽度时才切换,就导致切换到下一个变得很难
    我将其修改为超过单位宽度的一半则自动切换到下一组文字,修改代码如下

    case MotionEvent.ACTION_UP:
         float del = anInt * 1.0f / 2;
         if (Math.abs(anOffset) > del) {
             Log.d("TEST", "anOffset:" + anOffset);
             //滑动大于一个单位的2/3,则惯性滑动到下一个
             if (anOffset > 0) {
                 //向右滑动(抬起点比按下点x值大,n--)
                 anOffset = 0.0F;
                 setAnRightOffset();
             } else {
                 anOffset = 0.0F;
                 setAnLeftOffset();
                 }
         } else {
             //否则,偏移量归零,相当于回弹。
             anOffset = 0.0F;
             invalidate();
         }
         break; 
    

    setAnRightOffset,setAnLeftOffset方法也做了修改

    /**
         * 向右移动一个单元
         */
        public void setAnRightOffset() {
            Log.d("TEST", "向右移动一个单元");
            if (n > 0) {
                --n;
            }
            invalidate();
        }
    
    /**
         * 向左移动一个单元
         */
        public void setAnLeftOffset() {
            Log.d("TEST", "向左移动一个单元");
            if (n < strings.size() - 1) {
                ++n;
            }
            invalidate();
        }
    
  2. 因为这个view是横向滚动的,而且高度比较小,这样就很容易导致滑动一小块就移出了view的区域,而默认情况下当不在view区域时会产生MotionEvent.ACTION_CANCEL事件,导致真个触摸事件无效,表现出来就是滑动卡顿
    而我研究与他比较相似的TabLayout发现它在滑动离开区域时还是可以继续响应move事件的,而我通过此文章android ACTION_CANCEL事件知道了Cancel事件发生的原因是被父控件拦截了,而我们要想实现子view离开控件后还可以继续滑动只要请求父view不拦截我们的点击事件就可以了
    于是我在onTouchEvent里添加了以下代码

    getParent().requestDisallowInterceptTouchEvent(true);
    

    这样就实现了只要在我们自定义view开始发生的触摸事件,不论你移动到何处当前view都可以响应这次触摸事件,所谓的卡顿为题就解决了

    最后的onTouchEvent代码如下

    @Override
        public boolean onTouchEvent(MotionEvent event) {
            getParent().requestDisallowInterceptTouchEvent(true);
            Log.e("TEST", "onTouchEvent: " + event.getAction());
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downX = event.getX();
                    break;
                case MotionEvent.ACTION_UP:
                    float del = anInt * 1.0f / 2;
                    if (Math.abs(anOffset) > del) {
                        Log.d("TEST", "anOffset:" + anOffset);
                        //滑动大于一个单位的2/3,则惯性滑动到下一个
                        if (anOffset > 0) {
                            //向右滑动(抬起点比按下点x值大,n--)
                            anOffset = 0.0F;
                            setAnRightOffset();
                        } else {
                            anOffset = 0.0F;
                            setAnLeftOffset();
                        }
    
                    } else {
                        //否则,偏移量归零,相当于回弹。
                        anOffset = 0.0F;
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    float scrollX = event.getX();
                    if (n != 0 && n != strings.size() - 1) {
                        //滑动时的偏移量,用于计算每个是数据源文字的坐标值
                        anOffset = scrollX - downX;
                    } else {
                        //当滑到两端的时候添加一点阻力
                        anOffset = (float) ((double) (scrollX - downX) / 1.5D);
                    }
    
                    if (scrollX > downX) {
                        //向右滑动,当滑动距离大于每个单元的长度时,则改变被选中的文字。
                        if (scrollX - downX >= (anInt) && n > 0) {
                            anOffset = 0.0F;
                            --n;
                            downX = scrollX;
                            if (mOnSelectedChangedListener != null) {
                                mOnSelectedChangedListener.selectedChanged(getSelectedString());
                            }
                        }
                    } else if (downX - scrollX >= (anInt) && n < strings.size() - 1) {
                        //向左滑动,当滑动距离大于每个单元的长度时,则改变被选中的文字。
                        anOffset = 0.0F;
                        ++n;
                        downX = scrollX;
                        if (mOnSelectedChangedListener != null) {
                            mOnSelectedChangedListener.selectedChanged(getSelectedString());
                        }
                    }
    
                    invalidate();
                default:
            }
    
            return true;
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值