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

作者:正义啊 时间:2022-01-20 22:49:35 

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

Android 使用 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 实现平滑滚动功能的示例代码

来源:https://blog.csdn.net/sjdjdjdjahd/article/details/107257057

标签:android,Scroller,平滑滚动
0
投稿

猜你喜欢

  • Java 实现微信和支付宝支付功能

    2023-03-08 23:18:04
  • java编程创建型设计模式单例模式的七种示例

    2023-06-21 08:47:39
  • Java面试题之HashMap 的 hash 方法原理是什么

    2022-09-11 20:20:54
  • synchronized背后的monitor锁实现详解

    2023-07-31 08:14:10
  • 详解Java面向对象中的继承

    2023-10-06 13:26:14
  • springboot注册bean的三种方法

    2023-11-22 21:57:12
  • Java 集合中的类关于线程安全

    2023-03-13 12:53:22
  • Java synchronized关键_动力节点Java学院整理

    2023-11-10 11:08:53
  • spring+srpingmvc+hibernate实现动态ztree生成树状图效果

    2022-07-21 21:41:59
  • 详解Java高级特性之反射

    2021-06-09 14:01:06
  • 深入解析Java中的Classloader的运行机制

    2023-07-16 11:47:59
  • MySQL+SSM+Ajax上传图片问题

    2023-01-26 04:22:52
  • 深入了解Hadoop如何实现序列化

    2023-10-13 10:33:43
  • 详解Maven安装教程及是否安装成功

    2021-07-14 00:00:21
  • Java查看线程运行状态的方法详解

    2023-05-23 12:21:10
  • Java Integer如何获取第一位和最后一位,并截取

    2022-12-27 08:27:13
  • Java使用BigDecimal精确运算浮点数

    2023-08-11 09:47:11
  • Java如何实现自定义异常类

    2023-06-21 23:44:01
  • java和c/c++ 数据类型长度的比较

    2021-06-18 00:07:45
  • Java线程的start方法回调run方法的操作技巧

    2023-11-11 06:02:00
  • asp之家 软件编程 m.aspxhome.com