ScrollView下拉頭部縮放

** ScrollView下拉頭部縮放 **

用法和ScrollView一樣



public class PersonalScrollView extends ScrollView {
    private static final String TAG = "BounceScrollView";
    //----頭部收縮屬性--------
    // 記錄首次按下位置
    private float mFirstPosition = 0;
    // 頭部圖片是否正在放大
    private Boolean mScaling = false;
    private View dropZoomView;//需要被放大的view
    private int dropZoomViewWidth;
    private int dropZoomViewHeight;
    //----頭部收縮屬性end--------
    //------尾部收縮屬性--------
    private View inner;// 子View
    private float y;// 點(diǎn)擊時(shí)y坐標(biāo)
    private Rect normal = new Rect();// 矩形(這里只是個(gè)形式,只是用于判斷是否需要?jiǎng)赢?)
    private boolean isCount = false;// 是否開始計(jì)算
    //最后的坐標(biāo)
    private float lastX = 0;
    private float lastY = 0;
    //當(dāng)前坐標(biāo)
    private float currentX = 0;
    private float currentY = 0;
    //移動(dòng)的坐標(biāo)量
    private float distanceX = 0;
    private float distanceY = 0;
    private boolean upDownSlide = false; //判斷上下滑動(dòng)的flag
    //------尾部收縮屬性end--------
    public PersonalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    //初始化
    private void init() {
        setOverScrollMode(OVER_SCROLL_NEVER);
        if (getChildAt(0) != null) {
            inner = getChildAt(0);//這個(gè)是底部收縮的view
            //頭部收縮的
            ViewGroup vg = (ViewGroup) getChildAt(0);
            if (vg.getChildAt(0) != null) {
                dropZoomView = vg.getChildAt(0);
            }
        }
    }
    /***
     * 生成視圖工作完成.該函數(shù)在生成視圖的最后調(diào)用,在所有子視圖添加完之后. 即使子類覆蓋了 onFinishInflate
     * 方法,也應(yīng)該調(diào)用父類的方法,使該方法得以執(zhí)行.
     */
    @Override
    protected void onFinishInflate() {
        //初始化
        init();
        super.onFinishInflate();
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //這里只是計(jì)算尾部坐標(biāo)
        currentX = ev.getX();
        currentY = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                distanceX = currentX - lastX;
                distanceY = currentY - lastY;
                if (Math.abs(distanceX) < Math.abs(distanceY) && Math.abs(distanceY) > 12) {
                    upDownSlide = true;
                }
                break;
        }
        lastX = currentX;
        lastY = currentY;
        if (upDownSlide && inner != null) commOnTouchEvent(ev);
        return super.dispatchTouchEvent(ev);
    }
    /***
     * 觸摸事件
     *
     * @param ev
     */
    public void commOnTouchEvent(MotionEvent ev) {
        //頭部縮放計(jì)算
        if (dropZoomViewWidth <= 0 || dropZoomViewHeight <= 0) {
            dropZoomViewWidth = dropZoomView.getMeasuredWidth();
            dropZoomViewHeight = dropZoomView.getMeasuredHeight();
        }
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                //手指離開后頭部恢復(fù)圖片
                mScaling = false;
                replyImage();
                // 手指松開尾部恢復(fù)
                if (isNeedAnimation()) {
                    animation();
                    isCount = false;
                }
                clear0();
                break;
            //這里頭尾分開處理,互不干擾
            case MotionEvent.ACTION_MOVE:
                //尾部處理
                final float preY = y;// 按下時(shí)的y坐標(biāo)
                float nowY = ev.getY();// 時(shí)時(shí)y坐標(biāo)
                int deltaY = (int) (preY - nowY);// 滑動(dòng)距離
                if (!isCount) {
                    deltaY = 0; // 在這里要?dú)w0.
                }
                y = nowY;
                // 當(dāng)滾動(dòng)到最上或者最下時(shí)就不會(huì)再滾動(dòng),這時(shí)移動(dòng)布局
                if (isNeedMove()) {
                    // 初始化頭部矩形
                    if (normal.isEmpty()) {
                        // 保存正常的布局位置
                        normal.set(inner.getLeft(), inner.getTop(),
                                inner.getRight(), inner.getBottom());
                    }
                    // 移動(dòng)布局
                    inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2,
                            inner.getRight(), inner.getBottom() - deltaY / 2);
                }
                isCount = true;
                //尾部處理end
                //頭部處理
                if (!mScaling) {
                    if (getScrollY() == 0) {
                        mFirstPosition = ev.getY();// 滾動(dòng)到頂部時(shí)記錄位置,否則正常返回
                    } else {
                        break;
                    }
                }
                int distance = (int) ((ev.getY() - mFirstPosition) * 0.6); // 滾動(dòng)距離乘以一個(gè)系數(shù)
                if (distance < 0) { // 當(dāng)前位置比記錄位置要小,正常返回
                    break;
                }
                // 處理放大
                mScaling = true;
                setZoom(1 + distance);
                //頭部處理end
                break;
        }
    }
    /***
     * 回縮動(dòng)畫,尾部往下縮動(dòng)畫
     */
    public void animation() {
        // 開啟移動(dòng)動(dòng)畫
        TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
                normal.top);
        ta.setDuration(200);
        inner.startAnimation(ta);
        // 設(shè)置回到正常的布局位置
        inner.layout(normal.left, normal.top, normal.right, normal.bottom);
        normal.setEmpty();
    }
    // 是否需要開啟動(dòng)畫
    public boolean isNeedAnimation() {
        return !normal.isEmpty();
    }
    // 回彈動(dòng)畫,header往上縮動(dòng)畫 (使用了屬性動(dòng)畫)
    public void replyImage() {
        final float distance = dropZoomView.getMeasuredWidth() - dropZoomViewWidth;
        // 設(shè)置動(dòng)畫
        ValueAnimator anim = ObjectAnimator.ofFloat(0.0F, 1.0F).setDuration((long) (distance * 0.7));
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float cVal = (Float) animation.getAnimatedValue();
                setZoom(distance - ((distance) * cVal));
            }
        });
        anim.start();
    }
    //頭部縮放
    public void setZoom(float s) {
        if (dropZoomViewHeight <= 0 || dropZoomViewWidth <= 0) {
            return;
        }
        ViewGroup.LayoutParams lp = dropZoomView.getLayoutParams();
        lp.width = (int) (dropZoomViewWidth + s);
        lp.height = (int) (dropZoomViewHeight * ((dropZoomViewWidth + s) / dropZoomViewWidth));
        dropZoomView.setLayoutParams(lp);
    }
    /***
     * 是否需要移動(dòng)布局 inner.getMeasuredHeight():獲取的是控件的總高度
     *
     * getHeight():獲取的是屏幕的高度
     *
     * @return
     */
    public boolean isNeedMove() {
        int offset = inner.getMeasuredHeight() - getHeight();
        int scrollY = getScrollY();
        // 0是頂部,后面那個(gè)是底部
        if (scrollY == 0 || scrollY == offset) {
            return true;
        }
        return false;
    }
    //清理尾部屬性值
    private void clear0() {

        lastX = 0;
        lastY = 0;
        distanceX = 0;
        distanceY = 0;
        upDownSlide = false;


    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,692評(píng)論 4 61
  • 《人脈就是我們的錢脈》 美國(guó)成功學(xué)大師戴爾·卡耐基經(jīng)過長(zhǎng)期研究曾經(jīng)得出這樣一個(gè)結(jié)論:??“專業(yè)知識(shí)在一個(gè)人成功中的...
    方琪兒閱讀 262評(píng)論 0 0
  • 相信大家對(duì)《傲慢與偏見》這部世界著名并不陌生,其作者是簡(jiǎn)奧斯汀,與其有異曲同工之妙的《理智與情感》也是由她創(chuàng)作...
    劉梓YA閱讀 1,241評(píng)論 0 1
  • 財(cái)經(jīng)美女葉檀,集美貌和智慧于一體,經(jīng)常聽她高談闊論。最近她對(duì)國(guó)人的普遍焦慮總結(jié)歸納如下:無處可逃的生存型...
    妙計(jì)菩提閱讀 508評(píng)論 8 3
  • 引言 此文是iOS中的多線程編程:重溫GCD(一)系列的第二部分。將會(huì)輔以一定的例子簡(jiǎn)單講解一些更深層次的API使...
    ZhengLi閱讀 388評(píng)論 0 3

友情鏈接更多精彩內(nèi)容