VelocityTrackerView VelocityTracker 与 Scroller 实现View的滑动

VelocityTrackerView 是用 VelocityTracker 与 Scroller 实现View的滑动,继承自ViewGroup,对VelocityTracker,Scroller的学习做个笔记。

VelocityTrackerView.java

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class VelocityTrackerView extends ViewGroup {

    public static final String TAG = "VelocityTrackerView";

    public ArrayList<Position> viewPoints;

    private VelocityTracker mVelocityTracker;
    private int mMaximumVelocity;
    private int mMinimumVelocity;
    private Scroller mScroller;
    private int mPointerId; // 触点ID

    private void initOrResetVelocityTracker() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        } else {
            mVelocityTracker.clear();
        }
    }

    public VelocityTrackerView(Context context, AttributeSet attrs) {
        super(context, attrs);

        initScrollView();

        viewPoints = new ArrayList<Position>();
    }

    private void initVelocityTrackerIfNotExists() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
    }

    private void recycleVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    private void initScrollView() {
        mScroller = new Scroller(getContext());
        setFocusable(true);
        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
        setWillNotDraw(false);

        final ViewConfiguration configuration = ViewConfiguration
                .get(getContext());
        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
        viewPoints.clear();

        //水平排列
        for (int i = 0; i < getChildCount(); i++) {
            View v = getChildAt(i);
            if (i == 0) {
                Position p = new Position();
                p.view = v;
                p.x = 0;
                p.y = 0;
                viewPoints.add(p);
            } else {
                Position p = new Position();
                p.view = v;
                p.y = 0;
                p.x = viewPoints.get(i - 1).x
                        + viewPoints.get(i - 1).view.getWidth();
                viewPoints.add(p);
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.setVisibility(View.VISIBLE);
            Position p = viewPoints.get(i);
            child.layout(p.x, p.y, p.x + child.getMeasuredWidth(),
                    p.y + child.getMeasuredHeight());
            if (i % 2 == 1) {
                child.setBackgroundColor(Color.parseColor("#FF666633"));
            } else {
                child.setBackgroundColor(Color.parseColor("#FFaa1122"));
            }
        }
    }

    float mLastMotionX;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        initVelocityTrackerIfNotExists();
        mVelocityTracker.addMovement(event);

        final float x = event.getX();
        final float y = event.getY();

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mPointerId = event.getPointerId(0);
            initOrResetVelocityTracker();
            
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();  //禁止滑动
            }
            mLastMotionX = x;

        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            // 求伪瞬时速度
            mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            final int velocityX = (int) mVelocityTracker
                    .getXVelocity(mPointerId);
            if ((Math.abs(velocityX) > mMinimumVelocity) && getChildCount() > 0) {
                fling(-velocityX);
            }
            recycleVelocityTracker();
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {

            int deltaX = (int) (mLastMotionX - x);
            mLastMotionX = x;
            //随着手指滚动
            scrollBy(deltaX, 0);
        } else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
            recycleVelocityTracker();
        }
        return true;
    }

    /**
     *  滑动
     * @param velocityX
     */
    public void fling(int velocityX) {
        
        if (getChildCount() > 0) {
            //设置Scroller的滑动参数
            mScroller.fling(getScrollX(), getScrollY(), velocityX, 0, 0, 10000,
                    0, 0);
             //这里必须调用postInvalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
            postInvalidate();
        }
    }

    @Override
    public void computeScroll() {

         //先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {
            int scrollX = getScrollX();
            int scrollY = getScrollY();
            int oldX = scrollX;
            int oldY = scrollY;
            int x = mScroller.getCurrX();
            int y = mScroller.getCurrY();
            scrollX = x;
            scrollY = y;
            scrollY = scrollY + 10;
            //这里调用View的scrollTo()完成实际的滚动
            scrollTo(scrollX, scrollY);
            postInvalidate();  //这里必须调用postInvalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
        }
    }

    public class Position {
        int x;
        int y = 0;
        int width;
        View view;
    }
}

xml中使用:

    <com.example.cyclingimage.VelocityTrackerView
        android:id="@+id/velocityTrackerView1"
        android:layout_width="wrap_content"
        android:layout_height="400dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true" >
          <TextView
            android:layout_width="300dp"
            android:layout_height="400dp"
            android:text="1" />
        <TextView
            android:layout_width="300dp"
            android:layout_height="400dp"
            android:text="2" />
        <TextView
            android:layout_width="300dp"
            android:layout_height="400dp"
            android:text="3" />
        <TextView
            android:layout_width="300dp"
            android:layout_height="400dp"
            android:text="4" />
        <TextView
            android:layout_width="300dp"
            android:layout_height="400dp"
            android:text="5" />
         
    </com.example.cyclingimage.VelocityTrackerView>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值