自定義控件 仿應用寶 管理界面的標題欄縮放效果

最近看到應用寶管理界面裏面那個能縮能放的標題欄很有意思,所以自己嘗試簡單模仿下。


先上效果圖:


實現原理:

在listview裏面設置ontouch監聽,判斷滑動方向和藍色區域的狀態,如果藍色區域狀態是顯示最大且滑動方向向上,那麼縮小該區域,如果藍色區域最小,且滑動方向向下,則放大該區域。如果區域既不最大 也不最小,那麼即可放大也可縮小。
藍色區域繼承framelayout,小標題和大標題的visibile是相反設置的,也就是說只能顯示一個標題。

結合代碼:

開始做初始化:通過id獲取兩個標題欄View,並得到他們的高度和設置大標題View可見,小標題View不可見。這裏需要注意一點:在繪製沒有完成的情況下獲取到的高度是0,那麼就會出問題, 所以initData()函數要放在下面的地方執行。

http://stackoverflow.com/questions/11946424/getmeasuredheight-and-width-returning-0-after-measure
 這個網址做了詳細解釋
@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if(bigHeaderView == null && smallHeaderView == null){
            initData();
        }
    }


private void initData() {

        int bigHeaderViewId= getResources().getIdentifier("big_header_view", "id", getContext().getPackageName());
        int smallHeaderViewId = getResources().getIdentifier("small_header_view", "id", getContext().getPackageName());
//        System.out.println("bigHeaderViewId = " + bigHeaderViewId + "   smallHeaderViewId = " + smallHeaderViewId);

        if (bigHeaderViewId != 0 && smallHeaderViewId != 0) {
            bigHeaderView = findViewById(bigHeaderViewId);
            smallHeaderView = findViewById(smallHeaderViewId);

            heightBV = bigHeaderView.getMeasuredHeight();
            currentHeightBV = heightBV;
            heightSV = smallHeaderView.getMeasuredHeight();

//            System.out.println("heightBV = " + heightBV + "   heightSV = " + heightSV);
            bigHeaderView.setVisibility(VISIBLE);
            smallHeaderView.setVisibility(INVISIBLE);
            state = BIG_HEADER_VIEW_STATE;

        } else {
            Log.e("Error Inform", "沒有設置HeaderView Id");
        }
    }


下面是改變藍色區域大小的代碼:
//根據滑動設置高度
    public void setHeaderHeight(float dis) {

        int height = (int)(currentHeightBV + dis);
        if (height < heightSV) {
            height = heightSV;
        } else if (height > heightBV) {
            height = heightBV;
        }
        if (bigHeaderView != null && bigHeaderView.getLayoutParams() != null) {
            bigHeaderView.getLayoutParams().height = height;
            System.out.println("height = " + height + "  currentHeight = " + currentHeightBV);

            //計算縮放比,有了縮放比,你就可以做很多其他事情,比如控制alpha變化,控制scale變化
            //像有些標題欄是根據手勢移動,來改變透明度的.
            float scalePercent = (height - heightSV)*1.0f / (heightBV - heightSV);
            setTextViewHeight(scalePercent);

            bigHeaderView.requestLayout();
        } else {
            Log.e(TAG, "bigHeaderView = null");
        }

        if(height <= heightSV){
            smallHeaderView.setVisibility(VISIBLE);
            bigHeaderView.setVisibility(INVISIBLE);
            state = SMALL_HEADER_VIEW_STATE;
        } else {
            smallHeaderView.setVisibility(INVISIBLE);
            bigHeaderView.setVisibility(VISIBLE);
            if(height == heightBV)
                state = BIG_HEADER_VIEW_STATE;
            else
                state = MID_HEADER_VIEW_STATE;
        }
    }

爲了體驗更好,在藍色區域縮放到2/3以內大小的時候,自動縮小直到最小。我的實現方式是通過線程來慢慢改變高度,詳見代碼,註釋很詳細
/**
     * 當位置大於heightSV 並且小於 heightBV*2/3的時候,執行平滑縮放
     * 感覺自己用線程實現的平滑效果不是很好......
     */
    public void smoothSetHeaderHeight() {

        currentHeightBV = bigHeaderView.getHeight();
        final int timeCount = 1*200; //0.2秒鐘 從heightBV*2/3 縮放到 heightSV
        final float dis = -1 * (heightBV*2.0f/3.0f-heightSV)*1.0f/timeCount*10;

//        System.out.println("currentHeightBV = " + currentHeightBV);
        if(currentHeightBV > (heightBV*2 / 3) || currentHeightBV <= heightSV) {
            return;
        }

//        System.out.println("dis = " + dis);
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < timeCount/10; i++) {
                    final float sumDis = i*dis + dis;
                    post(new Runnable() {
                        public void run() {
                            setHeaderHeight(sumDis);
                        }
                    });
                    try {
                        sleep(10); //爲了體驗好點,慢慢縮放
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }.start();
    }


下面貼上recycleview的事件監聽代碼
View.OnTouchListener onTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            int moveY = (int)event.getRawY();  //取得手指相對屏幕的Y座標

            if(event.getAction() == MotionEvent.ACTION_DOWN){
                mDownY = event.getRawY();  //按下時候的座標
            }
            if(event.getAction() == MotionEvent.ACTION_MOVE){
                int dis = (int)(moveY - mDownY);     //移動距離
//                System.out.println("move distance = " + dis);
                int state = scrollerHeaderLayout.getState();  //當前滑動狀態
                //下滑時候 需要做如下操作
                if(dis > 0 && !recycleView.canScrollVertically(-1)
                        && (state == ScrollerHeaderLayout.SMALL_HEADER_VIEW_STATE
                        || state == ScrollerHeaderLayout.MID_HEADER_VIEW_STATE)){
//                    System.out.println("stateScrollerDir" + stateScrollerDir);
                    /**
                     * 這裏邏輯是:如果你突然換方向移動,那麼需要改變mDownY的座標爲"換方向的那個轉折點"的Y標。
                     * 並初始化當前 scrollerHeaderLayout的高度。
                     */
                    if(stateScrollerDir < 0) {
                        mDownY = moveY;
                        scrollerHeaderLayout.initCurrentHeightBV();
                    }
                    //改變移動狀態
                    stateScrollerDir = 1;
                    dis = (int)(moveY - mDownY); //重新計算距離 :可能換方向移動了,原來計算的距離不對了.
                    scrollerHeaderLayout.setHeaderHeight(dis); //設置高度
                    return true;
                }
                //上滑 同下滑操作一樣
                if(dis < 0 && (state == ScrollerHeaderLayout.BIG_HEADER_VIEW_STATE
                        || state == ScrollerHeaderLayout.MID_HEADER_VIEW_STATE)){
                    if(stateScrollerDir > 0) {
                        mDownY = moveY;
                        scrollerHeaderLayout.initCurrentHeightBV();
//                        System.out.println("mDownY = " + mDownY);
                    }
                    stateScrollerDir = -1;

                    dis = (int)(moveY - mDownY);
//                    System.out.println("-1 dis = " + dis);
                    scrollerHeaderLayout.setHeaderHeight(dis);
                    return true;
                }
                mDownY = event.getRawY();
            }
            if(event.getAction() == MotionEvent.ACTION_UP){
                scrollerHeaderLayout.initCurrentHeightBV();
                scrollerHeaderLayout.smoothSetHeaderHeight();
            }
            return false;
        }
    };

總結:這裏通過線程方式實現的自動縮放致最小高度,因爲是勻速的,效果有點不太好...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章