First look at View#scrollTo(int x,int y)
, take x
as an example. When the incoming x>0
, View
content scrolls, and scroll along the negative direction of x
why???
ScrollTo scrolls the content of the View. If you want to scroll a view through scrollTo, you should call the scrollTo method of its parent View. Why is the content of the view scrolled? I will talk about this later.
Look at the source code.
First look View#scrollTo(int x,int y)
source code of 0612f98ac50e15. x
directly assigned to mScrollX
.
#View.java
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
For a View, when the scrollTo method of its parent view is called to scroll from point A to point B, and then to point C, the mScrollX of the view is the total ( A->C ) scroll distance instead of Phase ( A->B or B->C ) rolling distance
Look at View# invalidate(int l, int t, int r, int b)
. x
passed in by the previous method. l-scrollX
is the left side of the drawing area, and r-scrollX
is the right side of the drawing area. x>0
drawing area of 0612f98ac50efc will move to the left; the x<0
will move to the right.
#View.java
public void invalidate(int l, int t, int r, int b) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);
}
From the above, we can see that the View#scrollTo
call will trigger View#invalidate
, which causes the drawing area to change, that is, we see View
displays the content has changed.
For a View
position is changed, should be changed View
the mLeft
and mTop
two attribute values. Obviously, View#scrollTo
did not change the values of these two attributes. Therefore, View#scrollTo
will not cause View
to scroll, but will scroll the content View
How to customize a scrollable View?
Inherited from ViewGroup. Of course, if necessary, you need to rewrite onInterceptTouchEvent, intercept the MotionEvent.ACTION_MOVE event, rewrite onTouchEvent, and then call scrollTo or scrollBy to achieve scrolling.
private float lastDownX,lastDownY;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastDownX = event.getX();
lastDownY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (满足一定条件){
//请求父View不要拦截
getParent().requestDisallowInterceptTouchEvent(true);
//返回true。将ACTION_MOVE事件交给自身处理。
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastDownX = event.getX();
lastDownY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
float diffX = moveX - lastDownX;
float diffY = moveY - lastDownY;
/**
* 从左向右滑动,diffX<0;getScrollX()>0;
* scrollTo的参数x>0
* x = getScrollX() - diffX
*
* 从右向左滑动,diffX>0,getScrollX()<0;
* scrollTo的参数x<0
* x = getScrollX() - diffX
*
* 参数y同理
*/
scrollTo((int)(getScrollX()-diffX),(int)(getScrollY()-diffY));
//scrollBy(-(int)diffX,-(int)diffY);
return true;
case MotionEvent.ACTION_UP:
lastDownX = 0;
lastDownY = 0;
break;
}
return super.onTouchEvent(event);
}
When scrolling, the problem of boundary constraints should also be considered. Take the sliding deletion of the QQ message list as an example.
Swiping from left to right constrains the left boundary, and sliding from right to left constrains the right boundary.
Do boundary constraints in the ACTION_MOVE event. Use the code above.
//最大滑动距离,根据自己的业务情况来确定这个值。以QQ侧滑删除为例,这个值是删除按钮的宽度。
int maxScrollDistance;
case MotionEvent.ACTION_MOVE:
//某一时刻要滑动到的位置,这个位置到达边界时,要做约束。
float targetX = getScrollX() - (event.x - lastDownX);
//从左向右滑动,当滑动到左边界时,getScrollX() = 0;继续滑动,getScrollX()<0;对这个情况要做个约束,避免滑动越过左边界。
if (targetX<0) targetX = 0;
//从右向左滑动,当滑动到右边界时,getScrollX() = maxScrollDistance;继续滑动,getScrollX()>maxScrollDistance;对这个情况要做个约束,避免滑动越过右边界。
if (targetX>maxScrollDistance) targetX = maxScrollDistance;
scrollTo(targetX,0);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。