您的位置:首页 > 移动开发 > Android开发

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

2015-09-24 09:24 351 查看

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

先上效果图:



实现原理:

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

总结:这里通过线程方式实现的自动缩放致最小高度,因为是匀速的,效果有点不太好...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息