前语

在移动端的产品迭代中总会碰到屏幕适配的问题,不同的标准的设备展示的内容不相同,在Android平台中这个现象更为杰出。而它是怎样构成的,这个时分该怎么处理屏幕适配的问题?

作为一名规划师,我将从程序员的角度去剖析一下其发生的原因,以及该怎么更好地处理这个问题。本篇文章将作为一个引子,后续将会对里边的内容加以完善、补偿。

屏幕展示什么内容,展示多少内容许多时分并不是UI规划师来定的,或是产品司理、或是交互规划师,为了便当论说,下面将他们统称为规划师。

规划长度单位

在移动端的开发中,我们会碰到许多个长度单位:

  • Web中为px(pixel)。
  • iOS为pt(point)
  • Android中为dp(Density-independent pixels)、sp(Scale-independent pixels)

其间px为像素,是最小展示单位,放在显示器中对应着一个发光像素点,此时可以了解为物理像素,其间1080 × 1920的屏幕则具有2073600个像素点,为宽高相乘的结果。但是像素并非都代表物理像素,还可以作为烘托像素。在部分手机中,这两者大小不一致,烘托像素会经过一次转化才在物理像素中展示。

iPhone 8 Plus的物理像素为1080p,但是烘托像素为 1242 * 2208,其截图的标准和展示的标准不一致。

而pt、dp、sp的概念是类似的,都是逻辑像素。在实践展示中,会经过必定的比例缩放来映射到像素点中,即刚刚提到的px,而这一个比例也称为缩放因子(scale factor)。

但是在UI规划中的长度单位是什么呢?我们翻开规划软件看一下:

【规划探求】从规划师的角度看Android屏幕适配

答案是没有单位

被含糊掉的长度单位

UI规划软件中含糊了长度单位。目的也很明确,就是让规划师不要介怀自己运用的是什么长度单位,不必特意去了解不同长度单位之间有什么关系。

  • 在移动端或Mac的预设中,它是逻辑像素作为单位
  • 在PC端和Web的预设中,它是物理像素px作为单位

因为UI规划软件是矢量图,而且逻辑像素在展示进程中会主动缩放到物理像素并展示, 在移动端规划稿中运用一倍规划稿(预设)交付给开发即可无痛适配二、三甚至四倍规划稿。

在iOS开发中,SwiftUI也特意含糊掉了单位,举个比方:

ZStack {
    Text(title).font(.system(size: 50))
}.frame(
    width: 200
    height: 400
)

而它的效果也与前者类似,减少开发者的心智担负,iOS开发工程师直接运用规划师交付过来的标准即可完美适配

Flutter中也是如此:

Container(
  width: 100,
  height: 50,
)

甚至在ReactNative中也是类似的:

const App = () => (
  <View width={100} height={50}>
    <Text>Hello, world!</Text>
  </View>
);

Android“活络”的单位选择

在Android中非常活络,你一般可以很简略地接触到不同的单位并做出选择,一不留意简略埋下坑。假设运用的逻辑像素,系统内部在展示进程会将逻辑像素(dp、sp)转化成实践烘托像素(px),假设运用的是烘托像素,系统将会1:1烘托。

// Compose 其实对长度单位封装得很完善了
Text(
    text = text,
    fontSize = 12.sp,
    modifier = Modifier.width(200.dp).height(100.dp)
)
// 而在 View 中比较简略稠浊
TextView(context).apply {
    textSize = 14F // 其实是14.sp
    updateLayoutParams { 
        width = 120 // 其实是px
        height = 120 // 也是px
    }
}

Android的活络性也为后续提到的屏幕适配方案提供了基础。

屏幕适配作业的诞生

规划稿标准的选择

要看到问题的实质,就得追根溯源。市面上的Android设备五花八门,DPI也各不相同,这也会直接构成屏幕的逻辑像素非常多且杂,或许会有标准相同的设备展示的内容不一致,不过好在大多数设备的展示比例都还算正常。但是,反观iPhone的逻辑像素却非常安稳,新的设备和旧的设备的逻辑像素改动不会很大,甚至许多年都不会有改动。规划师在定规划稿标准的时分大多数都会首选iPhone的逻辑像素作为底图而不是Android的。

看到这儿必定会有疑问,iPhone不是一直在变长吗?

但是细心想一下,手机的长度真的很影响到APP的内容展示和交互适配吗?一般内容超出屏幕的场景简直都是列表或许信息流,而这两者都会用上翻滚布局。只需用上翻滚布局之后,手机的长度关于规划来说并不活络,不管长一些亦或许短一些,关于用户领会来说只是多划一下或许少划一下,因此UI适配主要看的是逻辑宽度

我们来回顾从iPhone 4到iPhone 11这整整9年间,逻辑宽度并没有发生太大改动。简略归纳为三个宽度:

  • 320(iPhone 4,5 / iPhone SE)
  • 375(iPhone 标准版 / iPhone Pro)
  • 414(iPhone Plus / Max)

这三个宽度应该选哪个呢?我们应该很了解,也就是375

至于为什么不是前后两个,细心想想,当你选择320作为规划稿标准的时分,这张规划稿放到414宽度中将会有非常大的留白,而且能展示的内容非常少,清楚明了320并不是很好的选择。

当你选择414作为规划稿标准的时分,一旦APP运行在320标准的手机中,将会有非常多的内容被裁剪或许看不到,甚至关于开发来说简略出现BUG。

所以折中选择中心的标准会是一个比较好的选择,遵照一个这样的规划观念会对屏幕适配非常有协助:在规划进程中留意对规划稿进行恰当的留白,以确保小标准的设备展示不会太乖僻。

从iPhone12初步这三个宽度将会有一些改动,320宽度被苹果扔掉,375成为最小的标准。如下所示:

  • 375(iPhone mini / iPhone SE)
  • 390 / 393(iPhone 标准版 / iPhone Pro)
  • 428 / 430(iPhone Plus / Max)

也就是说从这几年初步,需求考虑从375宽度的规划稿迁移到390 / 393了,以抵达较好的规划效果。若规划师还在运用375作为标准规划宽度的话,就会常常发实际践展示和规划稿对不上,这时的问题就出在规划师的规划底图标准选择上了。

Android阵营适配iPhone规划稿

因为iPhone的屏幕宽度数量很少,每个规划阶段只需求考虑三种宽度即可,因此iPhone的屏幕适配问题屈指可数。以iPhone的宽度作为标准的规划稿在Android阵营中总会有些水土不服,Android这边完成出来的效果不是偏大就是偏小。在规划走查环节,规划师眉头紧皱,Android开发工程师苦不堪言。

于是Android开发工程师运用Android的活络性和可自定义性发现了许多能“恢复”iPhone规划稿的办法。

作为一名Android开发,我这边聊一下了解的Android领域。(不太了解iOS)

SmallestWidth适配方案

已然规划师们运用特定的宽度作为规划稿宽度,那我们就可以以这个宽度去定义一个新的“长度单位”。而一旦运用这个单位,就可以直接无脑运用规划师交付的规划稿中的标准来开发,做出来的效果绝对满足规划稿的展示效果。

新“长度单位”这个概念只是便当了解,并不是真的新单位。

我们以390宽度举例,已然在390宽度的手机可以完美恢复规划稿,也就是说在390宽度的手机直接运用dp即可,即1长度单位 = 1dp。并以此向更窄以及更宽的手机去扩展。

  • 在宽度为360的手机1长度单位 = 360 ÷ 375 ≈ 0.92dp
  • 在宽度为400的手机1长度单位 = 400 ÷ 375 ≈ 1.03dp。

而Android也支撑主动在不同的标准去选择不同的资源文件,因此我们可以创立不同的资源文件放在对应的文件夹,如下所示。

【规划探求】从规划师的角度看Android屏幕适配

我们在布局文件直接运用即可。

<TextView
    android:layout_width="@dimen/DIMEN_1"
    android:layout_height="@dimen/DIMEN_1" />

在代码中也可以动态获取

textView.updateLayoutParams {
    width = resources.getDimension(R.dimen.DIMEN_1).toInt()
}

只需项目中的视图都运用dimens.xml中的对应长度,就可以完美适配规划稿,它的类似下图所示:

【规划探求】从规划师的角度看Android屏幕适配

中图是390的设备展示效果,而左图是宽度为360的设备展示效果,右图是宽度为440的设备的展示效果。他们就好像等比缩放了相同,而事实也是如此,这种效果完美符合规划师的预期了。

Density适配

逻辑像素经过必定的缩放比例映射到实践烘托像素,而这个比例被称为缩放因子,它与DPI的转化关系为:

DPI=160×ScaleFactorDPI = 160 \times ScaleFactor

缩放因子在Android中的名字为Density,可以经过如下代码获取,而DPI为densityDpi。

DPI和PPI的概念类似,但是其实有些不相同,PPI指的是屏幕的像素密度,DPI是Android特有的像素密度。

val displayMetrics: DisplayMetrics = resources.displayMetrics
val density = displayMetrics.density
val densityDpi = displayMetrics.densityDpi

而最抵死的是,DisplayMetrics这个类中的特点都是可以批改的,而且真的可以影响到系统展示。那我们在视图展示之前把里边的参数依照标准规划稿去进行调整就好了。

displayMetrics.densityDpi = displayMetrics.widthPixels.toFloat() / 390F
displayMetrics.density = (targetDensity * 160).toInt()

在实践开发中运用dp进行开发即可。

为了简练,此处未考虑字体缩放sp。

它的效果和上面的那种办法是相同的,类似等比缩放。

等比缩放的问题

我们发现了吗?常用的屏幕适配办法都是将当前设备展示的内容等比缩放到规划师出的规划稿底图的比例,已抵达展示的内容与规划稿一致,在水平方向,不会多展示东西,也不会少展示东西,满足规划需求的一起也不会发生更多的BUG。

但是我个人并不引荐我们继续运用,简略为今后埋下更深的坑,为什么?Android设备并不止有一种标准,它有折叠屏横竖屏,有平板,有车机,甚至手机横过来也是一种标准。举个比方上面适配好的页面一旦放在平板或折叠屏中展示时会变成以下这样:

【规划探求】从规划师的角度看Android屏幕适配

在屏幕宽度较大的设备中,全部东西都变得巨大,无法正常运用。

假设运用以上两种屏幕适配办法,你只能祈祷用户不要运用大屏幕的设备,但是这并不或许。

一旦运用上方等比缩放的办法,将会为后续适配埋下更多坑。例如:

  1. 规划师批改规划稿的标准宽度将非常困难,难以推进。因为一旦批改了,将会影响到旧的页面的展示效果,影响到代码的复用。
  2. 一旦在大屏设备运用APP,将难以运用。
  3. 一旦页面规划太多逻辑,需求进行屏幕适配,只能大规划重构,这将耗费大量人力。

有没有更好的办法?

需求完全处理屏幕适配这个问题,我们先捋一下思路。

  1. 规划师以iPhone的宽度作为基准制作规划稿,考虑了iPhone的三个不同宽度展示的内容,最大和最小宽度为规划稿的可用宽度规划

    因为iPhone的屏幕标准差异别较小,或许规划时没有特别考虑也可以适配。

  2. 因为Android设备的DPI各不相同,所以或许出现超出规划稿的可用宽度规划的手机,会出现漏展示或留白较多的问题,也或许会出现标准相同的设备展示的内容不一致(DPI和PPI不一致)。但是要求全部Android产商一致DPI不太实际。

鉴于Android视图开发的活络性和恢复规划稿的要求,Android开发者主动往前迈了一步,找到了归于自己的办法,把Android APP的标准变成了iPhone的形状。这既让规划师少走一步,又完美恢复了规划稿,进一步减少了BUG。

跟着手机屏幕在逐步升级,千元机也能用上1080P的屏幕,540p、720p屏幕渐渐减少,乖僻的ppi也渐渐变少。厂商在规划手机的时分也会将手机的DPI规划在一个比较合理的规划内。

因此,在我看来,屏幕适配这种原本应该Android开发考虑的作业,应该渐渐地交接给产品司理、交互规划师、UI规划师了。不同屏幕该展示什么内容,主动去适配不同PPI / DPI的设备、不同宽度的设备、不同比例的设备交给规划师们去构思,而程序员可以在开发进程中进行兜底、规避展示不全或许留白过多的问题。

规划师们需求考虑的作业

尽量多适配不同大小的逻辑宽度

主动把宽度的适配规划下潜,一般下潜到320左右(折叠屏单屏宽度)即可,因此在规划的时分需求预留更多的空间,或许在宽度较小的设备展示更少的内容。

把宽度更高的设备适配提上日程,运用该运用的未必是手机,或许是更多大屏设备。而宽度更多的设备或许会有留白,这关于规划来说是比较糟糕的,因此在产品规划的时分可以往里边塞下更多内容,以抵达更好地运用屏幕空间的目的。一旦屏幕宽度抵达必定的程度,就需求考虑运用不同的规划稿了。

关于这两点谷歌官方有更好的论说,因此可以查看:developer.android.com/guide/topic…

以下是《小鹅事务所》记账模块中的一个简略的比方,在出规划稿的时分需求一起考虑多个标准应该展示什么,根据屏幕标准对内容有增有减,并对布局位置进行相应调整,以抵达比较好的展示效果。

【规划探求】从规划师的角度看Android屏幕适配

多窗口适配

在大屏设备运用软件时,我们常常会看到软件被分割成两半,左面阅览信息流,右边查看概况,两边都是单独的页面。这是一种比较简略的大屏适配办法,在逻辑复杂,无法马上适配大屏页面的情况下,运用这种办法也能抵达一个不错的适配效果,例如下图所示。

【规划探求】从规划师的角度看Android屏幕适配

减少强迫症

在规划走查阶段,假设Android设备没有运用等比缩放去适配规划稿的办法,而是单纯运用逻辑像素进行开发,就或许会发现距离、布局大小和规划稿有些收支。

这个时分就不需求截屏到规划软件中拿尺子量啦,尊重设备的差异,只需实践偏差不太离谱,点评过不影响运用就可以睁一只眼闭一只眼。若真实过火严峻,则可以考虑一下特别对该机型的DPI从头编排布局或调整交互办法,即上面描绘的适配该类型的屏幕。因为涉及到必定的作业量,因此是否需求从头编排布局这项作业也需求进一步点评。

现在绝大多数手机的DPI都比较合理,因此需求特别适配的布局应该会很少。

总结

本文以屏幕适配为起点,对当下Android常见的屏幕适配问题简略做了一个论说。

  1. 简略介绍了UI规划的长度单位,还有规划稿选择375宽度的原因。
  2. Android设备的展示效果为什么总是和规划稿有收支。
  3. Android当下比较经典的屏幕适配办法的优缺点。
  4. 屏幕适配未来的作业需求渐渐交接给规划师们。

看完这篇文章,我们心里必定还会有一些问题,而我后续也会对文中表述不清晰的当地另外编写文章进一步说明,一起《小鹅事务所》开源项目适配大屏设备也提上日程,后续文章将辅以实践叙述。

参考