首页 > 编程语言 > Android 使用 Scroller 实现平滑滚动功能的示例代码
2020
10-08

Android 使用 Scroller 实现平滑滚动功能的示例代码

记录使用Scroller实现平滑滚动,效果图如下:

在这里插入图片描述

一、自定义View中实现View的平滑滚动

public class ScrollerView extends View {

 private Scroller mScroller;
 private Paint mPaint;
 /**
  * 屏幕拖动最小像素
  */
 private int mTouchSlop;
 /**
  * View宽度
  */
 private int width;
 /**
  * View高度
  */
 private int height;
 /**
  * MotionEvent.getX()
  */
 private int mEventX;
 /**
  * MotionEvent.getY()
  */
 private int mEventY;
 private Bitmap mBitmap;
 /**
  * View到屏幕左边距离
  */
 private int mStartX;
 /**
  * View到屏幕顶部距离
  */
 private int mStartY;
 /**
  * View默认大小
  */
 private static int DEFAULT_SIZE = 200;

 public ScrollerView(Context context) {
  this(context, null);
 }

 public ScrollerView(Context context, @Nullable AttributeSet attrs) {
  super(context, attrs);
  mPaint = new Paint();
  mScroller = new Scroller(context);

  ViewConfiguration configuration = ViewConfiguration.get(context);
  mTouchSlop = ViewConfigurationCompat.getScaledHoverSlop(configuration);
  mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  if (widthMode == MeasureSpec.EXACTLY) {
   width = MeasureSpec.getSize(widthMeasureSpec);
  } else {
   if (heightMode == MeasureSpec.EXACTLY) {
    width = MeasureSpec.getSize(heightMeasureSpec);
   } else {
    width = DEFAULT_SIZE;
   }
  }

  if (heightMode == MeasureSpec.EXACTLY) {
   height = MeasureSpec.getSize(heightMeasureSpec);
  } else {
   height = width;
  }
  setMeasuredDimension(width, height);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  if (null != mBitmap) {
   Rect src = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
   Rect dst = new Rect(0, 0, width, height);
   canvas.drawBitmap(mBitmap, src, dst, mPaint);
  } else {
   Log.e("zzy", "Bitmap is null");
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  int action = event.getAction();
  switch (action) {
   case MotionEvent.ACTION_DOWN:
    mEventX = (int) event.getX();
    mEventY = (int) event.getY();
    break;
   case MotionEvent.ACTION_MOVE:
    mStartX = (int) event.getRawX() - mEventX;
    mStartY = (int) event.getRawY() - mEventY;
    layout(mStartX,mStartY,mStartX+width,mStartY+height);
    break;
   case MotionEvent.ACTION_UP:
    startScroller();
    break;
  }
  return true;
 }

 @Override
 public void computeScroll() {
  if (mScroller.computeScrollOffset()){
   int l = mScroller.getCurrX();
   layout(l,mStartY,l+width,mStartY+height);
   invalidate();
  }
 }

 /**
  * 开始Scroller动画
  */
 private void startScroller(){
  mScroller.forceFinished(true);
  mScroller.startScroll(mStartX, mStartY,-mStartX,0);
  int screenWidth = getScreenWidth();
  // Scroller动画默认250ms,超过屏幕一半时设置为500ms
  if (mStartX > screenWidth / 2){
   mScroller.extendDuration(500);
  }
  invalidate();
 }

 private int getScreenWidth(){
  return getResources().getDisplayMetrics().widthPixels;
 }
}

Scroller其实是个辅助类,本身并不能完成动画的执行。而是帮我们计算随着时间的流逝,动画应该执行的位置值,我们需要获得当前时间的位置,然后调用View位置移动方法,将View移动到该位置,完成动画。

所以,在自定义View中。我们需要调用invalidate()触发View的重绘,并覆写重绘会执行的方法computeScroll()

computeScroll()方法中调用ScrollercomputeScrollOffset()计算当前时间动画应该移动的位置,返回值是动画是否在执行。

通过mScroller.getCurrX()mScroller.getCurrY()获得当前时间的位置。手动调用View位置移动的方法将View的位置移动到当前时间的位置,实现View的滚动。

然后再次调用invalidate()触发刷新。直到computeScrollOffset()返回false,动画执行完成,滚动完成。

二、直接使用Scroller实现View的平滑滚动

我们知道,Scroller会帮我们计算当前时间,插值器返回的值。

而如果直接使用Scroller实现平滑滚动的话,也需要借助带时间的监听器。

这里借助ValueAnimator来实现Scroller平滑滚动

 private Scroller mScroller;
 private ImageView mImage;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mImage = findViewById(R.id.image);

  mScroller =new Scroller(this);
 }

 public void btnStart(View view){
  start();
 }

 private void start(){
  mScroller.forceFinished(false);
  mScroller.extendDuration(500);
  mScroller.startScroll(0,0,400,400);
  ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
  valueAnimator.setDuration(500);
  valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    if (mScroller.computeScrollOffset()){
     ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mImage.getLayoutParams();
     params.leftMargin = mScroller.getCurrX();
     params.topMargin = mScroller.getCurrY();
     mImage.setLayoutParams(params);
    }
   }
  });
  valueAnimator.start();
 }

在ValueAnimator的addUpdateListener中刷新Scroller当前值。并移动位置。效果如下:

在这里插入图片描述

到此这篇关于Android 使用 Scroller 实现平滑滚动的文章就介绍到这了,更多相关android Scroller 平滑滚动内容请搜索自学编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持自学编程网!

编程技巧