彈性

package com.hou.mask;

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.TranslateAnimation;
import android.widget.ScrollView;

/**
 *
 */
public class ReboundScrollView extends ScrollView {
    private static final String TAG = "MaskScrollView";
    private static final int INVALID_POINTER = -1;
    private static final int FACTOR = 2;//因子,阻尼係數
    private View childView;
    private int mActivePointerId;
    private float mLastMotionY;
    private float lastDeltaY;
    private Rect normal = new Rect();
    private int mTouchSlop;

    private static final int ALL = 0;
    private static final int NONE = 1;
    private static final int TOP = 2;
    private static final int BOTTOM = 3;
    private int elasticity;

    public ReboundScrollView(Context context) {
        this(context, null);
    }

    public ReboundScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ReboundScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();

        elasticity = ALL;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        childView = getChildAt(0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        if (action == MotionEvent.ACTION_MOVE && Math.abs(ev.getY() - mLastMotionY) > mTouchSlop) {
            return true;
        } else if (action == MotionEvent.ACTION_DOWN) {
            if (getChildCount() == 0) {
                return false;
            }
            mLastMotionY = ev.getY();
            mActivePointerId = ev.getPointerId(0);
            lastDeltaY = 0;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int actionMasked = MotionEventCompat.getActionMasked(ev);
        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                if (getChildCount() == 0) {
                    return false;
                }
                mLastMotionY = ev.getY();
                mActivePointerId = ev.getPointerId(0);
                lastDeltaY = 0;
                break;
            case MotionEvent.ACTION_MOVE:
                int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                if (activePointerIndex == -1) {
                    Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
                    break;
                }
                final float y = ev.getY(activePointerIndex);
                float deltaY = mLastMotionY - y;
                //<0只是上邊有彈性,>0只是下邊有彈性,不加上下都有
                if (elasticity == ALL || elasticity == TOP && deltaY < 0 || elasticity == BOTTOM && deltaY > 0) {
                    if (normal.isEmpty()) {
                        //記錄原始位置,用來恢復
                        normal.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());
                    }
                    int offsetY = (int) ((lastDeltaY - deltaY) / FACTOR);
                    childView.layout(childView.getLeft(), childView.getTop() + offsetY,
                            childView.getRight(), childView.getBottom() + offsetY);
                    lastDeltaY = deltaY;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                animateToBack();
                mActivePointerId = INVALID_POINTER;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                int index = ev.getActionIndex();
                mLastMotionY = ev.getY(index);
                mActivePointerId = ev.getPointerId(index);
                lastDeltaY = 0;
                break;
            case MotionEvent.ACTION_POINTER_UP:
                onSecondaryPointerUp(ev);
                mLastMotionY = ev.getY(ev.findPointerIndex(mActivePointerId));
                final float upY = ev.getY(ev.findPointerIndex(mActivePointerId));
                lastDeltaY = mLastMotionY - upY;
                break;
        }
        return super.onTouchEvent(ev);
    }

    private void animateToBack() {
        TranslateAnimation animation = new TranslateAnimation(0, 0, childView.getTop() - getPaddingTop(), normal.top - getPaddingTop());
        animation.setDuration(200);
        childView.startAnimation(animation);
        childView.offsetTopAndBottom(normal.top - childView.getTop());
        normal.setEmpty();
    }

    private void onSecondaryPointerUp(MotionEvent ev) {
        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
                MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        final int pointerId = ev.getPointerId(pointerIndex);
        if (pointerId == mActivePointerId) {
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastMotionY = ev.getY(newPointerIndex);
            mActivePointerId = ev.getPointerId(newPointerIndex);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章