簡單實現自定義橫向滾動選擇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;
        }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章