自定义控件 仿应用宝 管理界面的标题栏缩放效果

来源:互联网 发布:对人工智能社会的畅想 编辑:程序博客网 时间:2024/06/01 08:58

最近看到应用宝管理界面里面那个能缩能放的标题栏很有意思,所以自己尝试简单模仿下。


先上效果图:


实现原理:

在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;        }    };

总结:这里通过线程方式实现的自动缩放致最小高度,因为是匀速的,效果有点不太好...
0 0