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当前值。并移动位置。效果如下:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Scroller 是一个用于实现平滑滚动效果的工具类。它可以用于在 Android 应用中实现滑动的动画效果,如平滑滚动到指定位置或者平滑滚动到顶部。 使用 Android Scroller 需要以下步骤: 1. 创建一个 Scroller 实例:使用 `new Scroller(context)` 创建一个 Scroller 对象。 2. 在 View 的 `computeScroll()` 方法中更新滚动位置:在需要实现滑动效果的 View 类里重写 `computeScroll()` 方法,然后在该方法中调用 `scroller.computeScrollOffset()` 获取当前的滚动位置,并根据需要更新 View 的位置。 3. 处理触摸事件:在触摸事件的回调方法中调用 Scroller 的 `startScroll()` 方法来启动滚动效果。可以根据触摸事件的不同情况调用不同的方法,如 `startScroll(int startX, int startY, int dx, int dy)` 或者 `startScroll(int startX, int startY, int dx, int dy, int duration)` 来指定滚动的起点、偏移量和持续时间。 4. 在 View 的 `invalidate()` 方法中不断重绘:在 `computeScroll()` 方法中更新了 View 的位置后,需要在 View 的 `invalidate()` 方法中调用,以便触发 View 的重新绘制。 需要注意的是,尽管 Android Scroller 提供了平滑滚动的功能,但它仅仅是一个工具类,实际的滚动效果实现还需要结合其他相关的 API 和组件来完成,如使用 `ViewGroup.LayoutParams` 来设置 View 的位置和大小,或者使用 `ViewPropertyAnimator` 实现更复杂的动画效果。 希望这个回答对你有帮助!如果有更多问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值