之前接到一個優化需求,ui嫌棄橫向滾動卡頓,提了優化需求,我發現自定義view是來自郭霖的簡單實現自定義橫向滾動的文章,未讀過的請看原文
現在發現的問題是
-
當前頁面設置了最多顯示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(); }
-
因爲這個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; }