需求描述:
PM來一句,做成美團首頁頂通的效果。
實現效果要做的事情有:
- 沉浸式狀態欄
- 標題欄變色(從透明變成白色再漸變成紅色)
- 無Banner時不沉浸(有狀態欄有標題欄)
實現效果如下所示。
屏幕快照 2017-08-05 下午3.39.38.png
方法有很多,我的解決方法如下:
狀態欄
4.4之前,狀態欄一值是黑色的,4.4中windowTransluentStatus可以給狀態欄設置顏色。4.4及以上都是可以實現沉浸式狀態欄效果,**5.0及其以上,可以直接在主題中設置顏色,或者直接調用Window類中的setStatusBarColor(int)來實現;
沉浸式的實現原理,就是將整個activity布局延伸到整個屏幕,然后使狀態欄變成透明色。所以沉浸式狀態欄又可以叫做Translucent Bar。
解決思路
- 先將狀態欄設置為透明屬性
- Toolbar代替ActionBar,獲得更好的控制
- 根布局設置成RelativeLayout,方便調整View的位置
Activity的布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar">
</FrameLayout>
<include android:id="@id/toolbar"
layout="@layout/activity_search_toolbar"/>
</RelativeLayout>
activity_search_toolbar的布局
<xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="0dp"
app:contentInsetStart="0dp">
<LinearLayout
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/toolbar_back"
android:layout_width="48dp"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:src="@drawable/arrow_left"/>
<TextView
android:id="@+id/search_edit"
android:layout_width="0dp"
android:layout_height="34dp"
android:layout_weight="1" android:drawableLeft="@drawable/search"
android:drawablePadding="3dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:hint="目的地/景點/關鍵詞"
android:maxLines="1"
android:paddingBottom="6dp"
android:paddingLeft="10dp"
android:paddingRight="5dp"
android:paddingTop="5dp"
android:textColor="@color/black"
android:textSize="14sp"/>
<TextView
android:id="@+id/change_city"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:drawablePadding="3dp"
android:drawableRight="@drawable/arrow_red"
android:gravity="center_vertical"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:textColor="#FF0"
android:textSize="14sp"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
設置透明狀態欄
//沉浸式狀態欄
public void immersiveStatusBar(Window window) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
int systemUiVisibility = window.getDecorView().getSystemUiVisibility();
//Activity全屏顯示,狀態欄不會被隱藏覆蓋,狀態欄依然可見,Activity頂端布局部分會被狀態欄遮住。
systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
//防止系統欄隱藏時內容區域大小發生變化
systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
window.getDecorView().setSystemUiVisibility(systemUiVisibility);
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
immersive = true;
}
根據有無Banner,設置content(內容Fragment的位置)
- 如果有Banner,狀態欄設置為透明,toolbar的topMargin=狀態欄高度,RelativeLayout不動,監聽滾動,設置狀態欄和toolbar的顏色
- 如果沒有Banner,設置content在toolbar的下面,toolbar的topMargin=狀態欄高度
- 因為在滾動過程中,還要更改狀態欄的顏色和透明度,干脆做一個假的狀態欄,方便控制。
private void setNoBannerToolbarStyle() {
if (toolbar == null) {
return;
}
//content的布局參數
RelativeLayout.LayoutParams contentLayoutParams = (RelativeLayout.LayoutParams) contentLayout.getLayoutParams();
contentLayoutParams.addRule(RelativeLayout.BELOW, R.id.toolbar);
RelativeLayout.LayoutParams toolbarLayoutParams = (RelativeLayout.LayoutParams) toolbar.getLayoutParams();
if (immersive) {
toolbarLayoutParams.topMargin = getStatusBarHeight(getContext());
} else {
toolbarLayoutParams.topMargin = 0;
}
}
private void setToolbarStyle() {
if (toolbar == null) {
return;
}
RelativeLayout.LayoutParams contentLayoutParams = (RelativeLayout.LayoutParams) contentLayout.getLayoutParams();
contentLayoutParams.addRule(RelativeLayout.BELOW, 0);
if (immersive) {
RelativeLayout.LayoutParams toolbarLayoutParams = (RelativeLayout.LayoutParams) toolbar.getLayoutParams();
toolbarLayoutParams.topMargin = statusBarHeight;
.......
}
//添加假的狀態欄
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && statusBarView == null) {
ViewGroup contentView = (ViewGroup) getActivity().findViewById(R.id.page);
statusBarView = new View(getContext());
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
getStatusBarHeight(getActivity()));
statusBarView.setBackgroundColor(Color.TRANSPARENT);
contentView.addView(statusBarView, lp);
}