关于Android滑动scroll,弹性滑动以及VelocityTracker

一 VelocityTracker

速度追踪,手指在滑动中的速度,包括水平和竖直方向。

计算公式: 速度 =(终点位置-起点位置)/ 时间段

使用:

VelocityTracker velocityTracker= VelocityTracker.obtain() ;
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();

最后需要重置和回收

velocityTracker.clear();
velocityTracker.recycle();

 

二 关于scroll

 

 public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }

    /**
     * Move the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the amount of pixels to scroll by horizontally
     * @param y the amount of pixels to scroll by vertically
     */
    public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }
  • scrollTo 绝对滑动(以画布为参照)
  • scrollBy 相对滑动 (相对于自己上一次的位置)

mScrollX 通过getScrollX可获得 是 View左边缘和内容左边缘水平距离,单位像素

mScrollY 通过getScrollY可获得 是 View上边缘和内容上边缘竖直距离,单位像素

注意滑动的是View的内容,本身位置不变。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/linear"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="#FFF68F"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#FFC1C1"
            android:orientation="vertical">

            <Button
                android:id="@+id/btn_scollto"
                android:layout_width="wrap_content"
                android:layout_height="45dp"
                android:text="使用ScrollTo" />

            <Button
                android:id="@+id/btn_scollby"
                android:layout_width="wrap_content"
                android:layout_height="45dp"
                android:text="使用ScrollBy" />
        </LinearLayout>


    </LinearLayout>


</LinearLayout>

   LinearLayout linear = findViewById(R.id.linear);

        findViewById(R.id.btn_scollto).setOnClickListener(v -> {
            Log.i("scroll", "scrollTo移动前: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
            linear.scrollTo(-50,-50);
            Log.i("scroll", "scrollTo移动后: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
        });

        findViewById(R.id.btn_scollby).setOnClickListener(v -> {
            Log.i("scroll", "scrollBy移动前: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
            linear.scrollBy(-50,-50);
            Log.i("scrolls", "scrollBy移动后: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
        });

通过上述例子可以看到移动的是View的内容,本身位置没有改变。注意观察其scrollTo和scrollBy的区别。以及移动位置的正负值。

 

除了scroll方式以为还有动画和改变View的布局参数可以产生滑动的效果。三种方式的区别:

scroll 滑动View的内容,不能滑动View本身

动画:滑动后点击事件在新的位置无法点击,本身位置没有变。适用于没有交互,复杂动画效果。

三 弹性滑动

原理 将一次大的滑动分为若干次小的滑动并在一个时间段内完成

1.scroller的弹性滑动

public class MyScroller extends LinearLayout {

    private final static String TAG ="MyScroller";
    Scroller mScroller;
    public MyScroller(Context context) {
        super(context);
        mScroller = new Scroller(context);
    }

    public MyScroller(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
    }

    public MyScroller(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScroller = new Scroller(context);
    }


    public void smoothScrollerTo(int x){
        int scrollX = getScrollX();
        int deltaX = x -scrollX;
        //1000ms内完成滑动
        mScroller.startScroll(scrollX,0,deltaX,0,1000);
        invalidate();
    }
    @Override
    public void computeScroll() {
//        super.computeScroll();
        if(mScroller.computeScrollOffset()){
            scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            postInvalidate();
        }
    }
}
  MyScroller myScroller = findViewById(R.id.myScroller);
        findViewById(R.id.btn_scollto).setOnClickListener(v -> {
            myScroller.smoothScrollerTo(-400);
        });
<?xml version="1.0" encoding="utf-8"?>
<com.example.scroll.MyScroller xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/myScroller"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_scollto"
        android:layout_width="wrap_content"
        android:layout_height="45dp"
        android:text="scroller弹性滑动" />



</com.example.scroll.MyScroller>

效果:

 

如果把smoothScrollerTo里面的invalidate注释掉,是否还能滑动呢?不能

由于invalidate方法会导致View重绘,会调用draw方法,在draw里面会调用computeScroll方法。

2.利用动画实现弹性滑动

原理:在动画每一帧到来时获取动画完成的比例,根据这个比例计算当前View要滑动的距离。

  LinearLayout myScroller = findViewById(R.id.linear);
        findViewById(R.id.btn_scollto).setOnClickListener(v -> {
        startAnimaScroll(myScroller);
        });

    

private void startAnimaScroll(View view){

    int startX = 0;
    int deltaX = -500;
    ValueAnimator animator = ValueAnimator.ofInt(0, 1).setDuration(1000);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float fraction = animator.getAnimatedFraction();
            view.scrollTo(
                    startX + (int) (deltaX * fraction), 0
            );
        }
    });
    animator.start();

}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/linear"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_scollto"
        android:layout_width="wrap_content"
        android:layout_height="45dp"
        android:text="scroller弹性滑动" />

</LinearLayout>

3.使用延时策略

通过发送一系列消息达到渐进式效果。

比如在Handler里面连续不断的发消息,然后接收到消息按比例滑动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值