弹性scrollview

弹性scrollview 第一个子item是图片,随着下拉图片有弹性变化。

public class ReboundScrollView extends ScrollView {
    String TAG = "ReboundScrollView";
    /**
     * 区分点击or滑动
     */
    private int mScaledTouchSlop;
    private int TOP_Y = 0;
    /**
     * 阻力
     */
    private float damk = 0.5f;
    /**
     * 回弹延迟
     */
    private int resetDelay = 200;

    /**
     * ScrollView的子View (ScrollView只能有一个子View)
     */
    private View mInnerView;
    private View boundView;

    private float startY;
    private int originHeight;
    private Rect originRect = new Rect();
    private int boundId;

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

    public ReboundScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        readStyleAttributes(context, attrs, 0);
    }

    @Override
    protected void onFinishInflate() {
        if (getChildCount() == 0) {
            return;
        }
        mInnerView = getChildAt(0);
        if (boundId != 0) {
            View viewById = findViewById(boundId);
            setBoundView(viewById);
        }
    }

    protected void readStyleAttributes(Context context, AttributeSet attrs, int defStyle) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.bound, 0, defStyle);
        boundId = a.getResourceId(R.styleable.bound_bound_id, 0);
        a.recycle();
        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        Log.i(TAG, "" + mScaledTouchSlop);
    }

    public void setBoundView(View view) {
        refreshOriginHeight(view);
        boundView = view;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                startY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float currentY = ev.getY();
                float scrollY = currentY - startY;
                return Math.abs(scrollY) > mScaledTouchSlop;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (mInnerView != null) {
            computeMove(ev);
        }
        return super.onTouchEvent(ev);
    }

    private void computeMove(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_UP:
                doReset();
                break;
            case MotionEvent.ACTION_MOVE:
                doMove(event);
                break;
        }
    }

    private int computeDeltaY(MotionEvent event) {
        float currentY = event.getY();
        int deltaY = (int) ((startY - currentY) * damk);
        startY = currentY;
        return deltaY;
    }

    private void doMove(MotionEvent event) {
        int deltaY = computeDeltaY(event);
        if (!isNeedMove(deltaY)) {
            return;
        }
        refreshNormalRect();
        if (boundView != null) {
            moveElasticView(deltaY);
        } else {
            moveInnerView(deltaY);
        }
    }

    private void refreshOriginHeight(View view) {
        if (boundView != null) {
            android.view.ViewGroup.LayoutParams layoutParams = boundView.getLayoutParams();
            layoutParams.height = originHeight;
            boundView.setLayoutParams(layoutParams);
        }
        if (null != view) {
            originHeight = view.getLayoutParams().height;
        }
    }

    private void refreshNormalRect() {
        if (!originRect.isEmpty()) {// 保存正常的布局位置
            return;
        }
        originRect.set(mInnerView.getLeft(), mInnerView.getTop(), mInnerView.getRight(), mInnerView.getBottom());
    }

    private void moveInnerView(int deltaY) {
        mInnerView.layout(mInnerView.getLeft(), mInnerView.getTop() - deltaY, mInnerView.getRight(), mInnerView.getBottom() - deltaY);
    }

    private void moveElasticView(int deltaY) {
        android.view.ViewGroup.LayoutParams layoutParams = boundView.getLayoutParams();
        layoutParams.height = Math.max(0, layoutParams.height - deltaY);
        boundView.setLayoutParams(layoutParams);
    }
    // 是否需要还原
    private boolean isNeedReset() {
        if (boundView == null) {
            return !originRect.isEmpty();
        } else {
            return originHeight != boundView.getLayoutParams().height;
        }
    }
    private void doReset() {
        boolean needReset = isNeedReset();

        if (!needReset) {
            return;
        }

        if (boundView != null) {
            resetElasticView();
        } else {
            resetInnerView();
        }
    }

    private void resetElasticView() {

        ValueAnimator animator = ObjectAnimator.ofInt(boundView.getLayoutParams().height, originHeight);
        animator.setDuration(resetDelay);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (Integer) animation.getAnimatedValue();
                android.view.ViewGroup.LayoutParams layoutParams = boundView.getLayoutParams();
                layoutParams.height = value;
                boundView.setLayoutParams(layoutParams);

            }
        });
        animator.start();

    }

    private void resetInnerView() {
        int moveY = mInnerView.getTop() - originRect.top;
        ValueAnimator animator = ObjectAnimator.ofInt(moveY, 0);
        animator.setDuration(resetDelay);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (Integer) animation.getAnimatedValue();
                mInnerView.layout(originRect.left, originRect.top + value, originRect.right, originRect.bottom + value);
            }
        });
        animator.start();

    }

    // 是否需要移动布局
    private boolean isNeedMove(int deltaY) {
        return deltaY == 0 ? false : (deltaY < 0 ? isNeedMoveTop() : isNeedMoveBottom());
    }

    private boolean isNeedMoveTop() {
        int scrollY = getScrollY();
        return (scrollY == TOP_Y);
    }

    private boolean isNeedMoveBottom() {
        int offset = mInnerView.getMeasuredHeight() - getHeight();
        offset = (offset < 0) ? 0 : offset;

        int scrollY = getScrollY();
        return (scrollY == offset);
    }

}

猜你喜欢

转载自blog.csdn.net/sinat_21693123/article/details/50684894
今日推荐