Android仿qq回彈阻尼ScrollView

仿qq寫一個可以來回彈的ScrollView.

只需要重寫ScrollView:

public class MyScrollView extends ScrollView {
    // y方向上當前觸摸點的前一次記錄位置
    private int previousY = 0;
    // y方向上的觸摸點的起始記錄位置
    private int startY = 0;
    // y方向上的觸摸點當前記錄位置
    private int currentY = 0;
    // y方向上兩次移動間移動的相對距離
    private int deltaY = 0;
    // 第一個子視圖
    private View childView;
    // 用於記錄childView的初始位置
    private Rect topRect = new Rect();
    public MyScrollView(Context context) {
        super(context);
    }

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @SuppressLint("MissingSuperCall")
    @Override
    protected void onFinishInflate() {
        if (getChildCount() > 0) {
            childView = getChildAt(0);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (null == childView) {
            return super.dispatchTouchEvent(event);
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startY = (int) event.getY();
                previousY = startY;
                break;
            case MotionEvent.ACTION_MOVE:
                currentY = (int) event.getY();
                deltaY = previousY - currentY;
                previousY = currentY;
                if (0 == getScrollY()
                        || childView.getMeasuredHeight() - getHeight() <= getScrollY()) {
                    // 記錄childView的初始位置
                    if (topRect.isEmpty()) {
                        topRect.set(childView.getLeft(), childView.getTop(),
                                childView.getRight(), childView.getBottom());
                    }
                    // 更新childView的位置
                    childView.layout(childView.getLeft(), childView.getTop()
                                    - deltaY / 3, childView.getRight(),
                            childView.getBottom() - deltaY / 3);
                }
                break;
            case MotionEvent.ACTION_UP:
                if (!topRect.isEmpty()) {
                    upDownMoveAnimation();
                    // 子控件回到初始位置
                    childView.layout(topRect.left, topRect.top, topRect.right,
                            topRect.bottom);
                }
                startY = 0;
                currentY = 0;
                topRect.setEmpty();
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    // 初始化上下回彈的動畫效果
    private void upDownMoveAnimation() {
        TranslateAnimation animation = new TranslateAnimation(0.0f, 0.0f,
                childView.getTop(), topRect.top);
        animation.setDuration(100);
        animation.setInterpolator(new AccelerateInterpolator());
        childView.setAnimation(animation);
    }
}

然後想在哪用直接佈局就行了。這種重寫方法是不會和子控件的點擊事件起衝突的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章