¿Cómo hacer que un conjunto de códigos se adapte perfectamente a varias pantallas?

El propósito de la adaptación.

A diferencia de iOS, los dispositivos Android tienen diferentes tamaños de resolución y sistemas de diferentes fabricantes. Para la resolución actual del mercado, puede ver las estadísticas relevantes de Umeng.

imagen.png

Se puede ver que hay más de 10 resoluciones principales. Cuando no se hace ninguna adaptación, el efecto de un conjunto de códigos en diferentes dispositivos es demasiado grande, demasiado pequeño, truncado y dejado en blanco. ¿Cómo se puede mostrar perfectamente ese conjunto de códigos? en diferentes dispositivos?Puedes ver algunos esquemas de adaptación a continuación.

2. Adaptación de la interfaz de usuario

2.1 Métodos de adaptación comunes

2.1.1, adaptación de control de diseño xml

  1. Evite escribir el ancho y el alto de la Vista, intente usar warp_content y match_parent;
  2. El diseño principal es LinearLayout , elige usar el atributo android:layout_weight para establecer el peso de cada Vista secundaria en el diseño;
  3. El diseño principal es RelativeLayout, puede elegir usar atributos como layout_centerInParent para establecer la posición relativa de la Vista secundaria;
  4. Google proporcionó oficialmente un método de diseño de porcentaje en versiones anteriores:apoyo:porcentaje, admite el diseño porcentual de RelativeLayout y FrameLayout, pero ya no se mantiene oficialmente y se reemplaza por un nuevo diseño: ConstraintLayout , ConstraintLayout es poderoso no solo porque puede realizar el diseño porcentual, sino también el posicionamiento relativo y el posicionamiento angular , las restricciones de tamaño, la relación de aspecto, el diseño de la cadena, etc., se pueden manejar fácilmente en diferentes dispositivos.

2.1.2, adaptación de imagen

  1. La imagen .9.9.png
    es esencialmente una imagen png. En comparación con la imagen png ordinaria, la imagen .9 puede hacer que la imagen se estire en la posición especificada y mostrar el contenido en la posición especificada sin distorsión;
  2. Consulte 2.1.4 Calificadores de resolución;

2.1.3, según la adaptación del diseño del producto

所谓产品设计适配,指的是产品流程在不同设备上有不同的展示方式,例如手机与Pad的区别,在手机设备上,一般来说具体Item列表是一个页面,点击每个Item会跳转至新的详情页;而在宽度>高度的Pad上,为了防止页面空白浪费,一般会要求屏幕左侧为Item列表,右侧即详情页,item与详情页会同时出现在用户的视觉内,如下图

Almohadilla.png

关于这种类型的设计,其实郭霖《第一行代码》给出了一个方案,我在这里抛砖引玉一下,给出基本思路。

这种情况下,适配的核心在于利用android动态加载布局的机制,使得程序能够根据分辨率或者屏幕大小在运行时动态加载不同的布局,而动态加载就需要使用到限定符

  • 限定符 所谓限定符,指的是给res目录中的子目录加上“-限定符”,可以给不同设备提供不同的资源以及布局,如下图,layout添加-large,-small。

imagen.png

layout-small:指的是提供给小屏幕设备的资源;
layout-large:指的是提供给大屏幕设备的资源;
layout/layout-normal:指的是提供给中等屏幕设备的资源,也就是默认状态;
layout-xlarge:值得是提供给超大屏幕设备的资源;

在上面所提出的情景下,Pad即指的大屏幕,手机一般可看作为中等屏幕设备,为了在大屏幕下显示双页模式,我们可以在layout-large和layout目录下新建同一个name的布局xml,在layout-large下的xml针对Pad做双页处理,即左半边View+右半边View样式,layout目录下xml还是做普通处理。

在最后项目运行时,会根据不同设备来加载不同目录下的xml资源,即Pad会加载layout-large目录下的xml,普通手机设备会加载layout目录下的xml资源。

从而实现一套代码在不同设备上产品逻辑。

限定符可以大范围的区分设备,但是你还是不知道-large代表是多大的设备,-small代表的是多小的设备,如果需要清楚的区分各个屏幕的大小,那就需要用到最小宽度限定符。

  • 最小宽度限定符(Smallest-width Qualifier),简称SW 最小宽度限定符指的是,对屏幕的宽度设立一个最小的值(dp),当当前设备屏幕宽度大于这个值就加载一个布局,

imagen.png

例如在res下新建一个layout-sw720dp的文件夹,当屏幕宽度大于720dp时,项目就会加载layout-sw720dp/***.xml 资源文件。

2.1.4、限定符适配

在2.1.3中提到了限定符的概念,也解决了一部分的设计适配问题,但是还有一些限定符的概念没有涉及到,该目录下将会提到不同的限定符的概念,可以结合2.1.3一起食用。

  • 分辨率限定符 在Android项目中,会把放置图片资源的文件夹分为drawable-hdpi、xhdpi xxhdpi xxxhdpi等,这些指的就是分辨率限定符。

Andriod系统会根据手机屏幕的大小及屏幕密度去选择不同文件夹下的图片资源,以此来实现在不同大小不同屏幕分辨率下适配的问题。

这里提一点AS对图片资源的匹配规则:

举个例子,当当前的设备密度为xhdpi,此时代码中ImageView需要去引用drawable中的图片,那么根据匹配规则,系统首先会在drawable-xhdpi文件夹中去搜索,如果需要的图片存在,那么直接显示;如果不存在,那么系统将会开始从更高dpi中搜索,例如drawable-xxhdpi,drawable-xxxhdpi,如果在高dpi中搜索不到需要的图片,那么就会去drawable-nodpi中搜索,有则显示,无则继续向低dpi,如drawable-hdpi,drawable-mdpi,drawable-ldpi等文件夹一级一级搜索.

当在比当前设备密度低的文件夹中搜到图片,那么在ImageView(宽高在wrap_content状态下)中显示的图片将会被放大.图片放大也就意味着所占内存也开始增多.这也就是为什么分辨率不高的图片随意放置在drawable中也会出现OOM,而在高密度文件夹中搜到图片,图片在该设备上将会被缩小,内存也就相应减少。

在理想的状态下,不同dpi的文件下应该放置相应dpi的图片资源,以对不同的设备进行适配。

  • 尺寸限定符和最小宽度限定符 见2.1.3

  • 屏幕方向限定符 屏幕方向限定符即“-land”、“-port”,分别代表横排和竖屏。

手机会存在横竖屏切换的场景,当设备横屏时,会主动加载layout-land/目录下的资源文件,当设备为竖屏时,则加载layout-port目录下的资源文件。

2.2、今日头条适配方式

在开始今日头条的适配方案之前,需要提及px、dpi、density的概念。

px:即像素,我们常看到的480 * 800 、720 * 1280、1080 * 1920指的就是像素值宽高的意思;

dpi:即densityDpi,每英寸中的像素数;

density:屏幕密度,density = dpi / 160;

scaledDensity:字体的缩放因子,正常情况下和density相等,但是调节系统字体大小后会改变这个值

android中的dp在渲染前会将dp转为px,计算公式:

  • px = density * dp

从dp和px的转换公式 :px = dp * density 可以看出,如果设计图宽为360dp,想要保证在所有设备计算得出的px值都正好是屏幕宽度的话,我们只能修改 density 的值。这就是该方案的核心。

那如何修改系统的density?

可以通过DisplayMetrics获取系统density和scaledDensity值,

val displayMetrics = application.resources.displayMetrics

val density = displayMetrics.density
val scaledDensity = displayMetrics.scaledDensity

设配的目的在于使用一套设计稿,能完好的展示在不同设备上,所以UI需要确定一个固定的尺寸,依据density=px / dp的公式,确定density的值,其中px指的是真实设备的值, 这里我们以设计稿的宽度作为一个纬度进行测算。

举个例子,如设计稿中固定宽度为360dp,当前设备的屏幕宽度为720,那么density = 720 / 360 = 2,其中当前设备的屏幕宽度也可以用DisplayMetrics来获取:

val targetDensity = displayMetrics.widthPixels / 360

整体思路

//0.获取当前app的屏幕显示信息
val displayMetrics = application.resources.displayMetrics
if (appDensity == 0f) {
    //1.初始化赋值操作 获取app初始density和scaledDensity
    appDensity = displayMetrics.density
    appScaleDensity = displayMetrics.scaledDensity
}

/*
 2.计算目标值density, scaleDensity, densityDpi
 targetDensity为当前设备的宽度/设计稿固定的宽度
 targetScaleDensity:目标字体缩放Density,等比例测算
 targetDensityDpi:density = dpi / 160 即dpi = density * 160
 */
val targetDensity = displayMetrics.widthPixels / WIDTH
val targetScaleDensity = targetDensity * (appScaleDensity / appDensity)
val targetDensityDpi = (targetDensity * 160).toInt()

//3.替换Activity的density, scaleDensity, densityDpi
val dm = activity.resources.displayMetrics
dm.density = targetDensity
dm.scaledDensity = targetScaleDensity
dm.densityDpi = targetDensityDpi

三、刘海屏适配

imagen.png imagen.png
  • 有状态栏的界面:刘海区域会显示状态栏,无需适配;
  • 全屏界面:刘海区域可能遮挡内容,需要适配;

针对刘海屏适配,在Android P以上,谷歌官方给出了适配方案,可参考developer.android.google.cn/guide/topic… ,所以在 targetApi >= 28 上可以使用谷歌官方推荐的适配方案进行刘海屏适配。 而在Android O的设备上,如华为、小米、oppo等厂商给出了适配方案。

3.1、Android9.0官方适配

将内容呈现到刘海区域中,则可以使用 WindowInsets.getDisplayCutout() 来检索 DisplayCutout 对象,同时可以使用窗口布局属性 layoutInDisplayCutoutMode 控制内容如何呈现在刘海区域中。

layoutInDisplayCutoutMode

  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT: en modo vertical, el contenido se representará en el área de muesca, pero en modo horizontal, el contenido mostrará bordes negros.
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES: tanto en el modo vertical como en el horizontal, el contenido se representará en el área de la muesca.
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER: el contenido nunca se representa en el área del flequillo.
/**
 * @param mode 刘海屏下内容显示模式,针对Android9.0
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; //在竖屏模式下,内容会呈现到刘海区域中;但在横屏模式下,内容会显示黑边
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2;//不允许内容延伸进刘海区
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1;//在竖屏模式和横屏模式下,内容都会呈现到刘海区域中
 */
@RequiresApi(Build.VERSION_CODES.P)
private fun setDisplayCutoutMode(mode: Int) {
    window.attributes.apply {
        this.layoutInDisplayCutoutMode = mode
        window.attributes = this
    }

}

Determine si el dispositivo actual tiene flequillo:

/**
 * 判断当前设备是否有刘海
 */
@RequiresApi(Build.VERSION_CODES.P)
private fun hasCutout(): Boolean {
    window.decorView.rootWindowInsets?.let {
        it.displayCutout?.let {
            if (it.boundingRects.size > 0 && it.safeInsetTop > 0) {
                return true
            }
        }
    }
    return false
}

Establezca layoutInDisplayCutoutMode antes de setContentView(R.layout.activity_main) de la actividad.

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
image.png image.png image.png

3.2 Soluciones de adaptación de los principales fabricantes (Huawei, Xiaomi, oppo, etc.)

Además del esquema de adaptación oficial bajo el sistema AndroidP, los principales fabricantes también brindan esquemas de adaptación correspondientes para sus propios sistemas, consulte:

oppo
vivoXiaomi Huawei
_

Documentos de referencia Solución de adaptación de Toutiao
Solución
de adaptación oficial de Android9.0

Estoy participando en el reclutamiento del programa de firma de creadores de la Comunidad Tecnológica de Nuggets, haga clic en el enlace para registrarse y enviar .

Supongo que te gusta

Origin juejin.im/post/7117630529595244558
Recomendado
Clasificación