Android异形屏适配全攻略:从DisplayCutout到华为兼容性实战 1. 项目概述从“一刀切”到“量体裁衣”的屏幕适配新挑战作为一名在移动端开发一线摸爬滚打了十多年的老兵我见证了Android屏幕从最初的几种标准分辨率发展到如今“百花齐放”甚至“奇形怪状”的历程。早期我们谈屏幕适配核心是解决不同分辨率、不同像素密度density下的布局缩放问题那更像是一个“比例缩放”的数学题。但自从“全面屏”概念兴起特别是各种异形屏Notch Screen成为主流后屏幕适配的命题彻底变了。它不再仅仅是缩放而是变成了如何在屏幕的“非规则区域”与应用的“规则内容”之间找到和谐共处的平衡点。今天要聊的就是这个让不少开发者头疼的“异形屏适配”我会结合大量实战经验把刘海屏、水滴屏、挖孔屏这些“异形”背后的适配逻辑、具体操作以及那些官方文档里不会写的“坑”给你掰开揉碎了讲清楚。简单来说异形屏适配的核心目标就一个让你的应用内容能够智能地避开屏幕的缺口Notch或摄像头区域同时又能充分利用屏幕的额外显示空间实现真正的“沉浸式”体验。这听起来简单做起来却需要你对系统特性、厂商差异和设计原则有深刻的理解。无论是刚入行的新手还是遇到过适配难题的中高级开发者这篇从原理到实操、从通用方案到厂商定制的深度解析都能帮你建立起一套完整的适配知识体系让你下次面对任何新奇的屏幕形态时都能从容应对。2. 异形屏类型深度解析与设计影响在动手写代码之前我们必须先搞清楚我们面对的都是些什么“对手”。不同的异形屏形态其设计意图、对内容的遮挡影响以及系统的处理策略都有细微差别理解这些是制定正确适配策略的前提。2.1 主流异形屏形态及其特点目前市面上主流的异形屏可以归纳为三大类它们并非凭空出现而是手机厂商在追求极致屏占比道路上与前置摄像头、听筒等硬件模块妥协后的不同解决方案。1. 刘海屏Notch Display这是最早大规模普及的异形屏形态以某品牌2017年的旗舰机为代表。其特点是在屏幕顶部中央有一个明显的矩形或圆角矩形凹陷区域用于集中放置前置摄像头、听筒、光线距离传感器等组件。设计影响刘海区域会侵占状态栏Status Bar的部分空间。对于未适配的应用系统默认行为通常是将状态栏区域整体拉高变黑应用内容从刘海下方开始布局这会导致屏幕有效显示高度减少。适配后应用内容可以延伸到刘海两侧实现顶部区域的内容最大化利用。适配核心关键在于处理好状态栏的高度和内容与刘海区域的避让关系。2. 水滴屏Water Drop Display/ 珍珠屏可以看作是刘海屏的进化版将刘海区域的面积缩小为一个类似水滴或珍珠形状的小型凹陷通常只容纳一颗前置摄像头。设计影响相比刘海屏水滴屏对屏幕的侵入感更小遮挡的区域也更少。其适配逻辑与刘海屏基本一致但因为它更“小”所以很多情况下即使不做精细适配视觉上的违和感也不会像大刘海那样强烈。但这绝不意味着可以忽略适配。适配核心与刘海屏类似但需要更精细的圆角处理确保内容不会紧贴水滴的弧形边缘。3. 挖孔屏Punch-Hole Display这是当前更主流的方案包括单挖孔和双挖孔药丸屏。它在屏幕左上角、右上角或中央直接“挖”出一个圆形或椭圆形孔洞来放置摄像头。设计影响挖孔屏对屏幕的侵入是“点”状的而非“条”状的。它可能直接覆盖在应用的内容区域而不是状态栏。例如一个位于左上角的挖孔可能会遮挡住应用工具栏的返回按钮或标题。这是挖孔屏适配最需要警惕的地方。适配核心重点从“状态栏适配”转向了“内容区域避障”。需要确保关键交互元素和内容不会被摄像头孔洞遮挡。注意除了以上三种还有升降摄像头、屏下摄像头等方案它们从物理上消除了屏幕缺口不属于软件适配范畴。但屏下摄像头区域可能存在显示精度差异也需要注意。2.2 异形屏带来的核心设计挑战理解形态后我们要明确适配到底要解决哪些具体问题内容遮挡这是最直接的问题。状态栏图标、标题栏按钮、关键文本或图片可能被缺口挡住导致功能不可用或信息不全。视觉断裂背景图片或颜色延伸到缺口区域时会被硬生生切断破坏设计的整体性和沉浸感。交互冲突如果缺口区域恰好覆盖了可点击的按钮虽然可能看不到但该区域的触摸事件仍然是有效的可能导致误操作或点击无响应因为用户看不到按钮状态。兼容性差异不同Android版本、不同手机厂商如华为、小米、OPPO、vivo等对异形屏的系统和接口支持存在差异需要针对性处理。3. Android官方沉浸式布局适配方案详解从Android 4.4API 19引入setSystemUiVisibility到Android 11API 30强化边衬区APIGoogle提供了一套逐步演进的方案来应对异形屏。我们重点看目前最主流、最推荐的适配方式。3.1 使用WindowInsetsController与边衬区DisplayCutout对于Android 9API 28及以上版本DisplayCutout类的引入是异形屏适配的里程碑。它允许应用获取到屏幕缺口的确切位置和形状信息。第一步启用全屏布局要获取边衬区信息首先需要将内容布局到系统栏状态栏、导航栏之下。// 在Activity的onCreate中调用setContentView之后 if (Build.VERSION.SDK_INT Build.VERSION_CODES.R) { // Android 11 推荐方式 window.insetsController?.let { controller - controller.hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()) controller.systemBarsBehavior WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } } else { // Android 9-10 的兼容方式 Suppress(DEPRECATION) window.decorView.systemUiVisibility (View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) }这段代码的作用是让内容全屏显示同时隐藏状态栏和导航栏并且通过LAYOUT_系列标志确保布局会延伸到系统栏区域。第二步获取DisplayCutout信息并应用避让在布局延伸到屏幕边缘后我们需要通过WindowInsets来获取缺口信息并给内容设置相应的内边距Padding。// 在您的根布局View如ConstraintLayout、FrameLayout上设置监听 ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, windowInsets - val cutout if (Build.VERSION.SDK_INT Build.VERSION_CODES.P) { windowInsets.displayCutout } else { null } if (cutout ! null) { // 获取安全区域即系统建议不放置关键内容的区域 val safeInsetTop cutout.safeInsetTop val safeInsetBottom cutout.safeInsetBottom val safeInsetLeft cutout.safeInsetLeft val safeInsetRight cutout.safeInsetRight // 方案A为整个根布局设置Padding避开所有不安全区域 view.setPadding( safeInsetLeft, safeInsetTop, safeInsetRight, safeInsetBottom ) // 方案B更精细的控制只为顶部工具栏设置Margin // toolbar.layoutParams (toolbar.layoutParams as ViewGroup.MarginLayoutParams).apply { // topMargin safeInsetTop // } } // 消费掉insets返回更新后的insets windowInsets }这里有两个关键点safeInsetTop等值系统给出的“安全”内边距表示从屏幕边缘到安全内容区域的距离。对于刘海屏safeInsetTop通常就是刘海的高度。设置Padding还是Margin为根布局设置Padding是最简单粗暴且安全的方法确保所有子View都不会超出安全区。但在复杂布局中这可能影响背景图的展示。更精细的做法是只为顶部AppBar、底部导航栏等特定组件设置Margin。第三步处理LAYOUT_IN_DISPLAY_CUTOUT_MODE窗口属性这是Android PAPI 28引入的另一个关键属性它定义了窗口如何与缺口区域交互。它有三种模式LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT默认行为。在竖屏下内容会避开刘海在全屏横屏下内容可能会延伸到刘海区域。LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES允许内容延伸到短边的缺口区域即竖屏时的顶部刘海横屏时的左右侧刘海。这是实现“沉浸式”效果最常用的模式。LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER永远不允许内容延伸到缺口区域。通常我们在主题Theme或代码中设置为SHORT_EDGES!-- styles.xml -- style nameTheme.Immersive parentTheme.MaterialComponents.DayNight.NoActionBar item nameandroid:windowLayoutInDisplayCutoutModeshortEdges/item /style// 或者在代码中动态设置 if (Build.VERSION.SDK_INT Build.VERSION_CODES.P) { val params window.attributes params.layoutInDisplayCutoutMode WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES window.attributes params }实操心得很多开发者只设置了windowLayoutInDisplayCutoutMode为shortEdges发现内容确实延伸到刘海下面了但状态栏图标和文字与刘海重叠了非常难看。这是因为你只完成了“允许延伸”但没有完成“安全避让”。必须结合使用shortEdges模式和WindowInsets监听来设置Padding/Margin才能达到完美的沉浸式效果。前者是“拿到通行证”后者是“规划行走路线”。3.2 针对不同场景的适配策略选择不是所有页面都需要全屏沉浸。你需要根据页面类型选择策略沉浸式页面如视频播放、游戏、全屏图片浏览策略采用上述全方案。设置shortEdges模式隐藏状态栏/导航栏监听WindowInsets并为内容设置顶部Padding等于刘海高度。效果视频画面充满整个屏幕但字幕、播放控件被约束在安全区域内不会被遮挡。常规内容页面如新闻列表、设置页策略通常不需要特殊处理。系统默认行为DEFAULT模式已经能很好地工作状态栏保持正常显示并容纳刘海应用内容从状态栏下方开始。你只需要确保你的主题使用了NoActionBar并使用Toolbar或MaterialToolbar作为应用栏并为其设置app:layout_scrollFlags等属性配合CoordinatorLayout实现滚动折叠效果时注意监听WindowInsets为Toolbar增加topMargin。对话框Dialog和浮层PopupWindow特别注意对话框默认可能会被限制在安全区域内导致在刘海屏上显示不全。需要为对话框的Window也设置layoutInDisplayCutoutMode。dialog.window?.let { window - if (Build.VERSION.SDK_INT Build.VERSION_CODES.P) { val attributes window.attributes attributes.layoutInDisplayCutoutMode WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES window.attributes attributes } // 同样可能需要为对话框的内容View设置Padding来避让刘海 }4. 华为手机异形屏适配特别注意事项国内安卓生态的复杂性在于各大厂商对Android标准的实现和扩展不尽相同。华为HarmonyOS/EMUI在异形屏适配上有一些自己的逻辑和接口如果不注意可能会导致在华为机型上出现显示异常。4.1 华为的“隐藏显示区域”与notch_support配置华为早期机型如P20系列引入了一个名为“隐藏显示区域”的设置。用户可以在系统设置中手动选择是否让应用使用刘海区域。为了兼容这个特性华为要求应用在AndroidManifest.xml中声明一个Meta-data。必须添加的配置!-- AndroidManifest.xml 的 application 节点下 -- meta-data android:nameandroid.notch_support android:valuetrue/这个声明告诉华为系统“本应用已对刘海屏进行适配请允许内容延伸到刘海区域”。如果没有这个声明在部分华为机型上即使你在代码中设置了shortEdges模式系统也可能强制将你的应用布局在安全区内导致顶部出现黑边。踩坑记录我曾经遇到一个Bug应用在小米、OPPO上全屏显示正常唯独在华为Mate 30 Pro上顶部有黑边。排查了半天代码最后发现就是漏了这个notch_support的meta-data。加上之后立即正常。这是一个典型的厂商兼容性问题务必牢记。4.2 华为专属API的识别与使用备选方案除了标准API华为也提供了一套自己的接口来查询刘海信息。原则上优先使用标准的DisplayCutoutAPI。华为的API可以作为在低版本系统上的一个备选查询手段。import android.provider.Settings // 注意此方法已不推荐仅作了解 fun hasNotchInScreen(context: Context): Boolean { return try { val cl context.classLoader val HwNotchSizeUtil cl.loadClass(com.huawei.android.util.HwNotchSizeUtil) val method HwNotchSizeUtil.getMethod(hasNotchInScreen) method.invoke(HwNotchSizeUtil) as Boolean } catch (e: Exception) { e.printStackTrace() false } } fun getNotchSize(context: Context): IntArray { return try { val cl context.classLoader val HwNotchSizeUtil cl.loadClass(com.huawei.android.util.HwNotchSizeUtil) val method HwNotchSizeUtil.getMethod(getNotchSize) method.invoke(HwNotchSizeUtil) as IntArray } catch (e: Exception) { e.printStackTrace() intArrayOf(0, 0) // [width, height] } }重要提示使用反射调用厂商API存在兼容性风险和稳定性风险。随着华为转向HarmonyOS这些API的可用性也在变化。最稳健的做法依然是依赖标准的WindowInsets和DisplayCutout并确保声明了notch_support。4.3 华为手机上的常见UI问题排查状态栏颜色异常在沉浸式页面你隐藏了状态栏但有时会发现状态栏区域并非完全透明而是呈现半透明黑色或白色。这通常是因为主题中设置了android:statusBarColor或者页面背景色未正确延伸到状态栏下。检查并确保你的主题使用了透明状态栏item nameandroid:statusBarColorandroid:color/transparent/item item nameandroid:windowTranslucentStatustrue/item !-- 可选根据效果调整 --导航栏遮挡内容在全屏模式下虽然隐藏了导航栏但华为手机的侧滑返回手势从屏幕左右边缘向内滑区域可能会与应用自身的侧滑抽屉导航冲突。你需要使用WindowInsets来获取手势区域的insetssystemGestures并相应调整你的触摸事件逻辑或布局边界。5. 实战演练为一个视频播放页进行全流程适配让我们通过一个具体的例子将上述所有知识点串联起来。假设我们要为一个视频播放Activity做沉浸式异形屏适配。步骤1基础主题与窗口设置首先在res/values/styles.xml中定义一个沉浸式主题。style nameTheme.VideoPlayer parentTheme.MaterialComponents.DayNight.NoActionBar !-- 关键允许内容延伸到短边的刘海区域 -- item nameandroid:windowLayoutInDisplayCutoutModeshortEdges/item !-- 关键设置状态栏透明 -- item nameandroid:statusBarColorandroid:color/transparent/item !-- 可选设置导航栏透明 -- item nameandroid:navigationBarColorandroid:color/transparent/item !-- 防止半透明导航栏在低版本上的兼容问题 -- item nameandroid:windowTranslucentNavigationtrue/item /style在AndroidManifest.xml中为该Activity应用此主题。activity android:name.VideoPlayerActivity android:themestyle/Theme.VideoPlayer /步骤2布局文件准备activity_video_player.xml布局采用ConstraintLayout作为根视图包含一个全屏的SurfaceView/TextureView用于播放视频和一个覆盖在上层的控制面板control_panel包含播放/暂停、进度条、标题等。androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:apphttp://schemas.android.com/apk/res-auto android:idid/root_container android:layout_widthmatch_parent android:layout_heightmatch_parent android:backgroundcolor/black android:fitsSystemWindowsfalse !-- 必须为false我们自己处理insets -- SurfaceView android:idid/video_surface android:layout_width0dp android:layout_height0dp app:layout_constraintBottom_toBottomOfparent app:layout_constraintEnd_toEndOfparent app:layout_constraintStart_toStartOfparent app:layout_constraintTop_toTopOfparent / LinearLayout android:idid/control_panel android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationvertical android:background#CC000000 !-- 半透明黑色背景 -- android:padding16dp app:layout_constraintBottom_toBottomOfparent app:layout_constraintEnd_toEndOfparent app:layout_constraintStart_toStartOfparent !-- 控制按钮、进度条等子View -- /LinearLayout androidx.appcompat.widget.Toolbar android:idid/toolbar android:layout_widthmatch_parent android:layout_height?attr/actionBarSize android:background#CC000000 app:layout_constraintTop_toTopOfparent app:title视频标题 / /androidx.constraintlayout.widget.ConstraintLayout步骤3在Activity中处理WindowInsets这是适配的核心代码写在VideoPlayerActivity.onCreate中。override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_video_player) // 1. 启用全屏模式兼容不同API版本 enableFullScreenMode() // 2. 获取根布局并应用WindowInsets监听 val rootContainer findViewByIdConstraintLayout(R.id.root_container) ViewCompat.setOnApplyWindowInsetsListener(rootContainer) { view, insets - // 获取系统栏和刘海的安全区域 val systemBars insets.getInsets(WindowInsetsCompat.Type.systemBars()) val displayCutout insets.getInsets(WindowInsetsCompat.Type.displayCutout()) // 计算最终的安全内边距取系统栏和刘海区域的最大值 val safeInsetTop max(systemBars.top, displayCutout.top) val safeInsetBottom max(systemBars.bottom, displayCutout.bottom) // 左右通常取系统栏和刘海的最大值但横屏时需特别注意 val safeInsetLeft max(systemBars.left, displayCutout.left) val safeInsetRight max(systemBars.right, displayCutout.right) // 3. 为控制面板和工具栏设置Margin避开不安全区域 // 视频播放SurfaceView保持全屏不受影响 val controlPanel findViewByIdLinearLayout(R.id.control_panel) val toolbar findViewByIdToolbar(R.id.toolbar) (controlPanel.layoutParams as ConstraintLayout.LayoutParams).apply { bottomMargin safeInsetBottom leftMargin safeInsetLeft rightMargin safeInsetRight } (toolbar.layoutParams as ConstraintLayout.LayoutParams).apply { topMargin safeInsetTop leftMargin safeInsetLeft rightMargin safeInsetRight } // 4. 请求重新布局 view.requestLayout() // 返回消费后的insets WindowInsetsCompat.CONSUMED } // 5. 请求应用一次WindowInsets确保监听器被触发 ViewCompat.requestApplyInsets(rootContainer) } SuppressLint(ObsoleteSdkInt) private fun enableFullScreenMode() { if (Build.VERSION.SDK_INT Build.VERSION_CODES.R) { window.insetsController?.let { it.hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()) it.systemBarsBehavior WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } } else { Suppress(DEPRECATION) window.decorView.systemUiVisibility (View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) } // 动态设置cutout模式确保覆盖主题设置如果需要 if (Build.VERSION.SDK_INT Build.VERSION_CODES.P) { val params window.attributes params.layoutInDisplayCutoutMode WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES window.attributes params } }步骤4处理横竖屏切换横竖屏切换时WindowInsets会发生变化我们的监听器会自动响应。但需要注意横屏时刘海可能出现在左侧或右侧短边displayCutout的left和right值会相应变化。上述代码中通过max(systemBars.left, displayCutout.left)已经能很好地处理。对于视频播放横屏全屏是常见需求此方案能确保视频画面充满屏幕而控制条自动避开左侧或右侧的刘海区域。6. 常见问题排查与调试技巧实录即使按照最佳实践操作在实际开发中还是会遇到各种稀奇古怪的问题。这里我整理了一份“排坑指南”。6.1 问题速查表问题现象可能原因排查步骤与解决方案顶部有黑边内容未延伸至刘海1. 未设置windowLayoutInDisplayCutoutMode为shortEdges。2. 华为手机未在Manifest中声明android.notch_support。3. 主题或代码中设置了fitsSystemWindows”true”。1. 检查主题和代码中的layoutInDisplayCutoutMode设置。2. 检查AndroidManifest.xml是否有meta-data android:name”android.notch_support” android:value”true”/。3. 将根布局的android:fitsSystemWindows设为false并改用WindowInsets监听。状态栏图标/文字与刘海重叠设置了shortEdges但未处理WindowInsets未给顶部内容增加安全边距。为Toolbar或顶部View通过WindowInsets设置topMargin或paddingTop。全屏下底部导航栏偶尔闪现使用了IMMERSIVE模式但未正确设置systemBarsBehavior或手势操作触发。在Android R使用BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE。这是预期行为提示用户导航栏位置。对话框显示不完整被刘海截断对话框Window未设置layoutInDisplayCutoutMode。为Dialog的Window也设置attributes.layoutInDisplayCutoutMode LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES。横屏时内容被左侧/右侧刘海遮挡横屏时未正确处理displayCutout的left和right安全区域。在OnApplyWindowInsetsListener中确保为左右两侧的内容如返回按钮、菜单设置leftMargin/rightMargin或paddingStart/paddingEnd。获取到的safeInsetTop为01. 设备无刘海。2. 未正确进入全屏模式或fitsSystemWindows干扰。3. 监听器设置时机太早视图未附加。1. 打印displayCutout是否为null。2. 确保全屏标志已设置且fitsSystemWindows”false”。3. 在onStart()或onResume()中调用ViewCompat.requestApplyInsets(view)。6.2 调试与验证技巧开启“开发者选项”中的“模拟具有凹口的显示屏”这是最强大的调试工具。在手机的开发者选项里你可以强制为任何应用模拟出不同尺寸和位置的刘海无需拥有真机即可测试各种情况。使用Layout Inspector查看视图边界在Android Studio的Layout Inspector中你可以清晰地看到每个View的边界框。检查你的Toolbar或顶部容器的实际位置是否包含了安全内边距。日志输出关键值在OnApplyWindowInsetsListener中打印出systemBars和displayCutout的各个inset值确认它们是否符合预期。Log.d(NotchDebug, SystemBars: L${systemBars.left}, T${systemBars.top}, R${systemBars.right}, B${systemBars.bottom}) Log.d(NotchDebug, DisplayCutout: L${displayCutout.left}, T${displayCutout.top}, R${displayCutout.right}, B${displayCutout.bottom})为安全区域可视化在调试阶段可以临时为根布局设置一个半透明的背景色来直观看到系统计算出的安全区域范围。rootContainer.setBackgroundColor(Color.argb(50, 255, 0, 0)) // 半透明红色运行后红色区域就是你的内容区域看看它是否避开了刘海和系统栏。6.3 关于兼容性的终极建议最低API级别如果你的minSdkVersion低于Android 9API 28那么DisplayCutoutAPI不可用。对于这些旧版本异形屏问题不突出通常可以忽略或者使用厂商特定的兼容库如华为的但务必做好条件判断。渐进增强采用“渐进增强”的策略。优先保证应用在非异形屏上的正常表现然后利用if (Build.VERSION.SDK_INT Build.VERSION_CODES.P)等条件判断为高版本系统增加沉浸式适配代码。充分测试异形屏适配光靠模拟器不够必须使用真机测试尤其是目标用户群体常用的主流机型如华为、小米、OPPO、vivo的最新款。真机测试能暴露厂商特定行为和细微的UI差异。异形屏适配是现代Android开发者的必修课它考验的是我们对系统UI机制的理解和对细节的掌控。其核心思想始终是尊重系统提供的安全区域指南在追求沉浸体验的同时绝对保障内容的可读性和交互的可用性。从DisplayCutout到WindowInsetsCompat官方提供的工具链已经相当完善结合对厂商特定行为的了解我们完全能够打造出在所有屏幕上都能完美呈现的应用。记住好的适配是让用户感觉不到适配的存在一切都那么自然和舒适。