1. 程式人生 > >【Android實戰】沉浸式狀態列實現(上)

【Android實戰】沉浸式狀態列實現(上)

傳統的手機狀態列是呈現出黑色條狀的,有的和手機主介面有很明顯的區別。這樣就在一定程度上犧牲了視覺寬度,介面面積變小。
沉浸模式的狀態列和主介面完全融為了一體,在設計上有不同的視覺感受。

我們先上兩張圖,很容易看出區別:

      

Android在4.4的時候增加了透明狀態列與導航欄的功能,依託於這個新特性,我們可以開始跟隨潮流,實現Android的沉浸式狀態列 其實上圖展示的這個關於介面的程式碼非常簡單
/**
 * 關於介面
 *
 * @author SuS
 * @time 2015.07.29
 */
public class AboutActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.activity_about);

        setImmerseLayout(findViewById(R.id.common_back));

        initBackButton();
        setTitleBar(R.string.durian_about);
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

}
現在請注意setImmerseLayout()這個方法,這個方法是在BaseActivity中實現的
public class BaseActivity extends FragmentActivity {
    private static final String TAG = "BaseActivity";

  ...............
   
    public void initBackButton() {
        ImageView backButton = (ImageView) this.findViewById(R.id.durian_back_image);
        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finishActivity();
            }
        });
    }
   
    protected void setImmerseLayout(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                Window window = getWindow();
                /*window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);*/
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

            int statusBarHeight = ScreenUtil.getStatusBarHeight(this.getBaseContext());
            view.setPadding(0, statusBarHeight, 0, 0);
        }
    }
   
    public void finishActivity() {
        finish();
        overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out);
    }
   
    public void setTitleBar(int id) {
        TextView tvName = (TextView) findViewById(R.id.durian_title_text);
        tvName.setText(id);
    }
}
使用 window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,                 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 或者 window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
都可以使狀態列透明,但是關鍵是下面這兩行程式碼,如果沒有這兩行,會是這樣
那麼這兩行神奇的程式碼的原理是什麼? 我們先看一下ScreenUtil中的getStatusBarHeight方法
  /**
     * 用於獲取狀態列的高度。 使用Resource物件獲取(推薦這種方式)
     *
     * @return 返回狀態列高度的畫素值。
     */
    public static int getStatusBarHeight(Context context) {
        int result = 0;
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
                "android");
        if (resourceId > 0) {
            result = context.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

這裡是獲得狀態列的高度,然後我們就可以通過設定common_back的padding屬性 即:view.setPadding(0, statusBarHeight, 0, 0)來達到終極效果 但是這裡還是需要注意細節的,首先大家應該理解padding的含義:內邊距 那麼再看一下common_back的佈局檔案 在activity_about.xml中我們是使用include引用的common_back
 <include
        android:id="@+id/common_back"
        layout="@layout/common_back" />

common_back的佈局如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/durian_head_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/common_top_bg" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="51dp" >

        <ImageView
            android:id="@+id/durian_back_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="18dp"
            android:padding="5dp"
            android:src="@drawable/btn_back_selector" />

        <TextView
            android:id="@+id/durian_title_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="@color/common_text_black"
            android:textSize="18sp" />

        <ImageView
            android:id="@+id/durian_titlebar_image1"
            android:layout_width="51dp"
            android:layout_height="51dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:scaleType="centerInside"
            android:visibility="gone" />

        <ImageView
            android:id="@+id/durian_titlebar_image2"
            android:layout_width="51dp"
            android:layout_height="51dp"
            android:layout_centerVertical="true"
            android:layout_toLeftOf="@id/durian_titlebar_image1"
            android:scaleType="centerInside"
            android:visibility="gone" />
    </RelativeLayout>

</FrameLayout>

這裡我們使用了一層FrameLayout包裹住RelativeLayout,這裡有什麼玄機那,其實這裡就是為了 方便上面那兩行神奇的程式碼起作用,這樣我們就能設定RelativeLayout相對於FrameLayout的內邊距為狀態列的高度了 也就完美的達到了沉浸式狀態列的目的,而且保證導航欄的相對位置不變。 這裡存在一個common_back作為一個基準來控制高度達到狀態列的高度,如果一個activity只有一個背景圖片或者不以類似導航欄的空間作為基準的話,怎麼實現沉浸式狀態列,例如達到這種狀態 我們只需要在程式碼這樣設定
   protected void setImmerseLayout(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                Window window = getWindow();
                /*window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);*/
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

           /* int statusBarHeight = ScreenUtil.getStatusBarHeight(this.getBaseContext());
            view.setPadding(0, statusBarHeight, 0, 0);*/
        }
    }

然後在當前activity的佈局檔案中加入這兩句話  android:fitsSystemWindows="true"  android:clipToPadding="true" 這時候狀態列的背景與Activity的整個大背景融合在一起了

總結:

基於以上的方法介紹,我們可以實現狀態列與導航欄以及狀態列與頁面大背景的沉浸式體驗。

其實上面也可以看出程式碼封裝的一些技巧:如讓我們所有的activity繼承BaseActivity,這樣像

 setImmerseLayout(findViewById(R.id.common_back));         initBackButton();         setTitleBar(R.string.durian_about); 諸如此類的操作實現起來省時省力了! 歡迎拍磚 、評論! 今天的部落格就寫到這裡了,抓緊回家了,要不外面又要下大雨了! 昨天太晚了,沒有上傳demo,現在附上

補充:這個只是我剛開始搞這部分內容,肯定存在很多不足,也有很多問題沒有考慮到,覺得可以參考的就拿去,覺得比較low的大神請放過