近期我们可爱的产品提了一个需求,要向大厂看齐。仿照某易新闻客户端,在浏览图集的时候,希望底下的文字可以滚动。怎么样个滚动法呢,效果如下:
当文本过长时,可以和标题一起向上滚动。当滚动到一个最大高度时,如果文本还未完全显示,可以继续滚动。需求看似很简单,一开始的思路是Scrollview进行嵌套,一番研究后发现一个问题。Scrollview的TouchEvent事件中判断如果是拖动操作会一直拦截,导致即使外层的Scrollview滑到顶部了,里层的Scrollview也接受不到触摸事件。
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { /* * This method JUST determines whether we want to intercept the motion. * If we return true, onMotionEvent will be called and we do the actual * scrolling there. */ /* * Shortcut the most recurring case: the user is in the dragging * state and he is moving his finger. We want to intercept this * motion. */ final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true; } /* * Don't try to intercept touch if we can't scroll anyway. */ if (getScrollY() == 0 && !canScrollVertically(1)) { return false; }
........
}
截取了其中的一段源码,mIsBeingDragged变量一旦置为true,ScrollView会直接拦截触摸事件并处理,直到执行完ACTION_UP。这就很尴尬了啊,我必须先滑动父Scrollview到顶部,然后松开手指,再滑动子Scrollview才能滚动文本。类似如下的效果:
不是如丝般顺滑,怎么能接受呢。如果想继续优化,必须对触摸事件的分发和拦截重新复写,感觉是个无底洞,果断放弃。后来无意间看到一个ObservableScrollView的Demo,受到了启发。
和我的需求很吻合啊,如获至宝,研读一番发现,如来它只有一个Scrollview,标题根据滚动的距离来tranlation,很鸡贼啊!本着拿来主义的精神,立即对其一番改造。在图集的ViewPage上加一层头部透明的Scrollview,title的高度进行计算设置,不就OK了么!但有一个问题需要注意,即ScrollView透明的头部用户看不见,但是响应滑动事件,同时拦截了下面ViewPage的翻页操作,这显然是个bug。我们只需在上面ScrollView中的dispatchTouchEvent做下处理就行了。
@Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean dispatch = super.dispatchTouchEvent(ev); if (mIgnoreTouchRect != null) { Rect curTouchRect = new Rect(mIgnoreTouchRect.left, mIgnoreTouchRect.top, mIgnoreTouchRect.right, mIgnoreTouchRect.bottom - mScrollY > 0 ? mIgnoreTouchRect.bottom - mScrollY : 0); if (curTouchRect.contains((int)ev.getX(), (int)ev.getY())) { return false; } else { return dispatch; } } else { return dispatch; } }
这里的mIgnoreTouchRect是初始化时设置的,即我们不拦截触摸操作的区域,之所以又减了个mScrollY的高度,是考虑到ScrollView滚动后,非触摸操作区域的变化。好了,到这所有的问题都完美解决了。
怎么样?perfect!希望对有相同需求的同学有一点帮助,需要源码的可以给我留言。