Android 屏幕适配Android 屏幕适配1. 阅读前问题卡Android 屏幕适配1.1 阅读前先看这几个问题1.2 读完后完成这 3 个任务1.2.1 任务 1画出核心概念关系1.2.2 任务 2完成一次换算对比1.2.3 任务 3走读最小适配代码1.3 自检清单2. 为什么 Android 得做屏幕适配3. 做屏幕适配需要了解的概念3.1 像素是什么3.2 屏幕尺寸是什么3.3 屏幕分辨率是什么3.4 屏幕像素密度是什么3.5 屏幕尺寸、屏幕分辨率、屏幕像素密度之间的关系是什么3.6 密度无关像素是什么3.7 密度无关像素 dp 与像素 px 的换算关系是什么3.8 独立比例像素是什么4. 适配方案4.1 为什么要做适配4.2 控件适配4.3 布局适配4.4 今日头条的适配方案5. 总结1. 阅读前问题卡Android 屏幕适配建议先读先读第 3 节的尺寸、分辨率、dpi、dp、sp 及换算关系再进入第 4 节比较控件适配、约束布局与今日头条方案。1.1 阅读前先看这几个问题Android 为什么不能只靠一套固定的 px 尺寸适配所有设备屏幕尺寸、分辨率与像素密度 dpi 分别描述什么它们之间如何换算dp、px、density 之间是什么关系160 dpi 为什么是换算基准图片中的TypedValue.applyDimension()又如何处理COMPLEX_UNIT_PX、COMPLEX_UNIT_DIP与COMPLEX_UNIT_SPsp 与 dp 的差异是什么系统字体大小变化时 TextView 的文字和布局可能怎样变化wrap_content、match_parent、weight、dp 与约束布局分别如何帮助控件和布局适配系统默认 density 与今日头条方案的 targetDensity 各自如何计算二者追求的适配效果有什么不同setCustomDensity()修改了哪些 DisplayMetrics 字段为什么还要监听字体缩放变化今日头条方案有哪些文中明确指出的局限什么情况下约束布局可能更合适1.2 读完后完成这 3 个任务1.2.1 任务 1画出核心概念关系做什么用一张关系图连接屏幕尺寸、分辨率、dpi、密度类型、density、dp、px 与 sp并写出文中的关键换算公式。验证标准图中至少包含 8 个概念箭头方向与文中关系一致并能用 3 句话解释从设备参数到最终 px 渲染的过程。1.2.2 任务 2完成一次换算对比做什么复算文中 1440 px 屏幕、360 dp 设计稿、30 dp 控件的例子对比系统 density 为 3.5 与 targetDensity 为 4 时的结果。验证标准能分别得到 105 px 和 120 px并说明哪个结果保持了 30 / 360 的宽度占比以及原因。1.2.3 任务 3走读最小适配代码做什么逐段说明setCustomDensity()如何保存原始密度、监听字体变化、计算目标密度并更新 Application 与 Activity 的 DisplayMetrics。验证标准能指出density、scaledDensity、densityDpi的赋值来源并说出代码中设计稿基准宽度使用的具体数值。1.3 自检清单我能一句话说明 Android 屏幕适配要解决的问题。我能区分屏幕尺寸、分辨率、dpi、density、dp、px 与 sp。我能写出并使用文中的 dpi、density、dp、px 换算公式。我能解释系统字体设置为什么影响 sp以及它不必然让外层布局整体变大。我能说明系统默认适配与今日头条方案追求的效果差异。我能复述setCustomDensity()修改 DisplayMetrics 的完整流程。我能指出今日头条方案在极端宽高比和多 Activity 策略下的局限。2. 为什么 Android 得做屏幕适配首先我们知道Android 系统是开源的任何用户、开发者、OEM 厂商、运营商都可以对 Android 进行定制导致运行 Android 的设备多种多样这些设备的屏幕尺寸像素密度都不相同尽管我们通过基本的缩放和调整大小能使界面适配不同的屏幕但还是需要进一步优化来确保所有界面能在不同设备上美观的体现出来3. 做屏幕适配需要了解的概念3.1 像素是什么像素是指由图像的小方格组成的这些小方格都有一个明确的位置以及被分配的色彩值小方格颜色和位置就决定了该图形所呈现出来的样子比如小时候家里的电视没有信号的时候会闪出雪花画面画面中一个个跳动的雪花就是像素点3.2 屏幕尺寸是什么屏幕尺寸指的是屏幕对角线的长度单位是英寸1 英寸 2.54 厘米腾讯面试官曾经问过你对哪些尺寸的机型做了适配答首先常见的屏幕尺寸有 2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0 等我主要是对 4.2、5.0、5.5、6.0 这四种屏幕尺寸的机型做适配比如华为小米魅族等这些机型3.3 屏幕分辨率是什么屏幕分辨率指的是在纵横方向的像素点个数屏幕分辨率的单位是 px1 px 就是一个像素点一般我们描述屏幕分辨率是以纵向像素 × 横向像素来描述屏幕分辨率的如 1080 * 1920表示这个机型的屏幕分辨率是宽度方向上有 1080 个像素点长度方向上有 1920 个像素点你知道 Android 手机常见的分辨率吗答常见的 Android 手机屏幕分辨率是 320 x 480、480 * 800、720 * 1290、1090 x 1920UI 设计师的设计图会以 px 作为统一的计量单位。3.4 屏幕像素密度是什么屏幕像素密度指的是每英寸的像素点个数单位是 dpi即 “dot per inch”每英寸有多少个像素点的缩写。假设设备内每英寸有 160 个像素那么该设备的屏幕像素密度就是 160 dpi。屏幕像素密度与屏幕尺寸、屏幕分辨率有关在单一变化条件下屏幕尺寸不变屏幕分辨率越高屏幕像素密度越大屏幕分辨率不变屏幕尺寸越小屏幕像素密度越大Android 手机对每一类手机屏幕大小都有一个相应的屏幕像素密度标准屏幕像素密度mdpi每一寸长度上都有 150 个像素点屏幕像素密度为 160 dpi即称为标准屏幕像素密度mdpi3.5 屏幕尺寸、屏幕分辨率、屏幕像素密度之间的关系是什么由上文我们知道了下面的关系屏幕尺寸 屏幕分辨率 ↓ 计算出屏幕像素密度 dpi ↓ Android 根据 dpi 归类成密度类型 ↓ ldpi / mdpi / hdpi / xhdpi / xxhdpi / xxxhdpi那么屏幕尺寸、屏幕分辨率、屏幕像素密度之间的具体转换关系是什么呢比如说3.6 密度无关像素是什么密度无关像素density-independent pixel简称 dip 或 dp就是我们 Android 开发时的尺寸定位 dp密度无关像素与终端上的物理像素点无关可以保证在不同屏幕也就是不同的屏幕像素密度的设备上显示相同的效果Android 开发时用的尺寸定位是 dp而不是 px。dp 是 Android 特有的定位。场景假如同样都是画一条长度是屏幕宽度一半的线如果采用 px 作为计量定位那么在 480 x 800 的屏幕分辨率的手机上这条线的像素个数应为 240 px在 320 x 480 的屏幕分辨率的手机上这条线的像素个数应为 160 px使用 px 作为计量定位不同的屏幕分辨率上画一条长度为屏幕一半的线对长度尺寸的设置就不同了如果使用 dp 为计量定位因为 dp 是密度无关像素与物理像素点无关两种分辨率下160 dp 都会显示为屏幕宽度一半的长度在 Android 中规定以屏幕像素密度为 160 dpi即屏幕分辨率为 320 x 480 为基准此时 px 和 dp 的换算关系是1 px 1 dp谷歌给的标准3.7 密度无关像素 dp 与像素 px 的换算关系是什么逻辑密度 具体像素密度 / 标准屏幕像素密度也就是density (dpi / 160)像素 密度无关像素 * 逻辑密度也就是px dp * (dpi / 160)不过无论是 pxdp亦或是 sp最终都会以 px 为单位渲染到屏幕上3.8 独立比例像素是什么独立比例像素scale-independent pixels即 sp与 dp 类似用来设置 Android 中文本显示的大小并且可以根据文字大小首选项进行缩放。如何理解“根据文字大小首选项进行缩放”比如你在 Android 里写TextViewandroid:textSize16sp/正常情况下16sp和16dp在视觉大小上可能差不多。但是用户如果去系统设置里把字体调大设置 - 显示 - 字体大小 - 大那么16sp 显示出来会变大 16dp 不会因为字体设置而变大这就是“可以根据文字大小首选项进行缩放”的意思。用户调大系统字体后sp 对应的实际像素会变大。文字本身会占用更多像素空间不是只变粗。但外层控件、窗口、屏幕尺寸不会自动整体变大。至于文字所在的 TextView 会不会变大要看它的布局参数。4. 适配方案4.1 为什么要做适配现在来回答一下这个问题Android 运行在大量不同尺寸、不同分辨率、不同像素密度、不同宽高比、不同系统显示设置的设备上所以同一套 UI 在不同设备上可能表现不同。4.2 控件适配布局文件中使用wrap_contentmatch_parentweightdp0 dp来控制控件的宽高不要使用 px 这种绝对的尺寸按理来说谷歌给我们开发者提供的 dp 和 sp 就已经可以做到屏幕适配了为什么还会在某些手机上不能完全满足显示效果。其实我们通过 px dp * (dpi / 160) 这个公式就可以发现如果手机厂商不按照谷歌的标准来比如 1080 * 1920 的设备本来 dpi 应该是 480但是厂商设备的尺寸却是 5 英寸那么最终算出来的 dpi 大概就是 440那 dpi 都不一样了dp 当然就不一样呀。4.3 布局适配使用官方推荐的约束布局可以尽可能还原设计稿ConstraintLayout可以减少嵌套方便通过约束、百分比、Guideline、Barrier、链等方式适配不同尺寸但它不能单独解决所有屏幕适配问题。4.4 今日头条的适配方案Android 默认会根据设备的dpi计算density再通过px dp * density把dp转成px。比如一台1080px宽的手机density 3那么30dp最终就是90px。如果设计稿是按360 dp宽来做的那么30dp在设计稿中占的比例是30 / 360 1/12。在1080px宽的设备上它对应90px比例也是90 / 1080 1/12所以显示正常。但换到一台1440px宽、系统默认density 3.5的手机上30dp会被换算成105px。这时它占屏幕宽度的比例是105 / 1440比原设计稿的1/12小控件看起来就偏窄。今日头条适配方案就是为了解决这个问题。它不直接使用系统默认的density而是用targetDensity 屏幕宽度px / 设计稿宽度dp对于1440px宽的手机如果设计稿宽度是360 dp那么targetDensity 1440 / 360 4这样30dp就会变成30 * 4 120px此时120 / 1440 30 / 360 1/12控件在屏幕中的占比就和设计稿一致了。对于不同设备系统默认会根据设备的 dpi 计算 density再用 px dp * density 把布局中的 dp 换算成 px。这个方式更偏向保证控件的物理尺寸接近但不一定能保证控件在屏幕中的占比和设计稿一致。比如设计稿中某个控件占页面宽度的 1/2换到另一台设备后因为系统 density 不一定等于“屏幕宽度 px / 设计稿基准宽度 dp”所以这个控件最终占屏幕宽度的比例可能发生变化。今日头条适配方案就是重新计算 density。它用当前设备的屏幕宽度 px除以设计稿基准宽度 dp得到一个目标 density然后替换系统原来的 density。这样布局中的 dp 再换算成 px 时就会按照设计稿的宽度比例来缩放。最终控件在设备屏幕中的占比和它在设计稿中的占比保持一致从而更接近设计稿效果。所以今日头条适配方案的核心思想是修改应用运行时的 density。系统默认会根据设备的 dpi 得到 density再用px dp * density把 dp 转成 px。头条方案则根据当前设备的屏幕像素宽度和设计稿基准宽度计算一个目标 density比如targetDensity screenWidthPx / designWidthDp然后把Resources.DisplayMetrics中的density、scaledDensity、densityDpi替换成目标值。这样开发者可以直接按照设计稿对应的 dp 尺寸写布局在不同屏幕上让页面宽度按设计稿比例缩放从而提升视觉还原度。一句话总结今日头条适配方案有了对头条适配方案原理的了解后再来看这篇讲解 今日头条的原理、优缺点和使用 的文章它通过修改 Android 的density让设计稿宽度对应当前设备屏幕宽度从而让布局里的dp按设计稿比例自动缩放。importandroid.app.Activity;importandroid.app.Application;importandroid.content.ComponentCallbacks;importandroid.content.res.Configuration;importandroid.util.DisplayMetrics;importandroidx.annotation.NonNull;publicclassWindowUtils{/** * 系统的Density */privatestaticfloatsNonCompatDensity;/** * 系统的ScaledDensity */privatestaticfloatsNonCompatScaleDensity;publicstaticvoidsetCustomDensity(Activityactivity){Applicationapplicationactivity.getApplication();finalDisplayMetricsappDisplayMetricsapplication.getResources().getDisplayMetrics();if(sNonCompatDensity0){// 系统的Density:长度相关参数dpsNonCompatDensityappDisplayMetrics.density;// 系统的ScaledDensity字体相关参数spsNonCompatScaleDensityappDisplayMetrics.scaledDensity;// 监听在系统设置中切换字体application.registerComponentCallbacks(newComponentCallbacks(){OverridepublicvoidonConfigurationChanged(NonNullConfigurationnewConfig){if(newConfig!nullnewConfig.fontScale0){sNonCompatScaleDensityapplication.getResources().getDisplayMetrics().scaledDensity;}}OverridepublicvoidonLowMemory(){}});}/* * 如果UX提供的是480dp的设计稿,也就是分辨率为1080*1920的设计稿 * * 把系统的逻辑密度density和像素密度dpi根据UX提供的设计稿进行处理 */finalfloattargetDensityappDisplayMetrics.widthPixels/480;finalfloattargetScaledDensitytargetDensity*(sNonCompatScaleDensity/sNonCompatDensity);finalinttargetDensityDpi(int)(160*targetDensity);/** * 设置Application对应的DisplayMetrics参数 */appDisplayMetrics.densitytargetDensity;appDisplayMetrics.scaledDensitytargetScaledDensity;appDisplayMetrics.densityDpitargetDensityDpi;/** * 同时也要设置Activity对应的DisplayMetrics参数 */finalDisplayMetricsactivityDisplayMetricsactivity.getResources().getDisplayMetrics();activityDisplayMetrics.densitytargetDensity;activityDisplayMetrics.scaledDensitytargetScaledDensity;activityDisplayMetrics.densityDpitargetDensityDpi;}}5. 总结因为 Android 系统是开源的任何用户开发者厂商运营商都可以对 Android 系统的源码进行定制所以运行 Android 系统的设备屏幕尺寸屏幕分辨率屏幕像素密度不甚相同在相同屏幕尺寸下可能会出现不同分辨率的情况开发者如果使用 px 作为控件尺寸的单位那么要达到相同的物理尺寸需要的像素个数不同就需要设置不同的 px 值谷歌为了处理这种情况就出了一种新的尺寸单位 dp也叫做密度无关像素使用 dp 作为计量单位最终也会换算为具体的 px 值再根据这个 px 值绘制控件换算公式为逻辑密度 dpi / 160px dp * 逻辑密度 dp * (dpi / 160)开发者使用 dp 作为单位在相同屏幕尺寸不同分辨率的情况下系统会根据逻辑密度将 dp 值换算为对应的 px 值来尽可能还原控件的物理尺寸但是使用 dp 只能还原物理尺寸但是在不同设备的屏幕中物理尺寸和分辨率比例不一致导致相同 dp 的控件在不同设备上的视觉占比不同与设计稿的比例效果有偏差。为了处理不同设备上控件在页面中的视觉占比尽可能还原设计稿中控件在页面中的视觉占比我们通常会引入今日头条的适配方案头条适配方案的原理是重新计算出一个将 dp 换算为 px 的逻辑密度具体的计算新的逻辑密度的方法是计算设备屏幕尺寸和设计稿尺寸的比值以宽度为例子我们需要先通过分辨率确定设备具体的宽度 px以及设计稿的宽度 dp然后计算设备宽度 px 和设计稿宽度 dp 的比值将这个比值替换掉系统通过 dpi 计算的逻辑密度使用新的逻辑密度会将布局控件中设置的 dp 值转为新的 px 值此时在设备中控件在页面中的视觉占比和设计稿中控件在页面中的视觉占比相同进一步还原了设计稿的效果因此我们最常用的适配方法就是使用 dp 取代 px作为控件尺寸的计量单位来尽可能还原物理尺寸引入今日头条的适配方案计算出新的逻辑密度让 dp 换算为符合设计稿视觉占比的 px来做到设备中布局控件视觉占比还原设计稿视觉占比今日头条的适配方案配置简单适配效果显著同时对业务代码几乎没有侵入性但是也有缺点就是这个方案是全局修改逻辑密度会导致所有使用 dp 的地方都按屏幕尺寸等比缩放在某些宽高极端的设备上比如一些超宽屏控件可能会被拉得很长很扁同时如果多个 Activity 需要不同的适配策略这种全局方案是不够灵活的所以可以考虑使用官方推荐的约束布局也可以尽可能还原设计稿ConstraintLayout可以减少嵌套方便通过约束、百分比、Guideline、Barrier、链等方式适配不同尺寸。面试官可能的追问追问你的应对dpi 怎么获取getResources().getDisplayMetrics().densityDpi设计稿一般是多大常见 360 dp、375 dp对应 iPhone 6/7/8 的宽度头条方案会影响 sp 吗会影响所以通常需要单独处理或禁用还有别的适配方案吗限定符方案、百分比布局、AutoSize 框架等6. 回答阅读卡问题1. Android 为什么不能只靠一套固定的 px 尺寸适配所有设备答因为 Android 设备以及应用窗口的屏幕尺寸、分辨率、像素密度、宽高比和可用空间不同还存在横竖屏、分屏、折叠屏和自由窗口等场景。同一个 px 值在不同像素密度的屏幕上对应的物理长度不同例如固定为100px的控件在低密度屏幕上看起来较大在高密度屏幕上看起来较小。如果要绘制屏幕高度一半的线在240 × 320px的竖屏上需要160px在320 × 480px的竖屏上需要240px。因此直接使用固定 px 描述界面尺寸需要针对不同设备和窗口进行额外换算不能只靠一套固定 px 完成适配。2. 屏幕尺寸、分辨率与像素密度 dpi 分别描述什么它们之间如何换算答屏幕尺寸表示屏幕物理对角线的长度单位是英寸。分辨率表示屏幕横向和纵向的物理像素数量通常按照“宽 × 高”描述例如1080 × 1920px。屏幕的理论物理像素密度表示每英寸包含的像素数更严谨的单位是 PPI通常按下面的公式计算对角线像素数 sqrt(widthPx² heightPx²) PPI 对角线像素数 / 屏幕对角线英寸数Android 资料中经常使用 dpi 表示密度但DisplayMetrics.densityDpi是系统用于 UI 缩放的逻辑密度不一定等于根据物理尺寸算出的真实 PPI。它可能受到厂商配置和用户“显示大小”设置影响。在实际适配中适配过哪些英寸的设备可以作为项目经历但现代 Android 开发更关注应用当前窗口的可用 dp 尺寸而不是只按手机的物理对角线分类。3. dp、px、density 之间是什么关系160 dpi 为什么是换算基准TypedValue.applyDimension()如何处理不同单位答dp 是密度无关像素px 是屏幕最终绘制使用的物理像素density 是 dp 转换成 px 时使用的逻辑密度。经典换算关系是density densityDpi / 160 px dp × density160dpi是 Android 人为规定的 mdpi 基准密度。在 mdpi 环境下density 160 / 160 1 1dp ≈ 1px160dpi不对应某个固定分辨率因为分辨率还需要结合屏幕物理尺寸才能确定像素密度。TypedValue.applyDimension()根据单位和DisplayMetrics将数值转换为最终 pxCOMPLEX_UNIT_PX - 输入已经是 px基本返回原值 COMPLEX_UNIT_DIP - value × metrics.density COMPLEX_UNIT_SP - 根据设备密度和用户字体缩放规则转换为 pxAndroid 14 开始支持非线性字体缩放因此 SP 与 px 之间不能始终简单地写成sp × scaledDensity。需要转换时应优先使用TypedValue.applyDimension()。4. sp 与 dp 的差异是什么系统字体大小变化时 TextView 的文字和布局可能怎样变化答dp 主要用于控件尺寸、间距和布局定位。系统根据逻辑 density 将 dp 转换成 px使相同 dp 在不同密度设备上具有近似一致的视觉或物理尺寸。sp 主要用于文字大小。它在密度换算的基础上还会响应用户设置的字体大小因此系统字体调大后使用 sp 的文字也会变大。字体变大不代表整个页面同比放大TextView 的具体变化由布局参数决定宽高为wrap_content时TextView 可能变宽、变高或者增加行数。宽高固定时文字可能被裁剪、省略或者显示不完整。宽度为match_parent或0dp时宽度通常不变但文字可能换行并增加高度。父布局空间不足时可能挤压相邻控件或者产生溢出。5.wrap_content、match_parent、weight、dp 与约束布局分别如何帮助适配答wrap_content根据内容、padding 和父布局提供的测量限制确定尺寸不是根据父布局等比缩放。match_parent占用父布局允许的可用空间不必然导致控件比例失调。weight在LinearLayout中按照权重分配剩余空间适合实现多个子控件按比例占用空间但不是对控件整体进行缩放。dp解决不同屏幕逻辑密度下的尺寸换算问题不负责解决屏幕宽高比、窗口空间和布局结构变化。ConstraintLayout通过相对约束、Guideline、Barrier、Chain、宽高比例和0dpmatch constraints使控件根据父布局和相邻控件的位置动态排列。ConstraintLayout可以减少布局嵌套和部分测量开销但减少嵌套不等同于一定减少过度绘制。过度绘制主要指同一个像素被多层背景或控件重复绘制。6. 系统默认 density 与今日头条方案的 targetDensity 如何计算追求的效果有什么不同答系统默认 density 通常根据逻辑densityDpi计算density densityDpi / 160 px dp × density系统 density 主要用于让相同 dp 在不同密度设备上具有近似一致的视觉或物理尺寸但不保证控件占屏幕的比例与设计稿完全一致。今日头条方案会选择宽度或高度中的一个方向作为适配基准。以宽度适配为例targetDensity 当前窗口宽度px / 设计稿基准宽度dp假设设备宽度为1440px设计稿基准宽度为360dptargetDensity 1440 / 360 4设计稿中的30dp最终变成30 × 4 120px 120 / 1440 30 / 360这样控件在设备宽度中的占比就与设计稿一致。该方案不是分别计算横向和纵向两个 density。DisplayMetrics只有一套 density横向和纵向都会使用相同缩放比例。通常根据业务选择宽度适配或者高度适配不能同时让两个宽高比不同的窗口完全匹配设计稿。7.setCustomDensity()修改了哪些 DisplayMetrics 字段为什么还要监听字体缩放变化答setCustomDensity()修改 Application 和 Activity 对应DisplayMetrics中的三个字段density // dp 转换为 px 使用的逻辑密度 scaledDensity // 传统 SP 转换为 px 使用的字体缩放密度 densityDpi // 与目标 density 对应的逻辑 dpi对应关系是targetDensityDpi 160 × targetDensity代码先保存系统原始的density和scaledDensity从而得到原来的字体缩放比例字体缩放比例 originalScaledDensity / originalDensity再根据目标 density 计算targetScaledDensity targetDensity × 字体缩放比例监听字体配置变化是因为用户可能在应用运行期间修改系统字体大小。如果不更新保存的原始scaledDensity后续页面仍会使用旧字体比例导致文字大小与当前系统设置不一致。示例代码还存在整数除法问题final float targetDensity appDisplayMetrics.widthPixels / 480;widthPixels和480都是整数会先执行整数除法应改为final float targetDensity appDisplayMetrics.widthPixels / 480f;这段代码的设计稿基准宽度是480dp不是前文示例中的360dp。另外Android 14 的非线性字体缩放使手动维护单一scaledDensity比例的方案不再完全可靠。8. 今日头条方案有哪些局限什么情况下约束布局更合适答今日头条方案配置相对简单对具体业务布局代码侵入较少也能较好地保持页面与设计稿的宽度或高度比例但存在以下局限修改 Application 的 density 会影响应用内所有使用 dp 和 sp 的页面。第三方控件、系统弹窗、WebView、图片尺寸和触摸区域也可能受到影响。多个 Activity 需要不同适配基准时全局 density 不够灵活。字体设置、横竖屏、分屏和窗口大小变化时需要重新计算和更新 density。它只能按一个方向整体缩放不能同时匹配宽高比不同的设计稿与窗口。在超宽但较矮的窗口中以宽度为基准可能导致全部控件和文字整体过大产生纵向溢出。它只能缩放已有布局不能把手机单栏布局自动转换成平板双栏布局。由于横纵方向使用同一个 density控件通常是整体等比放大或缩小不是单独被拉长或压扁。需要根据父布局和相邻控件动态调整位置、尺寸、比例或剩余空间时ConstraintLayout更合适。需要在手机、平板、折叠屏和分屏窗口中切换单栏、双栏、导航栏等布局结构时还应结合 Window Size Class 和资源限定符。完整的屏幕适配思路是使用 dp/sp 处理密度和字体缩放使用响应式约束处理空间变化使用 Window Size Class 或资源限定符处理布局结构变化修改 density 只适合作为特定设计基准下的整体比例缩放方案。