Android -- 自定義ScrollView實現放大回彈效果


1,剛剛在別人開源的項目中看到了一個挺不錯的用戶體驗,效果圖如下:

2,那下面我們就來實現一下,首先看一下布局,由於一般只是我們包含頭像的那部分方法,所以這里我們要把布局分成兩部分,對應的布局文件效果圖如下:

3,自定義ScrollView

  第一步:創建一個類,繼承自ScrollView,重寫相應的構造函數

public class ZoomInScrollView extends ScrollView {
 public ZoomInScrollView(Context context) {
        this(context, null);
    }

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

    public ZoomInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

  第二步:重寫OnFinishInflate()方法,並記錄第一個子view,即我們的head_fragment

@Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //設置不可過度滾動,否則上移后下拉會出現部分空白的情況
        setOverScrollMode(OVER_SCROLL_NEVER);
        View child = getChildAt(0);
        if (child != null && child instanceof ViewGroup) {
            //獲取默認第一個子View
            mHeaderView = ((ViewGroup) child).getChildAt(0);
        }
    }

  第三步:重寫OnTouchEvent()方法,在Action_Move方法中拿到下滑的距離,通過設置head_view的屬性參數來改變它的大小,在UP的時候還原head_view

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (mHeaderView == null)
            return super.onTouchEvent(ev);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                if (!mIsPulling) {
                    //第一次下拉
                    if (getScrollY() == 0) {
                        //在頂部的時候,記錄頂部位置
                        mLastY = (int) ev.getY();
                    } else {
                        break;
                    }
                }
                if (ev.getY() - mLastY < 0)
                    return super.onTouchEvent(ev);
                int distance = (int) ((ev.getY() - mLastY) * mScaleRatio);
                mIsPulling = true;
                setZoom(distance);
                return true;
            case MotionEvent.ACTION_UP:
                mIsPulling = false;
                replyView();
                break;
        }
        return super.onTouchEvent(ev);
    }

    在回彈view的時候通過屬性動畫動態的改變head_view的值,並重寫onSizeChange()方法,實時的記錄head_view的寬高

**
     * 放大view
     */
    private void setZoom(float s) {
        float scaleTimes = (float) ((mHeaderWidth + s) / (mHeaderWidth * 1.0));
//        如超過最大放大倍數,直接返回
        if (scaleTimes > mScaleTimes) return;

        ViewGroup.LayoutParams layoutParams = mHeaderView.getLayoutParams();
        layoutParams.width = (int) (mHeaderWidth + s);
        layoutParams.height = (int) (mHeaderHeight * ((mHeaderWidth + s) / mHeaderWidth));
//        設置控件水平居中
        ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - mHeaderWidth) / 2, 0, 0, 0);
        mHeaderView.setLayoutParams(layoutParams);
    }

    /**
     * 回彈
     */
    private void replyView() {
        final float distance = mHeaderView.getMeasuredWidth() - mHeaderWidth;
        // 設置動畫
        ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * mReplyRatio));
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                setZoom((Float) animation.getAnimatedValue());
            }
        });
        anim.start();
    }

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mHeaderWidth = mHeaderView.getMeasuredWidth();
        mHeaderHeight = mHeaderView.getMeasuredHeight();
    }

  這樣就實現了我們的效果了,看一下我們自己實現的效果:

   github下載地址(還沒有傳上去,網速差,騷等一下),有需要源碼的同學可以去下載一下。See You Next Time ......


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM