首先先来实现一个Scroller滑动
1.新建一个View,给它画上一个红色的矩形,左定点坐标是(100,100),并且在构造函数中初始化Scroller
public class MyView extends View {
private Scroller scroller;
private Paint paint = new Paint();
public MyView(Context context) {
super(context);
scroller = new Scroller(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
scroller = new Scroller(context);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
scroller = new Scroller(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.RED);
canvas.drawRect(100, 100, 300, 300, paint);
}
2.重写view的computeScroll()方法,系统绘制view的时候会在draw()方法调用computeScroll()。
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()) {
//通过Scroller来获取当前的滚动值
scrollTo(scroller.getCurrX(), scroller.getCurrY());
//重绘,会重新调用computeScroll() 不断移动view
invalidate();
}
}
3.写一个方法开始移动view,里面调用startScroll()
方法
public void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int deltaX = destX - scrollX;
scroller.startScroll(scrollX, 0, -deltaX, 0, 10000);
invalidate();
}
4.在布局文件中引用,Activity加载,写一个按钮控制smoothScrollTo()方法
public void startScroller(View view) {
myView.smoothScrollTo(400, 100);
}
5.点击按钮后,效果图
分析源代码
1.构造函数,有三个构造方法,不过第一种用的最广,第二种,传入一个插值器,然后在第三种中判断了一下插值器是否为空,不为空则使用默认的ViscousFluidInterpolator插值器
public Scroller(Context context) {
this(context, null);
}
public Scroller(Context context, Interpolator interpolator) {
this(context, interpolator,
context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
}
public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
mFinished = true;
if (interpolator == null) {
//判断插值器是否为空
mInterpolator = new ViscousFluidInterpolator();
} else {
mInterpolator = interpolator;
}
mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
mFlywheel = flywheel;
mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
}
2.主要方法
- startScroll(),有4个参数的和5个参数的,4个参数本质上也是调用了5个参数的startScroll(),区别在4个参数的用了默认的duration。
startX
:开始滑动的起点x
startY
:开始滑动的起点y
dx
:滑动的距离x,使用时注意正负
dy
:滑动的距离y,使用时注意正负
public void startScroll(int startX, int startY, int dx, int dy) {
startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
}
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
startScroll()方法是用来保存传进来的各种参数的,没有用来具体开启滑动的逻辑,而我们要使View滑动,startScroll()要用到invalidate()来使view进行重绘,从而调用draw()方法,这样draw()方法里的就会call到View中的computeScroll()方法。View中的computeScroll()方法是空实现,我们需要重写它
3.重写computeScroll()方法
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()) {
//滚动的逻辑
scrollTo(scroller.getCurrX(), scroller.getCurrY());
//接着重绘
invalidate();
}
}
可以看到computeScroll()里用到了scrollTo()以滚动View,接着调用invalidate()
会重新call到View中的draw()方法,从而不断的调用computeScroll()方法,使view一点一点的滑动,从而实现了平滑滚动。
4.其中if判断框中的computeScrollOffset()
是用来获取当前位置的ScrollX和ScrollY的,如果返回true这说明滑动未结束
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
//动画持续时间
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
//如果当前的动画持续时间小于设置的滑动持续时间(其实就是当前view滚动还没完的意思)
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
//通过插值器计算该时间段移动的距离mCurrX ,mCurrX
final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
case FLING_MODE:
...//省略
}
else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}
5.总结整个过程就是
end