敞开生长之旅!这是我参加「日新方案 2 月更文挑战」的第 11 天,点击检查活动概况
前语
简略来说,以前是做app的,然后转去做了终端几年,现在又做回了app,然后就涉及到了全面屏的适配,可是很多年前做的适配也不记得了,所以来重新再探究一遍。
以前做终端的时分,适配?我不知道什么叫适配,就一个机型,想怎样玩就怎样玩,自己便是爹。现在做运用,不好意思,手机厂商才是大爹,咱们都是孙子。
我简略的回忆了一下,其实全面屏的适配一开始是由于刘海屏才开始这条路线,然后就呈现一大堆奇奇怪怪的东西。幸亏谷歌也是做人,在28之后就提出一套标准。
Android P前后
关于Android P,其实也就android 8.0和android 9.0两个版别,由于是从android 8.0开始盛行的,各做各的,然后在9.0的时分google给出了一套标准。
关于Android 9.0也便是28,google推出了DisplayCutout,它一致了android凹凸屏的处理,运用起来也很便利。
WindowManager.LayoutParams wlp = getWindow().getAttributes();
wlp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(wlp);
给WindowManager.LayoutParams设置layoutInDisplayCutoutMode就行,是不是很简略。
它有几个参数可供挑选
(1)LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:默许值,一般作用和LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER相同。
(2)LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES:内容显现到凹凸屏区域。
(3)LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER:内容不会显现到凹凸屏区域。
关于Android 28以下的适配
这个比较费事,由于在28以下是没有layoutInDisplayCutoutMode的,所以要独自去调,网上也有很多说怎么去对不同的厂商去做适配,但其实这东西仍是要调的。哪怕你是相同的机型,不同的体系版别都可能会发生不同的作用,没错,便是这么恐惧。基本都是只能做if-else独自对不同的机型做适配。要么便是让28以下的一致不做全面屏的作用,比方说把内容显现到凹凸屏区域,你就判断在28的时分不做这种操作,但一般不是你说的算,多多少少仍是需要做适配,只能具体状况具体调试。
对不同的场景做适配
你觉得你说你就对28做适配,28以下就不管了,我就设置layoutInDisplayCutoutMode一行代码就行。可事情哪有这么简略。
体系的Bar首要分为3种,一种是在屏幕上方的状态栏,一种是在屏幕底端的导航栏,仍是一直是仿IOS的底部横条代替导航栏,这在和导航栏一同剖析但会有少许不同。
而这个过程中又会区分为横屏和竖屏的状况,多少也会又少许差异,当然我也没办法把全部特别的常见罗列出来。不同的手机厂商之间也会存在有不同的状况,还有上面说的android28前后,这儿首要是对android28之后进行剖析。
状态栏
假设要完成全屏显现的作用,咱们要怎么去对状态栏做适配。
为了便利调试,我把window的色彩设置为橙色,把布局的色彩设置成绿色
<style name="TestTheme" parent="@android:style/Theme.Material.Light.NoActionBar.Fullscreen" >
<item name="android:windowBackground">@android:color/holo_orange_light</item>
</style>
<activity
android:name=".TestActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenSize|screenLayout"
android:theme="@style/TestTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#336655"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用于参阅方位"
/>
</FrameLayout>
然后咱们直接运行看看作用
上面状态栏的色彩其实是我的桌面布景,这儿看不太清楚,我放一张我桌面的布景上来
能看到,内容是不会显现在状态栏的空间的。依据上面说到的,咱们用layoutInDisplayCutoutMode试试
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WindowManager.LayoutParams wlp = getWindow().getAttributes();
wlp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(wlp);
}
}
}
看看作用
能看到状态栏显现橙色,这说明window的内容现已能覆盖到状态栏了,可是显现的内容仍是没上去。
难道这个特点不可?当然不是。这个不知道怎样解释好,你能够简略了解成窗口是现已能显现到状态栏的区域了,可是view由于某些默许的装备导致距离顶部有必定的距离。
相信咱们多多少少听过沉浸形式,我之前写的软键盘冲突也有涉及到一点这块,view有一个办法SystemUiVisibility,它能够设置一些特点,其实这是一个int值的flags,你把它幻想成window的flags就好了解多了。
通过setSystemUiVisibility办法,咱们对View做一些装备,就按网上写的,沉浸形式
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WindowManager.LayoutParams wlp = getWindow().getAttributes();
wlp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(wlp);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
}
看看作用
能够看到,内容就正常显现到上面了。我觉得讲得现已挺详细了,好,那提两个问题:假设我不设layoutInDisplayCutoutMode,只设View的SystemUiVisibility,能不能显现到状态栏的区域?第二个,我设了layoutInDisplayCutoutMode,是不是这个window里面的一切view都必须设置SystemUiVisibility才能把内容显现到状态栏区域?
这个是完成一个把内容显现到状态栏的作用,还有其它作用比方设置状态栏色彩或者什么的,这儿就不讲了,但要注意,假设你在设置某些作用的过程中,没作用,能够考虑一下是不是手机厂商造成的,多试几个厂商。
对了,还有横屏的状况,横屏的状况下状态栏仍是在顶部,可是刘海区域(凹凸区域)在侧边,layoutInDisplayCutoutMode是对侧边的凹凸区域收效。所以要知道它不是针对状态栏的,是针对凹凸区域的。
导航栏和底部横条
这个就比状态栏费事一些。这儿就首要以横屏的状况去解说。横屏的状况下导航栏一共有3种显现状况,例如小米的横条,便是显现在底部,其它手机的导航栏便是显现在侧边,还有一种是侧边的状况下,不管你怎样转屏,都会固定显现在右边。
导航栏没有凹凸区域,所以不需要用到windoow lp的layoutInDisplayCutoutMode,咱们一般都能直接通过view的SystemUiVisibility办法去装备完成它的一个想要的作用。
能够先看看SystemUiVisibility能设置的一些常用的flags
public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 体系UI(状态栏导航栏)显现
public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; // 低沉形式(便是类似于变暗等作用)
public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; // 躲藏导航栏和横条
public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; // 全屏形式,体系UI会被躲藏
public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; // 安稳布局
public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; // 对窗口收效SYSTEM_UI_FLAG_HIDE_NAVIGATION
public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; // 对窗口收效SYSTEM_UI_FLAG_FULLSCREEN
public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; // 让SYSTEM_UI_FLAG_HIDE_NAVIGATION失效
public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; // 同上相反
关于SYSTEM_UI_FLAG_LAYOUT_STABLE安稳布局,官方有一段注释是这么说的,假设指定SYSTEM_UI_FLAG_LAYOUT_FULLSEEN和SYSTEM_UI-FLAG_LAYOUT _HIDE_NAVIGATION,则能够运用安稳的布局转换到SYSTEM_UI_FLAG_FULLSCREEN和SYSTEM _UI_FLAG-HIDE_NAVIGATION。(请注意,应防止独自运用SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION。)假设已将窗口标志WindowManager.LayoutParams.FLAG_FULLSCREEN设置为躲藏状态栏(而不是运用SYSTEM.UI_FLAG_FULLSCREEN),则躲藏的状态栏将被视为“安稳”状态。这什么意思呢?意思便是这个特点不是死的,它会受其它东西影响到终究的显现作用。说人话便是你用它的话完成的作用就很灵敏,但相同会出BUG的概率也更高。
关于SYSTEM_UI_FLAG_IMMERSIVE让SYSTEM_UI_FLAG_HIDE_NAVIGATION失效,官方有一段注释是这么说的:由于此标志是SYSTEM_UI_FLAG_HIDE_NAVIGATION的修饰符,因而仅当与该标志结合运用时才具有作用。它所体现出来的作用是SYSTEM_UI_FLAG_HIDE_NAVIGATION会躲藏导航栏,但当你手动拉出导航栏之后,就不会再躲藏了。
但这也涉及到不同的手机厂商可能会呈现不同的作用。比方小米,默许的显现会是这样
能够看出,横条是显现在底部,侧边没有导航栏,然后咱们一个一个flags来调看看作用。首要SYSTEM_UI_FLAG_LAYOUT_STABLE这种状况我是不调了,很难去模拟出来。SYSTEM_UI_FLAG_VISIBLE和SYSTEM_UI_FLAG_LOW_PROFILE作用在这儿显现的应该会和默许状况显现的一样。
这儿我会模拟两种场景来说,第一种是纯activity的window的view设置的作用,第二种是window.addview的view设置的作用(我后续会称之为两层window),它们的作用会有少许差异
1. SYSTEM_UI_FLAG_HIDE_NAVIGATION
先看看SYSTEM_UI_FLAG_HIDE_NAVIGATION,假设我设置了SYSTEM_UI_FLAG_HIDE_NAVIGATION
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
能够看到,底部横条现已不显现了。这儿能够多说一句,你们猜猜SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION对view管不管用,能够试试
只设置它能显着看出底部的横条仍是存在的。\可是当用window.addview之后再装备SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION的话,能够看看作用。
代码是这样的
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
addWindow();
}
private void addWindow() {
WindowManager wm = getWindowManager();
WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
wlp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.gravity = Gravity.START | Gravity.TOP;
TextView textView = new TextView(this);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setText("上一层");
textView.setBackgroundResource(R.color.blue);
wm.addView(textView, wlp);
}
}
看看作用,看到差异没有,咱们之前设置的话,它的横条还在,而且是黑色的,现在有一个window然后咱们设置之后发现横条还在,但布景变成通明的了。
2. SYSTEM_UI_FLAG_FULLSCREEN
看看独自设置SYSTEM_UI_FLAG_FULLSCREEN的作用
看得到作用也是一样的。说明SYSTEM_UI_FLAG_FULLSCREEN是不会躲藏底部导航栏的。
但这个特点是不是就没用了,并不是,假设我运用两层window的的状况,不设置这个参数的话,能够看到作用会是这样的:状态栏拉下来不会逗留,会快速的缩回去
但假设我设置了,代码写成这样
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
addWindow();
}
private void addWindow() {
WindowManager wm = getWindowManager();
WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
wlp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.gravity = Gravity.START | Gravity.TOP;
TextView textView = new TextView(this);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setText("上一层");
textView.setBackgroundResource(R.color.blue);
wm.addView(textView, wlp);
textView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
}
}
能看到作用状态栏下拉后就能正常的时间短逗留才消失
3. SYSTEM_UI_FLAG_IMMERSIVE_STICKY
前面说了SYSTEM_UI_FLAG_IMMERSIVE_STICKY是配合SYSTEM_UI_FLAG_HIDE_NAVIGATION的,所以咱们这儿测试的时分,写SYSTEM_UI_FLAG_HIDE_NAVIGATION。
直接是单层window去设置的话是看不出显着作用的,比方代码这样
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
// addWindow();
}
我把第二层给注释掉,然后给第一层设置SYSTEM_UI_FLAG_HIDE_NAVIGATION,不管设不设置SYSTEM_UI_FLAG_IMMERSIVE_STICKY,它在我这台手机,体现都一样。我强调“我这台手机”,是由于可能会不同机型有不同的体现。
然后咱们用两层去做看看作用,代码这样
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
addWindow();
}
private void addWindow() {
WindowManager wm = getWindowManager();
WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
wlp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.gravity = Gravity.START | Gravity.TOP;
TextView textView = new TextView(this);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setText("上一层");
textView.setBackgroundResource(R.color.blue);
wm.addView(textView, wlp);
textView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
}
不设置SYSTEM_UI_FLAG_IMMERSIVE_STICKY的状况下,我这儿没办法录gif(由于点了就会影响),它的作用是,一开始底部横条是躲藏的,可是当点击之后会显现而且显现之后就不再躲藏。
设置之后
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
addWindow();
}
private void addWindow() {
WindowManager wm = getWindowManager();
WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
wlp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
wlp.gravity = Gravity.START | Gravity.TOP;
TextView textView = new TextView(this);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setText("上一层");
textView.setBackgroundResource(R.color.blue);
wm.addView(textView, wlp);
textView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
能够看看作用
看到底部横条会变通明,然后拉出来一段时间之后会自己躲藏起来。PS:看到这儿状态栏缩回去很快,是由于没设置SYSTEM_UI_FLAG_FULLSCREEN
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN的作用是什么的?
这儿我就补贴代码直接让你们看看现象吧,假设不设置的话,体现是这样的
能够看出我切出去之后,再回来,第二层的window会被位移(或者说挤压)再康复。但假设设置的话就不会有这种问题。
总结
做个简略的总结,这儿首要是独自拆开详细讲了状态栏和导航栏的一些适配场景,首要是想让咱们先有个概念,重点是想说,即便google在android28中一致了标准,但仍是会呈现不同的厂商乃至不同的类型,不同的体系版别,所体现出的作用不同。
我这儿也总结了一些手机的体现,由于这儿写得确实有点长,所以就之后独自再些一篇出来总结。