使用scrollTo()、scrollBy()可以实现移动View中的内容的效果。
他的本质其实是给View自身设置一个偏移(scrollX, scrollY),然后触发重绘。在重绘的时候,父ViewGroup会先获取到此View的偏移,然后将此偏移取反(-scrollX, -scrollY),应用到此View的画布上,再交给此View进行绘制。
以android-2.3.3_r1源码为例
所以
1. 他并没有改变View的位置属性,left\top\right\bottom值不变!
2. scrollTo()、scrollBy()参数的坐标系跟画布坐标系是相反的,比如说scrollTo(100, 100)是先将画布向左上移动 translate(-100,-100)。
3. 效果是移动画布中的内容,但画布背景是在变换之前绘制的,所以背景不会移动。
如下TextView的背景是白色,调用scrollTo()/scrollBy()以后仅文本发生了移动
4. 可以使用getScrollX()、getScrollY()获取当前内容滑动的偏移,当然这个值也是跟画布坐标系相反的
5. 如果需要监听滑动改变,可以重写onScrollChanged()函数。每次调用scrollTo()/scrollBy()的时候,都会先调用onScrollChanged()函数。
从API23开始也提供了setOnScrollChangeListener()方法
6. 这个效果是一次完成的,如果需要平滑效果需要结合Scroller/OverScroller。
如下TextView
public class
MyTextView
extends
TextView {
public
MyTextView(Context context) {
super(context);
}
public
MyTextView(Context context,
AttributeSet attrs) {
super(context,
attrs);
}
public
MyTextView(Context context,
AttributeSet attrs, int
defStyleAttr) {
super(context,
attrs,
defStyleAttr);
}
@Override
protected void
onMeasure(int
widthMeasureSpec, int
heightMeasureSpec) {
Log.e("shadowfaxghh",
"onMeasure()");
super.onMeasure(widthMeasureSpec,
heightMeasureSpec);
}
@Override
protected void
onLayout(boolean
changed, int
left, int
top, int
right, int
bottom) {
Log.e("shadowfaxghh",
"onLayout()");
super.onLayout(changed,
left,
top,
right,
bottom);
}
@Override
protected void
onDraw(Canvas canvas) {
Log.e("shadowfaxghh",
"onDraw()");
Matrix matrix =canvas.getMatrix();
printMatrix(matrix);
super.onDraw(canvas);
}
public void
printMatrix(Matrix matrix){
float[] values=new
float[9];
matrix.getValues(values);
for(int
i=0;
i<3;
i++){
StringBuffer buffer=new
StringBuffer();
for(int
j=0;
j<3;
j++){
buffer.append(values[i*3+j]+"
");
}
Log.e("shadowfaxghh",
buffer.toString());
}
}
@Override
protected void
onScrollChanged(int
horiz, int
vert, int
oldHoriz, int
oldVert) {
super.onScrollChanged(horiz,
vert,
oldHoriz,
oldVert);
Log.e("shadowfaxghh",
"scrollX="+horiz+"
scrollY="+vert);
}
}
当调用scrollTo(100,0)时日志输出如下
更新
在后面写Scroller的时候,在高版本上某些情况下,在computeScroll()中,调用scrollTo()以后并没有调用invalidate(),暂时不明白原因,只好自己加上invalidate()调用。