android沉浸式状态栏实现

传统的手机状态栏是呈现出黑色条状的,有的和手机主界面有很明显的区别。这样就在一定程度上牺牲了视觉宽度,界面面积变小。
沉浸模式的状态栏和主界面完全融为了一体,在设计上有不同的视觉感受。

我们先上两张图,很容易看出区别:


Android在4.4的时候增加了透明状态栏与导航栏的功能,依托于这个新特性,我们可以开始跟随潮流,实现Android的沉浸式状态栏
其实上图展示的这个关于界面的代码非常简单
  1. /**
  2. * 关于界面
  3. *
  4. * @author SuS
  5. * @time 2015.07.29
  6. */
  7. public class AboutActivity extends BaseActivity {
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. this.setContentView(R.layout.activity_about);
  12. setImmerseLayout(findViewById(R.id.common_back));
  13. initBackButton();
  14. setTitleBar(R.string.durian_about);
  15. }
  16. @Override
  17. protected void onResume() {
  18. super.onResume();
  19. }
  20. @Override
  21. protected void onPause() {
  22. super.onPause();
  23. }
  24. @Override
  25. protected void onDestroy() {
  26. super.onDestroy();
  27. }
  28. }
/**
 * 关于界面
 *
 * @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中实现的
  1. public class BaseActivity extends FragmentActivity {
  2. private static final String TAG = "BaseActivity";
  3. ...............
  4. public void initBackButton() {
  5. ImageView backButton = (ImageView) this.findViewById(R.id.durian_back_image);
  6. backButton.setOnClickListener(new View.OnClickListener() {
  7. @Override
  8. public void onClick(View v) {
  9. finishActivity();
  10. }
  11. });
  12. }
  13. protected void setImmerseLayout(View view) {
  14. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  15. Window window = getWindow();
  16. /*window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
  17. WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);*/
  18. window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  19. int statusBarHeight = ScreenUtil.getStatusBarHeight(this.getBaseContext());
  20. view.setPadding(0, statusBarHeight, 0, 0);
  21. }
  22. }
  23. public void finishActivity() {
  24. finish();
  25. overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out);
  26. }
  27. public void setTitleBar(int id) {
  28. TextView tvName = (TextView) findViewById(R.id.durian_title_text);
  29. tvName.setText(id);
  30. }
  31. }
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方法
  1. /**
  2. * 用于获取状态栏的高度。 使用Resource对象获取(推荐这种方式)
  3. *
  4. * @return 返回状态栏高度的像素值。
  5. */
  6. public static int getStatusBarHeight(Context context) {
  7. int result = 0;
  8. int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
  9. "android");
  10. if (resourceId > 0) {
  11. result = context.getResources().getDimensionPixelSize(resourceId);
  12. }
  13. return result;
  14. }
  /**
     * 用于获取状态栏的高度。 使用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

  1. <include
  2. android:id="@+id/common_back"
  3. layout="@layout/common_back" />
 <include
        android:id="@+id/common_back"
        layout="@layout/common_back" />

common_back的布局如下:
  1. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:id="@+id/durian_head_layout"
  4. android:layout_width="match_parent"
  5. android:layout_height="wrap_content"
  6. android:background="@color/common_top_bg" >
  7. <RelativeLayout
  8. android:layout_width="match_parent"
  9. android:layout_height="51dp" >
  10. <ImageView
  11. android:id="@+id/durian_back_image"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:layout_centerVertical="true"
  15. android:layout_marginLeft="18dp"
  16. android:padding="5dp"
  17. android:src="@drawable/btn_back_selector" />
  18. <TextView
  19. android:id="@+id/durian_title_text"
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content"
  22. android:layout_centerInParent="true"
  23. android:textColor="@color/common_text_black"
  24. android:textSize="18sp" />
  25. <ImageView
  26. android:id="@+id/durian_titlebar_image1"
  27. android:layout_width="51dp"
  28. android:layout_height="51dp"
  29. android:layout_alignParentRight="true"
  30. android:layout_centerVertical="true"
  31. android:scaleType="centerInside"
  32. android:visibility="gone" />
  33. <ImageView
  34. android:id="@+id/durian_titlebar_image2"
  35. android:layout_width="51dp"
  36. android:layout_height="51dp"
  37. android:layout_centerVertical="true"
  38. android:layout_toLeftOf="@id/durian_titlebar_image1"
  39. android:scaleType="centerInside"
  40. android:visibility="gone" />
  41. </RelativeLayout>
  42. </FrameLayout>
<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只有一个背景图片或者不以类似导航栏的空间作为基准的话,怎么实现沉浸式状态栏,例如达到这种状态
我们只需要在代码这样设置
  1. protected void setImmerseLayout(View view) {
  2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  3. Window window = getWindow();
  4. /*window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
  5. WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);*/
  6. window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  7. /* int statusBarHeight = ScreenUtil.getStatusBarHeight(this.getBaseContext());
  8. view.setPadding(0, statusBarHeight, 0, 0);*/
  9. }
  10. }
   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,现在附上
Demo 下载地址 https://github.com/feifei003603/ImmerseLayoutDemo.git

Android 5.0 如何实现将布局的内容延伸到状态栏实?

补充:这个只是我刚开始搞这部分内容,肯定存在很多不足,也有很多问题没有考虑到,觉得可以参考的就拿去,觉得比较low的大神请放过

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值