Android 使用 Scroller 实现平滑滚动功能的示例代码
作者:正义啊 时间:2022-01-20 22:49:35
记录使用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()
方法中调用Scroller
的computeScrollOffset()
计算当前时间动画应该移动的位置,返回值是动画是否在执行。
通过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当前值。并移动位置。效果如下:
来源: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