ScrollPickerView

96 阅读1分钟

基本原理:每次滑动调用invalidate(),重新绘制item

onTouchEvent

滑动组件 先从onTouchEvent 入手

3,2,1上代码


if (mDisallowTouch) { // 不允许触摸
    return true;
}

switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        if (onPickerViewListener != null) {
            onPickerViewListener.onTouchDown(ScrollPickerView.this);
        }
        onTouchDown();
        break;
    case MotionEvent.ACTION_UP:
        if (onPickerViewListener != null) {
            onPickerViewListener.onTouchUp(ScrollPickerView.this);
        }
        onTouchUp();
        break;
}


//down 点击会被onTouchEvent消耗
if (mGestureDetector.onTouchEvent消耗(event)) {
    return true;
}

//处理move up事件
switch (event.getActionMasked()) {

    case MotionEvent.ACTION_MOVE:
    
    // 计算down---up之间移动的距离
    // 区分方向是水平还是竖直
    //start
        if (mIsHorizontal) {
            if (Math.abs(event.getX() - mLastMoveX) < 0.1f) {
                return true;
            }
           
            mMoveLength += event.getX() - mLastMoveX;
        } else {
            if (Math.abs(event.getY() - mLastMoveY) < 0.1f) {
                return true;
            }
            mMoveLength += event.getY() - mLastMoveY;
        }
        mLastMoveY = event.getY();
        mLastMoveX = event.getX();
        //end
        //处理滑过的情况,重新移回中间
        checkCirculation();
        //重绘,使item位置更新
        invalidate();
        break;
    case MotionEvent.ACTION_UP:
        mLastMoveY = event.getY();
        mLastMoveX = event.getX();
        moveToCenter();
        onTouchUp();
        break;
}

return true;

解析

设置禁止触摸

设置mDisallowTouch后无法响应事件,但是事件仍然被消耗了。 可以通过这个方法设置

public void setDisallowTouch(boolean disallowTouch) {
    mDisallowTouch = disallowTouch;
}

onTouchDown onTouchUp

onTouchDown();onTouchUp();是两个空方法,可以通过继承在该方法里面实现按下和抬起的处理逻辑。除此之外还可以通过setOnPickerViewListener这个方法来设置listener,同样也可以达到onTouchDown();onTouchUp();的效果。

mGestureDetector消耗了Down事件和单击事件
private class FlingOnGestureListener extends GestureDetector.SimpleOnGestureListener {

    private boolean mIsScrollingLastTime = false;

    @Override
    public boolean onDown(MotionEvent e) {
        ..
        .....防止拦截触摸事件......
        ..
        
        //isScrolling()判断是否在滑动
        mIsScrollingLastTime = isScrolling(); // 记录是否从滚动状态终止
        // 点击时取消所有滚动效果
        cancelScroll();
        mLastMoveY = e.getY();
        mLastMoveX = e.getX();
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, final float velocityY) {
        // 惯性滑动
        .........
        return true;
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        if (isTouchFromOut) {
            isTouchFromOut = false;
            return true;
        }
        mLastMoveY = e.getY();
        mLastMoveX = e.getX();


        float lastMove = 0;
        if (isHorizontal()) {
            mCenterPoint = mCenterX;
            lastMove = mLastMoveX;
        } else {
            mCenterPoint = mCenterY;
            lastMove = mLastMoveY;
        }
        
        if (mCanTap && !isScrolling() && !mIsScrollingLastTime) {
        //如果单击的位置在当前选择的item则执行onClick事件
            if (lastMove >= mCenterPoint && lastMove <= mCenterPoint + mItemSize) {
                performClick();
            } else if (lastMove < mCenterPoint) {
                
                ...............
                //调用autoScrollTo 移动指定距离,这个距离正好会使指定的item移到中间
                ...............
               
            }
        } else {
        //若该view正在滑动,则当前点击会使滑动停下,并移动item到中间
            moveToCenter();
        }
        return true;
    }
}

每次movecenter时都会终止上一次的scroll过程

设置是否循环滚动

setIsCirculation(boolean

获取当前选择的位置 从0开始

getSelectedPosition

设置选中item的背景

setCenterItemBackground
滚动到指定位置
autoScrollToPosition

设置选择item的监听

setOnPickerViewListener

可以监听这些事件

public interface OnPickerViewListener {
    void onSelected(ScrollPickerView scrollPickerView, int position);

    void onTouchDown(ScrollPickerView scrollPickerView);

    void onTouchUp(ScrollPickerView scrollPickerView);
}

设置item数据

setData(List<? extends T> data)

设置当前相对位置

centerPosition是当前可见数量的位置,比如说当前可见3个item,总的item的数量是10个, centerPosition = 1,是可见item的第二个item,是相对于可见item来说的.

而int mSelected表示绝对item位置。

setCenterPosition(int centerPosition)