Android 屏幕适配方案

二、基本概念

1、像素(px):
  • 含义:通常所说的像素,就是CCD/CMOS上光电感应元件的数量,一个感光元件经过感光,光电信号转换,A/D转换等步骤以后,在输出的照片上就形成一个点,我们如果把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单位“像素”(Pixel)。简而言之,像素就是手机屏幕的最小构成单元
  • 单位:px(pixel),1px = 1像素点 一般情况下UI设计师的设计图会以px作为统一的计量单位。
2、分辨率:
  • 含义:手机在横向、纵向上的像素点数总和 一般描述成 宽*高 ,即横向像素点个数 * 纵向像素点个数(如1080 x 1920)。
  • 单位:px(pixel),1px = 1像素点
3、屏幕尺寸(in):
  • 含义:手机对角线的物理尺寸
  • 单位 英寸(inch),一英寸大约2.54cm 常见的尺寸有4.7寸、5寸、5.5寸、6寸
4、屏幕像素密度(dpi):
  • 含义:每英寸的像素点数。 例如每英寸内有160个像素点,则其像素密度为160dpi。
  • 单位:dpi(dots per inch)
  • 计算公式: 像素密度 = 像素 / 尺寸 (dpi = px / in)
  • 标准屏幕像素密度(mdpi): 每英寸长度上还有160个像素点(160dpi),即称为标准屏幕像素密度(mdpi)。
密度类型代表的分辨率(px)屏幕像素密度(dpi)
低密度(ldpi)240 x 320120
中密度(mdpi)320 x 480160
高密度(hdpi)480 x 800240
超高密度(xhdpi)720 x 1280320
超超高密度(xxhdpi)1080 x 1920480
屏幕尺寸、分辨率、像素密度三者关系

一部手机的分辨率是宽x高,屏幕大小是以寸为单位,那么三者的关系是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

假设一部手机的分辨率是1080x1920(px),屏幕大小是5寸

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5、密度无关像素(dp):

  • 含义:density-independent pixel,叫dp或dip,与终端上的实际物理像素点无关
  • 单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果,是安卓特有的长度单位。
  • 场景例子:假如同样都是画一条长度是屏幕一半的线,如果使用px作为计量单位,那么在480x800分辨率手机上设置应为240px;在320x480的手机上应设置为160px,二者设置就不同了;如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一半的长度。
  • dp与px的转换:1dp = (dpi / 160 ) * 1px;
密度类型代表的分辨率(px)屏幕密度(dpi)换算
低密度(ldpi)240 x 3201201dp = 0.75px
中密度(mdpi)320 x 4801601dp=1px
高密度(hdpi)480 x 8002401dp=1.5px
超高密度(xhdpi)720 x 12803201dp=2px
超超高密度(xxhdpi)1080 x 19204801dp=3px

6、独立比例像素(sp):

  • 含义:scale-independent pixel,叫sp或sip
  • 单位:sp,字体大小专用单位 Android开发时用此单位设置文字大小,可根据字体大小首选项进行缩放; 推荐使用12sp、14sp、18sp、22sp作为字体大小,不推荐使用奇数和小数,容易造成精度丢失,12sp以下字体太小。

7、sp 与 dp 的区别:

  • dp只跟屏幕的像素密度有关;
  • sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。

追到android源码,发现系统内部用applyDimension() (路径:android.util.TypedValue.applyDimension())将所有单位都转换成px 再处理:

/**

  • Converts an unpacked complex data value holding a dimension to its final floating
  • point value. The two parameters unit and value
  • are as in {@link #TYPE_DIMENSION}.
  • @param unit The unit to convert from.
  • @param value The value to apply the unit to.
  • @param metrics Current display metrics to use in the conversion –
  •            supplies display density and scaling information.
    
  • @return The complex floating point value multiplied by the appropriate
  • metrics depending on its unit.
    */
    public static float applyDimension(int unit, float value,
    DisplayMetrics metrics)
    {
    switch (unit) {
    case COMPLEX_UNIT_PX:
    return value;
    case COMPLEX_UNIT_DIP:
    return value * metrics.density;
    case COMPLEX_UNIT_SP:
    return value * metrics.scaledDensity;
    case COMPLEX_UNIT_PT:
    return value * metrics.xdpi * (1.0f/72);
    case COMPLEX_UNIT_IN:
    return value * metrics.xdpi;
    case COMPLEX_UNIT_MM:
    return value * metrics.xdpi * (1.0f/25.4f);
    }
    return 0;
    }

可以发现dp和sp的区别在于density和scaledDensity两个值上;

/**

  • The logical density of the display. This is a scaling factor for the
  • Density Independent Pixel unit, where one DIP is one pixel on an
  • approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen),
  • providing the baseline of the system’s display. Thus on a 160dpi screen
  • this density value will be 1; on a 120 dpi screen it would be .75; etc.
  • This value does not exactly follow the real screen size (as given by

  • {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
  • the overall UI in steps based on gross changes in the display dpi. For
  • example, a 240x320 screen will have a density of 1 even if its width is
  • 1.8", 1.3", etc. However, if the screen resolution is increased to
  • 320x480 but the screen size remained 1.5"x2" then the density would be
  • increased (probably to 1.5).
  • @see #DENSITY_DEFAULT
    */
    public float density;

/**

  • A scaling factor for fonts displayed on the display. This is the same
  • as {@link #density}, except that it may be adjusted in smaller
  • increments at runtime based on a user preference for the font size.
    */
    public float scaledDensity;

三、适配方案

屏幕适配问题的本质是使得布局、布局组件在Android不同尺寸、不同分辨率的手机上具备相同的显示效果,下面我将分几个方面来谈谈如何去适配。

3.1 关于布局组件的适配:
  • 3.1.1 使用密度无关像素指定尺寸
    由于各种屏幕的像素密度都有所不同,因此相同数量的像素在不同设备上的实际大小也会有所差异,这样使用像素(px)定义布局尺寸就会产生问题。 因此,请务必使用密度无关像素 dp 或独立比例像素 sp 单位指定尺寸。

备注 : 在生产过程中,厂家不会完全按照屏幕密度标准去生产Android设备,会在Google的标准周围浮动变化,或是偏离Google的屏幕密度标准比较大,再加上理论计算(开方)造成的误差,实际上使用dp作为单位是不能完完全全的完成适配操作;

  • 3.1.2 使用相对布局或线性布局,不要使用绝对布局
    对于线性布局(Linearlayout)、相对布局(RelativeLayout)、帧布局(FrameLayout)、绝对布局(AbsoluteLayout)以及新增的加强版帧布局(CoordinatorLayout)需要根据需求进行选择,没有绝对而言。
    但因为RelativeLayout讲究的是相对位置,即使屏幕的大小改变,视图之前的相对位置都不会变化,与屏幕大小无关,灵活性很强,而LinearLayout法准确地控制子视图之间的位置关系,只能简单的一个挨着一个地排列,所以,对于屏幕适配来说,使用相对布局(RelativeLayout)将会是更好的解决方案,至于绝对布局由于适配性极差,所以极少使用。

  • 3.1.3 使用wrap_content、match_parent、权重
    使用 “wrap_content” 和 “match_parent” 尺寸值而不是硬编码的尺寸,系统会自动计算相应的数值,视图就会相应地使用自身所需的空间或填满可用空间,让布局正确适应各种屏幕尺寸和屏幕方向,组件的权重比同理。

  • 3.1.4 使用minWidth、minHeight、lines等属性
    很多时候我们显示的数据都是由后台返回的,再由我们加工处理后去适配我们的组件,这些数据的长度我们是无法确定的,而正常情况下我们构思的布局都仅是适用于理想的情况下,为了保证界面的对齐、数据显示完整等等的原因,我们需要在构思布局时增加对组件最小宽高度、行数等属性的设置,确保在特殊的数据下不会破坏我们的整体布局。

  • 3.1.5 dimens使用
    组件的长宽我们可以通过dimens来定义,不同的屏幕尺寸可以定义不同的数值,或者是不同的语言显示我们也可以定义不同的数值,因为翻译后的长度一般都不会跟中文的一致。

3.2 关于布局的适配:

以上几种方式可以解决屏幕适配性的问题,但是那些通过伸缩控件来适应各种不同屏幕大小的布局,未必就是提供了最好的用户体验。你的应用程序应该不仅仅实现了可自适应的布局,还应该提供一些方案根据屏幕的配置来加载不同的布局,可以通过配置限定符(configuration qualifiers)来实现。配置限定符允许程序在运行时根据当前设备的配置自动加载合适的资源(比如为不同尺寸屏幕设计不同的布局)。

  • 3.2.1 使用Size限定符
    很多应用会在较大的屏幕上实施“双面板”模式,即在一个面板上显示项目列表,而在另一面板上显示对应内容。平板电脑和电视的屏幕已经大到可以同时容纳这两个面板了,但手机屏幕就需要分别显示。因此,我们可以使用以下文件以便实施这些布局:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446102583971944.jpg

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446102728277991.jpg

请注意第二种布局名称目录中的 large 限定符。系统会在属于较大屏幕(例如 7 英寸或更大的平板电脑)的设备上选择此布局。系统会在较小的屏幕上选择其他布局(无限定符)。

  • 3.2.2 最小宽度限定符
    使用Size限定符有一个问题会让很多程序员感到头疼,large到底是指多大呢?很多应用程序都希望能够更自由地为不同屏幕设备加载不同的布局,不管它们是不是被系统认定为”large”。这就是Android为什么在3.2以后引入了”Smallest-width”限定符。
    最小宽度限定符可让您通过指定某个最小宽度(以 dp 为单位)来定位屏幕。例如,标准 7 英寸平板电脑的最小宽度为 600 dp,因此如果您要在此类屏幕上的用户界面中使用双面板(但在较小的屏幕上只显示列表),您可以使用上文中所述的单面板和双面板这两种布局,但您应使用 sw600dp 指明双面板布局仅适用于最小宽度为 600 dp 的屏幕,而不是使用 large 尺寸限定符。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446102760481409.jpg

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446102807853454.jpg

也就是说,对于最小宽度大于等于 600 dp 的设备,系统会选择 layout-sw600dp/main.xml(双面板)布局,否则系统就会选择 layout/main.xml(单面板)布局。

但 Android 版本低于 3.2 的设备不支持此技术,原因是这些设备无法将 sw600dp 识别为尺寸限定符,因此我们仍需使用 large 限定符。这样一来,就会有一个名称为 res/layout-large/main.xml 的文件(与 res/layout-sw600dp/main.xml 一样)。但是没有太大关系,我们将马上学习如何避免此类布局文件出现的重复。

  • 3.2.3 使用布局别名
    最小宽度限定符仅适用于 Android 3.2 及更高版本。因此,如果我们仍需使用与较低版本兼容的概括尺寸范围(小、正常、大和特大)。例如,如果要将用户界面设计成在手机上显示单面板,但在 7 英寸平板电脑、电视和其他较大的设备上显示多面板,那么我们就需要提供以下文件:

res/layout/main.xml: 单面板布局 res/layout-large: 多面板布局 res/layout-sw600dp: 多面板布局

后两个文件是相同的,因为其中一个用于和 Android 3.2 设备匹配,而另一个则是为使用较低版本 Android 的平板电脑和电视准备的。

要避免平板电脑和电视的文件出现重复(以及由此带来的维护问题),您可以使用别名文件。例如,您可以定义以下布局:

  • res/layout/main.xml,单面板布局

  • res/layout/main_twopanes.xml,双面板布局

然后添加这两个文件:

res/values-large/layout.xml:

![QQ截图20151029151423.jpg](https://user-gold-cdn.xitu.io/2018/4/27/1630762b8eba4d72?imageView2/0/w/128
0/h/960/ignore-error/1)

1446102885594589.jpg

res/values-sw600dp/layout.xml:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446102894526452.jpg

后两个文件的内容相同,但它们并未实际定义布局。它们只是将 main 设置成了 main_twopanes 的别名。由于这些文件包含 large 和 sw600dp 选择器,因此无论 Android 版本如何,系统都会将这些文件应用到平板电脑和电视上(版本低于 3.2 的平板电脑和电视会匹配 large,版本高于 3.2 的平板电脑和电视则会匹配 sw600dp)。

  • 3.2.4 使用屏幕方向限定符
    某些布局会同时支持横向模式和纵向模式,但我们可以通过调整优化其中大部分布局的效果。在新闻阅读器示例应用中,每种屏幕尺寸和屏幕方向下的布局行为方式如下所示:

小屏幕,纵向:单面板,带徽标
小屏幕,横向:单面板,带徽标
7 英寸平板电脑,纵向:单面板,带操作栏
7 英寸平板电脑,横向:双面板,宽,带操作栏
10 英寸平板电脑,纵向:双面板,窄,带操作栏
10 英寸平板电脑,横向:双面板,宽,带操作栏
电视,横向:双面板,宽,带操作栏

因此,这些布局中的每一种都定义在了 res/layout/ 目录下的某个 XML 文件中。为了继续将每个布局分配给各种屏幕配置,该应用会使用布局别名将两者相匹配:

res/layout/onepane.xml:(单面板)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446102945879746.jpg

res/layout/onepane_with_bar.xml:(单面板带操作栏)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446102982969502.jpg

res/layout/twopanes.xml:(双面板,宽布局)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446103034115365.jpg

res/layout/twopanes_narrow.xml:(双面板,窄布局)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446103047709192.jpg

既然我们已定义了所有可能的布局,那就只需使用配置限定符将正确的布局映射到各种配置即可。

现在只需使用布局别名技术即可做到这一点:

res/values/layouts.xml:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446103188926681.jpg

res/values-sw600dp-land/layouts.xml:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446103198972935.jpg

res/values-sw600dp-port/layouts.xml:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446103206749499.jpg

res/values-large-land/layouts.xml:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446103214277258.jpg

res/values-large-port/layouts.xml:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1446103221453853.jpg

  • 3.2.5 多套layout适配
    res/values/layouts.xml: res/values-sw600dp-land/layouts.xml: res/values-sw600dp-port/layouts.xml: res/values-large-land/layouts.xml: res/values-large-port/layouts.xml:
3.3 关于图片的适配:
  • 3.3.1 LOGO 图标
    建议按官方标准准备好各个图标;
屏幕密度对应的图片大小图片资源目录
120dip36px * 36pxmipmap-ldpi
160dip(基准)48px * 48pxmipmap或者mipmap-mdpi
240dip(1.5倍)72px * 72pxmipmap-hdpi
320dip (2倍)96px * 96pxmipmap-xhdpi
480dip (3倍)144px * 144pxmipmap-xxhdpi
640dip (4倍)192px * 192pxmipmap-xxxhdpi
  • 3.3.2 普通图片和图标
    建议安装官方的密度类型进行切图即可,但一般我们只需xxhdpi或xxxhdpi的切图即可满足我们的需求;

  • 3.3.3 自动拉伸位图:Nine-Patch的图片类型
    支持不同屏幕大小通常情况下也意味着,你的图片资源也需要有自适应的能力。例如,一个按钮的背景图片必须能够随着按钮大小的改变而改变。 如果你想使用普通的图片来实现上述功能,你会发现这是难以实现的,因为运行时会均匀地拉伸或压缩你的图片。解决方案是使用nine-patch图片,它是一种被特殊处理过的PNG图片,你可以指定哪些区域可以拉伸而哪些区域不可以。

  • 3.3.4 动画、自定义view、shape
    可以使用代码进行控制和展示多种视图,如patch动画替代帧动画。

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

如果你需要这些资料, ⬅ 专栏获取
nm-1719168201914)]

[外链图片转存中…(img-UTQBsf7t-1719168201914)]

[外链图片转存中…(img-W2Mkx7Wz-1719168201915)]

[外链图片转存中…(img-wKLmlk81-1719168201915)]

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

如果你需要这些资料, ⬅ 专栏获取

  • 12
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值