- 在 AbsListView、HorizontalScrollView、ScrollView 的 onTouchEvent 中判断是否到达边界(顶部 或 底部) ,然后调 view.overScrollBy ,传入 scrollX、scrollY 等参数
- overScrollBy 最终赋值给View的 mScrollX, mScrollY 两个变量
- 在AbsListView中调用完overScrollBy之后,调用invalidate重绘
/**
* 当 View 滚动超过了 View 的内容边界的时候, 该方法可以使用统
* 一的标准的行为来滚动 view。调用这个方法的 View 应该重写
* onOverScrolled 方法来响应滚动越界的行为。View 可以使用这个
* 方法来处理任何 touch 和 fling 的滚动
*
* @param deltaX Change in X in pixels scrollx 变化量
* @param deltaY Change in Y in pixels
* @param scrollX Current X scroll value in pixels before applying deltaX 在应用 deltaX 之前的当前 scrollX 值
* @param scrollY Current Y scroll value in pixels before applying deltaY
* @param scrollRangeX Maximum content scroll range along the X axis scrollX 的最大滚动范围
* @param scrollRangeY Maximum content scroll range along the Y axis
* @param maxOverScrollX Number of pixels to overscroll by in either direction scrollX 的最大超出值
* along the X axis.
* @param maxOverScrollY Number of pixels to overscroll by in either direction
* along the Y axis.
* @param isTouchEvent true if this scroll operation is the result of a touch event. 是否正在触摸
* @return true if scrolling was clamped to an over-scroll boundary along either
* axis, false otherwise.
*/
@SuppressWarnings({"UnusedParameters"})
protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
final int overScrollMode = mOverScrollMode;
final boolean canScrollHorizontal =
computeHorizontalScrollRange() > computeHorizontalScrollExtent();
final boolean canScrollVertical =
computeVerticalScrollRange() > computeVerticalScrollExtent();
final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS ||
(overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS ||
(overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
int newScrollX = scrollX + deltaX;
if (!overScrollHorizontal) {
maxOverScrollX = 0;
}
int newScrollY = scrollY + deltaY;
if (!overScrollVertical) {
maxOverScrollY = 0;
}
// Clamp values if at the limits and record
final int left = -maxOverScrollX;
final int right = maxOverScrollX + scrollRangeX;
final int top = -maxOverScrollY;
final int bottom = maxOverScrollY + scrollRangeY;
boolean clampedX = false;
if (newScrollX > right) {
newScrollX = right;
clampedX = true;
} else if (newScrollX < left) {
newScrollX = left;
clampedX = true;
}
boolean clampedY = false;
if (newScrollY > bottom) {
newScrollY = bottom;
clampedY = true;
} else if (newScrollY < top) {
newScrollY = top;
clampedY = true;
}
onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
return clampedX || clampedY;
}