為什么要屏幕適配?
因?yàn)锳ndroid設(shè)備的碎片化嚴(yán)重厦取,導(dǎo)致app的界面元素在不同分辨率的設(shè)備屏幕尺寸上顯示不一致潮太;
為了讓布局、布局組件虾攻、資源铡买、用戶界面流程,匹配不同設(shè)備屏幕尺寸霎箍;
常見屏幕適配方式:
布局適配
避免寫死控件尺寸奇钞,使用warp_content\match_content;
靈活使用以下屬性設(shè)置:
LinearLayout android:layout_weight="0.5"
RelativeLayout android:layout_centerInParent="true"....
ContraintLayout android:layout_constraintLeft_toLeftOf="parent"...
Percent-support-lib xxx:layout_widgetPercent="30%"
圖片資源適配
.9圖或者SVG圖實(shí)現(xiàn)縮放
備用位圖匹配不同分辨率
用戶流程適配
根據(jù)業(yè)務(wù)邏輯執(zhí)行不同的跳轉(zhuǎn)邏輯
根據(jù)別名展示不同的界面
例如:手機(jī)和平板適配中就會(huì)采用此方式實(shí)現(xiàn)
限定符適配
分辨率限定符 drawable-hdpi、drawable-xhdpi漂坏,等
尺寸限定符 layout-small(小屏)景埃,layout-large(大屏)媒至,
最小寬度限定符 values-sw360dp,values-sw384dp纠亚,(數(shù)字表示設(shè)備像素密度)
屏幕方向限定符 layout-land(水平)塘慕,layout-port(豎直)
市場(chǎng)劉海屏和水滴屏請(qǐng)參考各自官網(wǎng)適配詳情
自定義View適配
原理:以一個(gè)特定尺寸設(shè)備屏幕分辨率為參考,在View的加載過程中蒂胞,根據(jù)當(dāng)前設(shè)備的實(shí)際屏幕分辨率和參考設(shè)備屏幕分辨率縮放比換算出View控件的目標(biāo)像素图呢,再作用到控件上;
實(shí)現(xiàn)步驟:
一骗随、創(chuàng)建一個(gè)工具類:用來獲取屏幕水平和垂直方向縮放比
public class Utils {
? ? private static Utils instance;
? ? private float mDisplayWidth;
? ? private float mDisplayHeigth;
? ? private float STANDARD_WIDTH = 720;
? ? private float STANDARD_HEIGHT = 1280;
? ? private Utils(Context context) {
? ? ? ? if (mDisplayWidth == 0 || mDisplayHeigth == 0) {
? ? ? ? ? ? // 獲取屏幕實(shí)際寬高
? ? ? ? ? ? WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
? ? ? ? ? ? if (manager != null) {
? ? ? ? ? ? ? ? DisplayMetrics metrics = new DisplayMetrics();
? ? ? ? ? ? ? ? manager.getDefaultDisplay().getMetrics(metrics);
? ? ? ? ? ? ? ? if (metrics.widthPixels > metrics.heightPixels) {//橫屏
? ? ? ? ? ? ? ? ? ? mDisplayWidth = metrics.heightPixels;
? ? ? ? ? ? ? ? ? ? mDisplayHeigth = metrics.widthPixels;
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? mDisplayWidth = metrics.widthPixels;
? ? ? ? ? ? ? ? ? ? mDisplayHeigth = metrics.heightPixels - getStatusBarHeight(context);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? public static Utils getInstance(Context context) {
? ? ? ? if (instance == null) {
? ? ? ? ? ? instance = new Utils(context.getApplicationContext());
? ? ? ? }
? ? ? ? return instance;
? ? }
? ? // 獲取屏幕狀態(tài)欄高度
? ? public int getStatusBarHeight(Context context) {
? ? ? ? int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
? ? ? ? if (resId > 0) {
? ? ? ? ? ? return context.getResources().getDimensionPixelSize(resId);
? ? ? ? }
? ? ? ? return 0;
? ? }
? ? // 獲取水平方向上的縮放比
? ? public float getHorizontalScale() {
? ? ? ? return mDisplayWidth / STANDARD_WIDTH;
? ? }
? ? // 獲取垂直方向上的縮放比
? ? public float getVerticalScale() {
? ? ? ? return mDisplayHeigth / STANDARD_HEIGHT;
? ? }
}
二蛤织、在自定義View中測(cè)量時(shí)實(shí)際使用
public class MyView extends RelativeLayout {
? ? private boolean flag;// 用于標(biāo)記,防止二次測(cè)量
? ? private float scaleX;
? ? private float scaleY;
? ? public MyView(Context context) {
? ? ? ? this(context, null);
? ? }
? ? public MyView(Context context, AttributeSet attrs) {
? ? ? ? this(context, attrs, 0);
? ? }
? ? public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? ? ? //獲取縮放比
? ? ? ? scaleX = Utils.getInstance(getContext()).getHorizontalScale();
? ? ? ? scaleY = Utils.getInstance(getContext()).getVerticalScale();
? ? }
? ? @Override
? ? protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
? ? ? ? if (!flag) {
? ? ? ? ? ? int childCount = getChildCount();
? ? ? ? ? ? if (childCount > 0) {
? ? ? ? ? ? ? ? for (int i = 0; i < childCount; i++) {
? ? ? ? ? ? ? ? ? ? View child = getChildAt(i);
? ? ? ? ? ? ? ? ? ? // 獲取每個(gè)View的Params屬性
? ? ? ? ? ? ? ? ? ? LayoutParams params = (LayoutParams) child.getLayoutParams();
? ? ? ? ? ? ? ? ? ? params.width = (int) (params.width * scaleX);
? ? ? ? ? ? ? ? ? ? params.height = (int) (params.height * scaleY);
? ? ? ? ? ? ? ? ? ? params.leftMargin = (int) (params.leftMargin * scaleX);
? ? ? ? ? ? ? ? ? ? params.rightMargin = (int) (params.rightMargin * scaleX);
? ? ? ? ? ? ? ? ? ? params.topMargin = (int) (params.topMargin * scaleY);
? ? ? ? ? ? ? ? ? ? params.bottomMargin = (int) (params.bottomMargin * scaleY);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? flag = true;
? ? ? ? }
? ? ? ? super.onMeasure(widthMeasureSpec, heightMeasureSpec);
? ? }
}
百分比布局適配
Android提供了Android-percent-support這個(gè)庫鸿染,支持百分比布局指蚜,在一定程度上可以解決屏幕適配的問題
兩種布局:
PercentRelativeLayout和PercentFrameLayout
PercentRelativeLayout繼承RelativeLayout
PercentFrameLayout繼承FrameLayout
官方使用
build.gradle添加:
implementation 'com.android.support:percent:28.0.0'
PercentFrameLayout
<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentFrameLayout
? ? xmlns:android="http://schemas.android.com/apk/res/android"
? ? xmlns:app="http://schemas.android.com/apk/res-auto"
? ? android:layout_width="match_parent"
? ? android:layout_height="match_parent">
? ? <ImageView
? ? ? ? android:layout_width="0dp"
? ? ? ? android:layout_height="0dp"
? ? ? ? app:layout_heightPercent="20%"
? ? ? ? app:layout_widthPercent="50%"
? ? ? ? android:layout_gravity="center"
? ? ? ? android:background="@mipmap/picture"/>
? ? <TextView
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:textSize="16sp"
? ? ? ? android:layout_gravity="center"
? ? ? ? android:text="孩子"
? ? ? ? android:gravity="center"/>
</android.support.percent.PercentFrameLayout>
根據(jù)UI的設(shè)計(jì)原型在不同的設(shè)備屏幕上顯示效果都是一樣的;
下面就是重點(diǎn)了涨椒,自己實(shí)現(xiàn)谷歌官方百分比布局
一摊鸡、values文件夾下創(chuàng)建自定義屬性attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
? ? <declare-styleable name="PercentLayout">
? ? ? ? <attr name="widthPercent" format="float"></attr>
? ? ? ? <attr name="heightPercent" format="float"></attr>
? ? ? ? <attr name="marginLeftPercent" format="float"></attr>
? ? ? ? <attr name="marginRightPercent" format="float"></attr>
? ? ? ? <attr name="marginTopPercent" format="float"></attr>
? ? ? ? <attr name="marginBottomPercent" format="float"></attr>
? ? </declare-styleable>
</resources>
二、創(chuàng)建自定義布局蚕冬,并解析自定義屬性
public class PercentLayout extends RelativeLayout {
public PercentLayout(Context context) {
? ? this(context, null);
}
public PercentLayout(Context context, AttributeSet attrs) {
? ? this(context, attrs, 0);
}
public PercentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
? ? super(context, attrs, defStyleAttr);
}
? ? public static class PercentParams extends RelativeLayout.LayoutParams {
? ? ? ? private float widthPercent;
? ? ? ? private float heightPercent;
? ? ? ? private float marginLeftPercent;
? ? ? ? private float marginRightPercent;
? ? ? ? private float marginTopPercent;
? ? ? ? private float marginBottomPercent;
? ? ? ? public PercentParams(Context c, AttributeSet attrs) {
? ? ? ? ? ? super(c, attrs);
? ? ? ? ? ? // 解析自定義屬性
? ? ? ? ? ? TypedArray array = c.obtainStyledAttributes(attrs, R.styleable.PercentLayout);
? ? ? ? ? ? widthPercent = (float) array.getFloat(R.styleable.PercentLayout_widthPercent, 0);
? ? ? ? ? ? heightPercent = (float) array.getFloat(R.styleable.PercentLayout_heightPercent, 0);
? ? ? ? ? ? marginLeftPercent = (float) array.getFloat(R.styleable.PercentLayout_marginLeftPercent, 0);
? ? ? ? ? ? marginRightPercent = (float) array.getFloat(R.styleable.PercentLayout_marginRightPercent, 0);
? ? ? ? ? ? marginTopPercent = (float) array.getFloat(R.styleable.PercentLayout_marginTopPercent, 0);
? ? ? ? ? ? marginBottomPercent = (float) array.getFloat(R.styleable.PercentLayout_marginBottomPercent, 0);
? ? ? ? ? ? array.recycle();
? ? ? ? }
? ? }
}
三免猾、循環(huán)測(cè)量子view并設(shè)置子view的params值;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
? ? // 獲取父容器寬高
? ? int widthSize = MeasureSpec.getSize(widthMeasureSpec);
? ? int heighSize = MeasureSpec.getSize(heightMeasureSpec);
? ? // 循環(huán)遍歷子view并設(shè)置params
? ? int childCount = getChildCount();
? ? if (childCount > 0) {
? ? ? ? for (int i = 0; i < childCount; i++) {
? ? ? ? ? ? View child = getChildAt(i);
? ? ? ? ? ? LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
? ? ? ? ? ? // 如果是自定義的百分比屬性
? ? ? ? ? ? if (checkLayoutParams(layoutParams)) {
? ? ? ? ? ? ? ? PercentParams percentParams = (PercentParams) layoutParams;
? ? ? ? ? ? ? ? float widthPercent = percentParams.widthPercent;
? ? ? ? ? ? ? ? float heightPercent = percentParams.heightPercent;
? ? ? ? ? ? ? ? float marginLeftPercent = percentParams.marginLeftPercent;
? ? ? ? ? ? ? ? float marginRightPercent = percentParams.marginRightPercent;
? ? ? ? ? ? ? ? float marginTopPercent = percentParams.marginTopPercent;
? ? ? ? ? ? ? ? float marginBottomPercent = percentParams.marginBottomPercent;
? ? ? ? ? ? ? ? if (widthPercent > 0) layoutParams.width = (int) (widthSize * widthPercent);
? ? ? ? ? ? ? ? if (heightPercent > 0) layoutParams.height = (int) (heighSize * heightPercent);
? ? ? ? ? ? ? ? if (marginLeftPercent > 0)
? ? ? ? ? ? ? ? ? ? layoutParams.leftMargin = (int) (widthSize * marginLeftPercent);
? ? ? ? ? ? ? ? if (marginRightPercent > 0)
? ? ? ? ? ? ? ? ? ? layoutParams.rightMargin = (int) (widthSize * marginRightPercent);
? ? ? ? ? ? ? ? if (marginTopPercent > 0)
? ? ? ? ? ? ? ? ? ? layoutParams.topMargin = (int) (heighSize * marginTopPercent);
? ? ? ? ? ? ? ? if (marginBottomPercent > 0)
? ? ? ? ? ? ? ? ? ? layoutParams.bottomMargin = (int) (heighSize * marginBottomPercent);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private boolean checkLayoutParams(LayoutParams params) {
? ? return params instanceof PercentParams;
}
// 這里一定要重寫此方法囤热,并返回自定義的PercentParams
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
? ? return new PercentParams(getContext(), attrs);
}
四猎提、使用自定義百分比布局
<?xml version="1.0" encoding="utf-8"?>
<com.xxx.uidemo.PercentLayout 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="match_parent"
? ? tools:context=".MainActivity">
? ? <TextView
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:background="@color/colorPrimary"
? ? ? ? android:text="百分比控件"
? ? ? ? app:heightPercent="0.5"
? ? ? ? app:widthPercent="0.5"
? ? ? ? tools:ignore="MissingPrefix" />
</com.xxx.uidemo.PercentLayout>
修改像素密度
修改density(屏幕密度)、scaleDensity(字體縮放比例)旁蔼、densityDpi(每英寸像素點(diǎn)個(gè)數(shù))值-----直接更改系統(tǒng)內(nèi)部對(duì)于目標(biāo)尺寸而言的像素密度锨苏;
原理:布局中不管是dp、sp、pt最終都是通過系統(tǒng)中上面三個(gè)參數(shù)轉(zhuǎn)化為相應(yīng)的px值,只要統(tǒng)一了上面三個(gè)值之景,那么不管什么設(shè)備屏幕都能夠適配;
源碼轉(zhuǎn)化如下:
/frameworks/base/core/java/android/util/TypedValue.java
實(shí)現(xiàn)步驟:
一肯夏、創(chuàng)建修改Density的工具類
public class Density {
? ? private static final float WIDTH = 320;//參考設(shè)備的寬,單位dp犀暑;
? ? private static float appDensity;// 表示屏幕密度驯击;
? ? private static float appScaleDensity;// 表示字體縮放比例;默認(rèn)和appDensity一致
? ? public static void setDensity(final Application application, Activity activity) {
? ? ? ? // 獲取當(dāng)前app的屏幕顯示信息耐亏;
? ? ? ? final DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
? ? ? ? if (appDensity == 0 || appScaleDensity == 0) {
? ? ? ? ? ? // 初始化
? ? ? ? ? ? appDensity = displayMetrics.density;
? ? ? ? ? ? appScaleDensity = displayMetrics.scaledDensity;
? ? ? ? ? ? // 當(dāng)系統(tǒng)字體大小發(fā)生變化后徊都,需要重新對(duì)appScaleDensity進(jìn)行賦值;
? ? ? ? ? ? // 監(jiān)聽系統(tǒng)字體變化回調(diào)
? ? ? ? ? ? application.registerComponentCallbacks(new ComponentCallbacks() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void onConfigurationChanged(Configuration configuration) {
? ? ? ? ? ? ? ? ? ? // 字體發(fā)生變化后广辰,重新賦值
? ? ? ? ? ? ? ? ? ? if (configuration != null && configuration.fontScale > 0) {
? ? ? ? ? ? ? ? ? ? ? ? appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void onLowMemory() {
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? ? ? // 通過參考設(shè)備的寬暇矫,計(jì)算目標(biāo)值density主之、scaleDensity、densityDpi
? ? ? ? float targetDensity = displayMetrics.widthPixels / WIDTH;// 1080/360 = 3.0
? ? ? ? float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
? ? ? ? int targetDensityDpi = (int) (targetDensity * 160);
? ? ? ? // 替換當(dāng)前activity的density李根、scaleDensity槽奕、densityDpi值
? ? ? ? DisplayMetrics dm = activity.getResources().getDisplayMetrics();
? ? ? ? dm.density = targetDensity;
? ? ? ? dm.scaledDensity = targetScaleDensity;
? ? ? ? dm.densityDpi = targetDensityDpi;
? ? }
}
二、在Activity中使用
public class MainActivity extends AppCompatActivity {
? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? // 必須在setContentView方法之前執(zhí)行
? ? ? ? Density.setDensity(getApplication(), this);
? ? ? ? setContentView(R.layout.activity_test);
? ? }
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
? ? xmlns:app="http://schemas.android.com/apk/res-auto"
? ? android:layout_width="match_parent"
? ? android:layout_height="match_parent">
? ? <TextView
? ? ? ? android:id="@+id/text"
? ? ? ? android:layout_width="160dp"
? ? ? ? android:layout_height="160dp"
? ? ? ? android:background="@color/colorAccent"
? ? ? ? android:text="Hello World!"
? ? ? ? app:layout_constraintLeft_toLeftOf="parent"
? ? ? ? app:layout_constraintTop_toTopOf="parent" />
? ? <TextView
? ? ? ? android:id="@+id/text1"
? ? ? ? android:layout_width="160dp"
? ? ? ? android:layout_height="160dp"
? ? ? ? android:background="@color/colorAccent"
? ? ? ? android:text="Hello World!"
? ? ? ? app:layout_constraintLeft_toRightOf="@id/text"
? ? ? ? app:layout_constraintTop_toBottomOf="@id/text" />
</android.support.constraint.ConstraintLayout>
三房轿、當(dāng)有多個(gè)界面時(shí)的用法
a粤攒、抽取基類BaseActivity,在onCreate方法中調(diào)用Density.setDensity(getApplication(), this);
b囱持、實(shí)現(xiàn)application實(shí)現(xiàn)類夯接,在onCreate方法中監(jiān)聽app所有Activity生命周期并在Activity生命周期onCreate中調(diào)用Density.setDensity(getApplication(), this);如下所示
public class App extends Application {
? ? @Override
? ? public void onCreate() {
? ? ? ? super.onCreate();
? ? ? ? registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onActivityCreated(Activity activity, Bundle bundle) {
? ? ? ? ? ? ? ? Density.setDensity(App.this,activity);
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onActivityStarted(Activity activity) {
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onActivityResumed(Activity activity) {
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onActivityPaused(Activity activity) {
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onActivityStopped(Activity activity) {
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onActivityDestroyed(Activity activity) {
? ? ? ? ? ? }
? ? ? ? });
? ? }
}
劉海屏適配
Android官方9.0劉海屏適配策略
如果時(shí)非全屏模式(有狀態(tài)欄),則app不受劉海屏影響纷妆,劉海屏的高就是狀態(tài)欄高度盔几;
全屏模式,app未適配劉海屏掩幢,系統(tǒng)會(huì)對(duì)界面做特殊處理逊拍,豎屏下內(nèi)容區(qū)域下移,橫屏下內(nèi)容區(qū)域右移际邻;
所以說適配劉海屏只是在全屏模式下做適配
適配原理:首先app界面設(shè)置全屏模式顺献,然后設(shè)置內(nèi)容區(qū)域延伸到劉海區(qū);
代碼實(shí)現(xiàn)邏輯:
public class TestActivity extends AppCompatActivity {
? ? @Override
? ? protected void onCreate(@Nullable Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? // 1枯怖、設(shè)置全屏模式
? ? ? ? requestWindowFeature(Window.FEATURE_NO_TITLE);
? ? ? ? Window window = getWindow();
? ? ? ? window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
? ? ? ? // 2、判斷手機(jī)是否是劉海屏
? ? ? ? boolean hasDisplayCutout = hasDisplayCutout(window);
? ? ? ? if (hasDisplayCutout) {
? ? ? ? ? ? // 3能曾、設(shè)置內(nèi)容區(qū)域延伸至劉海區(qū)域
? ? ? ? ? ? WindowManager.LayoutParams layoutParams = window.getAttributes();
? ? ? ? ? ? /*
? ? ? ? ? ? public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;//默認(rèn)模式度硝,全屏模式下,內(nèi)容區(qū)域向下移動(dòng)寿冕,非全屏不受影響
? ? ? ? ? ? public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;// 不管是否全屏蕊程,內(nèi)容區(qū)域不能延伸至劉海區(qū)
? ? ? ? ? ? public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1;//允許內(nèi)容區(qū)域延伸至劉海區(qū)
? ? ? ? ? ? * */
? ? ? ? ? ? layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
? ? ? ? ? ? window.setAttributes(layoutParams);
? ? ? ? ? ? // 4、設(shè)置沉浸式
? ? ? ? ? ? int flag = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
? ? ? ? ? ? int visibility = window.getDecorView().getSystemUiVisibility();
? ? ? ? ? ? visibility |= flag;
? ? ? ? ? ? window.getDecorView().setSystemUiVisibility(visibility);
? ? ? ? }
? ? ? ? setContentView(R.layout.activity_test);
? ? }
? ? private boolean hasDisplayCutout(Window window) {
? ? ? ? DisplayCutout displayCutout;
? ? ? ? View rootView = window.getDecorView();
? ? ? ? WindowInsets windowInsets = rootView.getRootWindowInsets();
? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && windowInsets != null) {
? ? ? ? ? ? displayCutout = windowInsets.getDisplayCutout();
? ? ? ? ? ? if (displayCutout != null) {
? ? ? ? ? ? ? ? if (displayCutout.getBoundingRects() != null && displayCutout.getBoundingRects().size() > 0 && displayCutout.getSafeInsetTop() > 0) {
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return true;//這里由于使用的是模擬器驼唱,暫時(shí)設(shè)置為true藻茂;
? ? }
}
第一次運(yùn)行未成功,發(fā)現(xiàn)原因玫恳,需要將AppTheme中添加如下屬性:
<item name="windowNoTitle">true</item>
運(yùn)行結(jié)果截圖:
這里備注一下怎么給模擬器設(shè)置劉海屏模式:
開發(fā)者選項(xiàng)中設(shè)置:
真實(shí)開發(fā)時(shí)處理邏輯:
1辨赐、設(shè)置全屏模式
2、判斷手機(jī)廠商
3京办、判斷手機(jī)是否支持劉海屏
4掀序、設(shè)置讓內(nèi)容區(qū)域延伸至劉海屏區(qū)域
5、獲取劉海屏高度
6惭婿、如果有控件被劉海屏遮擋的情況下不恭,特殊處理叶雹,讓此控件向下移動(dòng),移動(dòng)高度就是劉海屏高度换吧;
如遇到如下情況折晦,需要5、6步驟處理沾瓦,下面的button被遮擋了
此時(shí)處理方式:溝通交互設(shè)計(jì)師满着,不讓button顯示在這里,或者讓button下移一個(gè)劉海屏高度的位置
一般劉海屏高度就是狀態(tài)欄高度暴拄;
// 獲取屏幕狀態(tài)欄高度
public int getStatusBarHeight(Context context) {
? ? int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
? ? if (resId > 0) {
? ? ? ? return context.getResources().getDimensionPixelSize(resId);
? ? }
? ? return 0;
}
然后給button設(shè)置marginTop屬性或者為button父布局設(shè)置paddingTop屬性漓滔;
整理了各大廠商劉海屏的適配文檔,請(qǐng)參考
華為:https://devcentertest.huawei.com/consumer/cn/devservice/doc/50114
小米:https://dev.mi.com/console/doc/detail?pId=1341
oppo:https://open.oppomobile.com/service/message/detail?id=61876