之前接到一个优化需求,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; }