Scroller 是一个实现 View 平滑滚动的辅助类,在使用它之前,需要通过 startScroll 来设置滚动参数,即起始点坐标和(x , y)轴上要滚动的距离。
相关方法有:
mScroller.getCurrX() //获取mScroller当前水平滚动的位置
mScroller.getCurrY() //获取mScroller当前竖直滚动的位置
mScroller.getFinalX() //获取mScroller最终停止的水平位置
mScroller.getFinalY() //获取mScroller最终停止的竖直位置
mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置
mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置
//滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量(注意:是偏移量,不是最终坐标), duration为完成滚动的时间
mScroller.startScroll(int startX, int startY, int dx, int dy) //内部默认执行时间250ms
mScroller.startScroll(int startX, int startY, int dx, int dy, int duration)
mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。
从上面 startScroll 方法可以看到,Scroller 它自己封装了滚动时间,滚动的目标位置,以及在每个时间内View应该滚动到的(x , y ) 轴坐标点。这样就可以在有效的滚动周期内通过 Scroller 的 getCurrX() 和 getCurrY() 来获取当前时刻View应该滚动的位置,然后通过调用 View 的 scrollTo 或者 ScrollBy 方法进行滚动。
getCurrX() 和getCurrY()可能有点不太好理解,从startScroll方法调用开始,它会在设定的滚动时间内(默认的250ms)持续滚动到目标位置,在它没有抵达目标位置之前,它是一直在滚动的,getCurrX() 和 getCurrY() 方法获取的是调用时 Scroller 所滚动的位置。
我们只需要重写 View 类的 computeScroll 方法,该方法是在 View 绘制时被调用,在里面调用 Scroller 的 computeScrollOffset 来判断滚动是否完成,没完成则继续通过 scrollTo 或者 ScrollBy 进行滚动视图,然后调用目标 View 的 postInvalidate() 或者 invalidate() 进行 View 重绘,View 的重绘又导致 computeScroll 方法被调用。所以,这里就形成了一个递归,结束标识就是当 View 滚动到 Scroller 所设定的目标位置(Scroller.computeScrollOffset() == true)。
这里是写的一个实例:
public class ScrollLayout extends LinearLayout {
Scroller scroller;
public ScrollLayout(Context context) {
super(context);
scroller = new Scroller(context);
}
// 该方法会在View重绘的时候调用
@Override
public void computeScroll() {
// 判断scroller是否已滚动到指定位置
if (scroller.computeScrollOffset()) {
// 使View滚动到目前的位置
this.scrollTo(scroller.getCurrX(), scroller.getCurrY());
// 重绘View,从而导致 computeScroll()被调用,开启递归模式,直到scroller.computeScrollOffset()返回false。
postInvalidate();
}
}
public void scrollTo(int y) {
scroller.startScroll(getScrollX(), getScrollY(), 0, y);
// 重绘View
invalidate();
}
}
调用该视图代码:
scrollLayout = new ScrollLayout(this);
TextView textView = new TextView(this);
textView.setText("测试");
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300));
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scrollLayout.scrollTo(-150);
}
});
scrollLayout.addView(textView);
setContentView(scrollLayout);
效果图:
看到这里又想到了一个问题,就是这个偏移的是子View,还是父View呢?
我们给 ScrollLayout 和 TextView 分别设置一个背景色,
textView.setBackgroundColor(Color.BLUE);
scrollLayout.setBackgroundColor(Color.GRAY);
再来看一下效果图:
这样就确定了Scroller控制的是childView。
好了,Scroller 的基本使用原理就是这些。时间不早了,洗洗睡吧。