Android UI进阶之旅9--Material Design之沉浸式设计

沉浸式设计基本概念

官方的沉浸式Translucent定义:就是让整个APP沉浸(充斥了整个屏幕)在屏幕里面,没有显示状态栏,甚至没有显示底部导航栏。

平时大家所讨论的沉浸式:比如QQ的顶部Toolbar和状态栏程一体的颜色。

5.0以上状态栏沉浸式设计

5.0+自动实现了沉浸式效果,状态栏的颜色跟随你的主题里面的colorPrimaryDark属性。

例如我们直接在主题里面设置colorPrimaryDark即可,也可以设置colorPrimaryDark:


由于每一个Activity(Fragment)的沉浸式颜色可能不一样,因此我们可以通过代码去设置:

//5.0+可以直接用API来修改状态栏的颜色。
getWindow().setStatusBarColor(getResources().getColor(R.color.material_blue_grey_800));
(注意:要在setContentView方法之前设置)

4.4以上状态栏沉浸式设计

用到一些特殊手段!----4.4(KitKat)新出的API,可以设置状态栏为透明的。

注意:低于4.4API,不可以做到

下面介绍一些方法:

一、通过设置属性样式(不推荐,兼容性不好)

在主题里面添加(注意需要在v-19以上的资源文件中添加哦):

true

二、2.在代码里面解决(笔者认为通过这个方法,已经可以解决4.4以上的所有问题了,因此特别推荐)

在Activity里面添加

getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
setContentView(R.layout.activity_main);

但是,APP的内容顶到最上面去了,即状态栏会遮挡一部分界面。

解决办法(有几种):

  1. 给布局最外层容器设置android:fitsSystemWindows="true" 。
  2. 给Toolbar设置top padding,但是这时候我们需要通过反射去获取状态栏的高度:

修改Toolbar的PaddingTop(因为纯粹增加toolbar的高度会遮挡toobar里面的一些内容)

/**
 * 获取状态栏的高度
 * @param context
 * @return
 */
private int getStatusBarHeight(Context context) {
    // 反射手机运行的类:android.R.dimen.status_bar_height.
    int statusHeight = -1;
    try {
        Class clazz = Class.forName("com.android.internal.R$dimen");
        Object object = clazz.newInstance();
        String heightStr = clazz.getField("status_bar_height").get(object).toString();
        int height = Integer.parseInt(heightStr);
        //dp--->px
        statusHeight = context.getResources().getDimensionPixelSize(height);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return statusHeight;
}

然后给Toolbar设置padding:

toolbar.setPadding(
    toolbar.getPaddingLeft(),
    toolbar.getPaddingTop()+getStatusBarHeight(this), 
    toolbar.getPaddingRight(),
    toolbar.getPaddingBottom());
注意:当你的toolbar是白色的时候,如果手机系统的状态栏的文字又刚好是白色的话,我们可以不用padding,而是使用一个渐变的半透明黑色.9图,类似360手机助手的效果
关于状态栏的沉浸式,还可以使用第三方的沉浸式解决方案:SystemTint,但是也会有一些坑。

5.0以上底部导航栏沉浸式设计

底部的虚拟按键导航栏我们一般很少去适配,这里只给出一些简单的解决方案。

5.0+ 可以用主题样式解决:

@color/system_bottom_nav_color

或者代码实现:

getWindow().setNavigationBarColor()

4.4以上底部导航栏沉浸式设计

用到一些特殊手段!----4.4(KitKat)新出的API,可以设置虚拟导航栏为透明的。

步骤:

  1. 在布局底部添加一个高度为0.1dp的view
  2. 动态设置底部View的高度为虚拟导航栏的高度

代码:

/**
 * 获取底部虚拟按键的高度
 * @param context
 * @return
 */
private int getStatusBarHeight(Context context) {
    // 反射手机运行的类:android.R.dimen.navigation_bar_height.
    int statusHeight = -1;
    try {
        Class clazz = Class.forName("com.android.internal.R$dimen");
        Object object = clazz.newInstance();
        String heightStr = clazz.getField("navigation_bar_height").get(object).toString();
        int height = Integer.parseInt(heightStr);
        //dp--->px
        statusHeight = context.getResources().getDimensionPixelSize(height);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return statusHeight;
}

然后在代码中设置:

View nav = findViewById(R.id.nav);
LayoutParams p = nav.getLayoutParams();
p.height += getNavigationBarHeight(this);
nav.setLayoutParams(p);

另外,还需要做兼容性判断:

1)SDK版本不一样,按照上述方法做不同处理:
两个区间:1. 大于5.0;2.=<4.4sdk<5.0

2)有的没有虚拟导航栏
    判断是否有虚拟导航栏(源码里面有方法可以得到是否有虚拟导航,反射得到)

3)有的有虚拟导航,但是还可以开关
    判断是否虚拟导航栏打开了

最后,我们封装一个具有上述功能的BaseActivity

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class BaseTranslucentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //判断版本,如果[4.4,5.0)就设置状态栏和导航栏为透明
        if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.KITKAT
                &&android.os.Build.VERSION.SDK_INT=android.os.Build.VERSION_CODES.KITKAT
                &&android.os.Build.VERSION.SDK_INT=android.os.Build.VERSION_CODES.LOLLIPOP){
            getWindow().setNavigationBarColor(translucentPrimaryColor);
            getWindow().setStatusBarColor(translucentPrimaryColor);
        }else{
            //<4.4的,不做处理
        }
    }
    

    private int getNavigationBarHeight(Context context) {
        return getSystemComponentDimen(this, "navigation_bar_height");
    }

    /**
     * 获取状态栏的高度
     * @param context
     * @return
     */
    private int getStatusBarHeight(Context context) {
        // 反射手机运行的类:android.R.dimen.status_bar_height.
        return getSystemComponentDimen(this, "status_bar_height");
    }
    
    private static int getSystemComponentDimen(Context context, String dimenName){
        // 反射手机运行的类:android.R.dimen.status_bar_height.
        int statusHeight = -1;
        try {
            Class clazz = Class.forName("com.android.internal.R$dimen");
            Object object = clazz.newInstance();
            String heightStr = clazz.getField(dimenName).get(object).toString();
            int height = Integer.parseInt(heightStr);
            //dp--->px
            statusHeight = context.getResources().getDimensionPixelSize(height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return statusHeight;
    }
    
    private static boolean hasNavigationBarShow(WindowManager wm){
        Display display = wm.getDefaultDisplay();
        DisplayMetrics outMetrics = new DisplayMetrics();
        //获取整个屏幕的高度
        display.getRealMetrics(outMetrics);
        int heightPixels = outMetrics.heightPixels;
        int widthPixels = outMetrics.widthPixels;
        //获取内容展示部分的高度
        outMetrics = new DisplayMetrics();
        display.getMetrics(outMetrics);
        int heightPixels2 = outMetrics.heightPixels;
        int widthPixels2 = outMetrics.widthPixels;
        int w = widthPixels-widthPixels2;
        int h = heightPixels-heightPixels2;
        System.out.println("~~~~~~~~~~~~~~~~h:"+h);
        return  w>0||h>0;//竖屏和横屏两种情况。
    }
    
}

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

公众号:Android开发进阶

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

你可能感兴趣的:(Android UI进阶之旅9--Material Design之沉浸式设计)