安卓APP开发中的屏幕适配问题如何解决?

爷,独闯天下 提交于 2019-12-07 23:46:46

1 为什么要进行Android屏幕适配

 

由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,于是导致: 

  • Android系统碎片化

    小米定制的MIUI、魅族定制的flyme、华为定制的EMUI等等——当然都是基于Google原生系统定制的;

  • Android机型屏幕尺寸碎片化

    5寸、5.5寸、6寸等等;

  • Android屏幕分辨率碎片化

    320x480480x800720x12801080x1920。



屏幕尺寸分布图


   据友盟指数显示,统计至201512月,支持Android的设备共有27796种。Android系统、屏幕尺寸、屏幕密度出现碎片化的时候,就很容易出现同一元素在不同手机上显示不同的问题。

   虽然系统为使您的应用适用于不同的屏幕,会进行缩放和大小调整,但您应针对不同的屏幕尺寸和密度优化应用。 这样可以最大程度优化所有设备上的用户体验,用户会认为您的应用实际上是专为他们的设备而设计,而不是简单地拉伸以适应其设备屏幕。

 

2 相关概念


2.1 屏幕尺寸

  • 含义:按屏幕对角测量的实际物理尺寸。

    为简便起见,Android 将所有实际屏幕尺寸分组为四种通用尺寸:小、 正常、大和超大

  • 单位:英寸(inch),一英寸≈2.54cm


2.2 分辨率

  • 含义:手机在横向、纵向上的像素点数总和

    一般描述成屏幕的”宽x高”=AxB

  • 含义:屏幕在横向方向(宽度)上有A个像素点,在纵向方向

(高)有B个像素点。

例子:1080x1920,即宽度方向上有1080个像素点,在高度方向上有1920个像素点

  • 单位:pxpixel),1px=1像素点

    UI设计师的设计图会以px作为统一的计量单位。

    Android手机常见的分辨率:320x480480x800720x12801080x1920


2.3 屏幕像素密度

  • 含义:每英寸的像素点数

  • 单位:dpidots per ich

    假设设备内每英寸有160个像素,那么该设备的屏幕像素密度=160dpi

  • 安卓手机对于每类手机屏幕大小都有一个相应的屏幕像素密度:

密度类型

代表的分辨率(px

屏幕像素密度(dpi

低密度(ldpi

240x320  

120

中密度(mdpi

320x480  

160

高密度(hdpi

480x800  

240

超高密度(xhdpi   

720x1280         

320

超超高密度(xxhdpi

1080x1920      

480

 

2.4 屏幕尺寸、分辨率、像素密度三者关系

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



2.5 密度无关像素 (dp)

  • 含义:density-independent pixel,叫dpdip,与终端上的实际物理像素点无关。

  • 单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果

  • Android开发时用dp而不是px单位设置图片大小,是Android特有的单位

    场景:假如同样都是画一条长度是屏幕一半的线,如果使用px作为计量单位,那么在480x800分辨率手机上设置应为240px;在320x480的手机上应设置为160px,二者设置就不同了;如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一半的长度。

  • dppx的转换

    因为ui设计师给你的设计图是以px为单位的,Android开发则是使用dp作为单位的,那么我们需要进行转换:


 

密度类型

代表的分辨率(px)

屏幕像素密度(dpi)

换算(px/dp)

比例

 

低密度(ldpi

240x320  

120

1dp=0.75px 

3

中密度(mdpi

320x480  

160

1dp=1px

4

高密度(hdpi 

480x800  

240

1dp=1.5px

6

超高密度(xhdpi

720x1280         

320

1dp=2px

8

超超高密度(xxhdpi

1080x1920      

480

1dp=3px 

12

Android中,规定以160dpi(即屏幕分辨率为320x480)为基准:1dp=1px

 

2.6 独立比例像素

  • 含义:scale-independent pixel,叫spsip

  • 单位:sp

    Android开发时用此单位设置文字大小,可根据字体大小首选项进行缩放。

    推荐使用12sp14sp18sp22sp作为字体设置的大小,不推荐使用奇数和小数,容易造成精度的丢失问题;小于12sp的字体会太小导致用户看不清。

 

3 如何适配

 

3.1 布局适配


3.1.1 使用相对布局(RelativeLayout),禁用绝对布局(AbsoluteLayout)


开发中,我们使用的布局一般有:

  • 线性布局(Linearlayout

  • 相对布局(RelativeLayout

  • 帧布局(FrameLayout

  • 绝对布局(AbsoluteLayout

由于绝对布局(AbsoluteLayout)适配性极差,所以极少使用。

对于线性布局(Linearlayout)、相对布局(RelativeLayout)和帧布局(FrameLayout)需要根据需求进行选择,但要记住:

  • 相对布局RelativeLayout

    布局的子控件之间使用相对位置的方式排列,因为RelativeLayout讲究的是相对位置,即使屏幕的大小改变,视图之前的相对位置都不会变化,与屏幕大小无关,灵活性很强

  • 线性布局LinearLayout

    通过多层嵌套LinearLayout和组合使用“wrap_content”和“match_parent”已经可以构建出足够复杂的布局。但是LinearLayout无法准确地控制子视图之间的位置关系,只能简单的一个挨着一个地排列。


所以,对于屏幕适配来说,使用相对布局(RelativeLayout)将会是更好的解决方案。

 

3.1.2 根据屏幕的配置来加载相应的UI布局


最小宽度(Smallest-width)限定符

Android 3.2及之后版本,引入了最小宽度(Smallest-width)限定符

定义:通过指定某个最小宽度(以 dp 为单位)来精确定位屏幕从而加载不同的UI资源


使用场景:

你需要为标准 7 英寸平板电脑匹配双面板布局(其最小宽度为 600 dp),在手机(较小的屏幕上)匹配单面板布局


解决方案:

您可以使用上文中所述的单面板和双面板这两种布局,但您应使用 sw600dp 指明双面板布局仅适用于最小宽度为 600 dp 的屏幕,而不是使用 large 尺寸限定符。 

sw xxxdp,即small width的缩写,其不区分方向,即无论是宽度还是高度,只要大于 xxxdp,就采用次此布局

例子:使用了layout-sw 600dp的最小宽度限定符,即无论是宽度还是高度,只要大于600dp,就采用layout-sw 600dp目录下的布局


代码展示:

(1)适配手机的单面板(默认)布局:res/layout/main.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  android:orientation="vertical"

  android:layout_width="match_parent"

  android:layout_height="match_parent">

  <fragment android:id="@+id/headlines"

            android:layout_height="fill_parent"

            android:name="com.example.android.newsreader.HeadlinesFragment"

            android:layout_width="match_parent" />

</LinearLayout>


(2)适配尺寸>7寸平板的双面板布局:res/layout-sw600dp/main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="horizontal">

    <fragment android:id="@+id/headlines"

              android:layout_height="fill_parent"

              android:name="com.example.android.newsreader.HeadlinesFragment"

              android:layout_width="400dp"

              android:layout_marginRight="10dp"/>

    <fragment android:id="@+id/article"

              android:layout_height="fill_parent"

              android:name="com.example.android.newsreader.ArticleFragment"

              android:layout_width="fill_parent" />

</LinearLayout>


对于最小宽度≥ 600 dp 的设备,系统会自动加载layout-sw600dp/main.xml(双面板)布局,否则系统就会选择 layout/main.xml(单面板)布局(这个选择过程是Android系统自动选择的)


3.2 布局组件适配


本质:使得布局组件自适应屏幕尺寸


  • 做法

    使用”wrap_content”、”match_parent”和”weight“来控制视图组件的宽度和高度。


  • wrap_content”

    相应视图的宽和高就会被设定成所需的最小尺寸以适应视图中的内容


  • match_parent(Android API 8之前叫作”fill_parent)

    视图的宽和高延伸至充满整个父布局


  • weight”

    定义:是线性布局(Linelayout)的一个独特比例分配属性

    作用:使用此属性设置权重,然后按照比例对界面进行空间的分配,公式计算是:    

控件宽度=控件设置宽度+剩余空间所占百分比宽幅



通过使用”wrap_content”、”match_parent”和”weight”来替代硬编码的方式定义视图大小&位置,你的视图要么仅仅使用了需要的那边一点空间,要么就会充满所有可用的空间,即按需占据空间大小,能让你的布局元素充分适应你的屏幕尺寸。

 

3.3 图片资源适配


本质:使得图片资源在不同屏幕密度上显示相同的像素效果


  • 做法:使用自动拉伸位图:Nine-Patch的图片类型

    假设需要匹配不同屏幕大小,你的图片资源也必须自动适应各种屏幕尺寸


  • 使用场景:一个按钮的背景图片必须能够随着按钮大小的改变而改变。

    使用普通的图片将无法实现上述功能,因为运行时会均匀地拉伸或压缩你的图片


  • 解决方案:使用自动拉伸位图(nine-patch图片),后缀名是.9.png,它是一种被特殊处理过的PNG图片,设计时可以指定图片的拉伸区域和非拉伸区域;使用时,系统就会根据控件的大小自动地拉伸你想要拉伸的部分。


1.必须要使用.9.png后缀名,因为系统就是根据这个来区别nine-patch图片和普通的PNG图片的;

2.当你需要在一个控件中使用nine-patch图片时,如

android:background=”@drawable/button”系统就会根据控件的大小自动地拉伸你想要拉伸的部分


3.4 进行屏幕密度匹配


3.4.1 “布局控件”匹配


本质:使得布局组件在不同屏幕密度上显示相同的像素效果

 

3.4.1.1 做法:使用密度无关像素

 

由于各种屏幕的像素密度都有所不同,因此相同数量的像素在不同设备上的实际大小也有所差异,这样使用像素(px)定义布局尺寸就会产生问题。

因此,请务必使用密度无关像素 dp 或独立比例像素 sp 单位指定尺寸。


3.4.1.2 相关概念介绍

(1)密度无关像素

  • 含义:density-independent pixel,叫dpdip,与终端上的实际物理像素点无关。

  • 单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果


1. Android开发时用dp而不是px单位设置图片大小,是Android特有的单位

2. 场景:假如同样都是画一条长度是屏幕一半的线,如果使用px作为计量单位,那么在480x800分辨率手机上设置应为240px;在320x480的手机上应设置为160px,二者设置就不同了;如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一半的长度。


  • dppx的转换

    因为ui给你的设计图是以px为单位的,Android开发则是使用dp作为单位的,那么该如何转换呢?

密度类型 

代表的分辨率(px

屏幕像素密度(dpi

换算(px/dp

比例

 

低密度(ldpi 

240x320  

120

1dp=0.75px 

3

中密度(mdpi

320x480  

160

1dp=1px

4

高密度(hdpi

480x800  

240

1dp=1.5px

6

超高密度(xhdpi   

720x1280         

320

1dp=2px

8

超超高密度(xxhdpi

1080x1920      

480

1dp=3px 

12

Android中,规定以160dpi(即屏幕分辨率为320x480)为基准:1dp=1px

 

T-Mobile G1(第一款android手机)的参数属于mdpi区域的,以上就是取160dpi作为基准的原因。


(2)独立比例像素

  • 含义:scale-independent pixel,叫spsip

  • 单位:sp


1. Android开发时用此单位设置文字大小,可根据用户的偏好文字大小/字体大小首选项进行缩放

2. 推荐使用12sp14sp18sp22sp作为字体设置的大小,不推荐使用奇数和小数,容易造成精度的丢失问题;小于12sp的字体会太小导致用户看不清


所以,为了能够进行不同屏幕像素密度的匹配,我们推荐:

  • 使用dp来代替px作为控件长度的统一度量单位

  • 使用sp作为文字的统一度量单位


可是,请看以下一种场景:

 Nexus5的总宽度为360dp,我们现在在水平方向上放置两个按钮,一个是150dp左对齐,另外一个是200dp右对齐,那么中间留有10dp间隔;但假如同样地设置在Nexus S(屏幕宽度是320dp),会发现,两个按钮会重叠,因为320dp<200+150dp


从上面可以看出,由于Android屏幕设备的多样性,如果使用dp来作为度量单位,并不是所有的屏幕的宽度都具备相同的dp长度

 
再次明确,屏幕宽度和像素密度没有任何关联关系


所以说,dp解决了同一数值在不同分辨率中展示相同尺寸大小的问题(即屏幕像素密度匹配问题),但却没有解决设备尺寸大小匹配的问题。(即屏幕尺寸匹配问题)

 

当然,我们一开始讨论的就是屏幕尺寸匹配问题,使用match_parentwrap_contentweight,尽可能少用dp来指定控件的具体长宽,大部分的情况我们都是可以做到适配的。


3.4.2 “图片资源”匹配


本质:使得图片资源在不同屏幕密度上显示相同的像素效果


3.4.2.1 做法:提供备用位图(符合屏幕尺寸的图片资源)


由于 Android 可在各种屏幕密度的设备上运行,因此我们提供的位图资源应该始终可以满足各类密度的要求:

密度类型 

代表的分辨率(px 

屏幕像素密度(dpi

低密度(ldpi

240x320  

120

中密度(mdpi

320x480  

160

高密度(hdpi

480x800  

240

超高密度(xhdpi

720x1280         

320

超超高密度(xxhdpi

1080x1920      

480


步骤1:根据以下尺寸范围针对各密度生成相应的图片。

比如说,如果我们为 xhdpi 设备生成了 200x200 px尺寸的图片,就应该按照相应比例地为hdpimdpi  ldpi 设备分别生成 150x150100x100  75x75 尺寸的图片:



即一套分辨率=一套位图资源(这个当然是Ui设计师做了)

 

步骤2:将生成的图片文件放在 res/ 下的相应子目录中(mdpihdpixhdpixxhdpi),系统就会根据运行您应用的设备的屏幕密度自动选择合适的图片。


步骤3:通过引用 @drawable/id,系统都能根据相应屏幕的 屏幕密度(dpi)自动选取合适的位图。

  • 如果是.9图或者是不需要多个分辨率的图片,放在drawable文件夹即可

  • 对应分辨率的图片要正确的放在合适的文件夹,否则会造成图片拉伸等问题。



3.4.2.2 更好的方案解决“图片资源”适配问题


上述方案是常见的一种方案,这固然是一种解决办法,但缺点在于:

  • 每套分辨率出一套图,为美工或者设计增加了许多工作量

  • 对Android工程文件的apk包变的很大

那么,有没有一种方法:

  • 保证屏幕密度适配

  • 可以最小占用设计资源

  • 使得apk包不变大(只使用一套分辨率的图片资源)


方法介绍

先来理解下Android 加载资源过程

Android SDK会根据屏幕密度自动选择对应的资源文件进行渲染加载(自动渲染)。比如说,SDK检测到你手机的分辨率是320x480(dpi=160),会优先到drawable-mdpi文件夹下找对应的图片资源;但假设你只在xhpdi文件夹下有对应的图片资源文件(mdpi文件夹是空的),那么SDK会去xhpdi文件夹找到相应的图片资源文件,然后将原有大像素的图片自动缩放成小像素的图片,于是大像素的图片照样可以在小像素分辨率的手机上正常显示。

具体请看http://blog.csdn.net/xiebudong/article/details/37040263


所以理论上来说只需要提供一种分辨率规格的图片资源就可以了。


那么应该提供哪种分辨率规格呢?


如果只提供ldpi规格的图片,对于大分辨率(xdpixxdpi)的手机如果把图片放大就会不清晰。所以需要提供一套你需要支持的最大dpi分辨率规格的图片资源,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。


那么这一套最大dpi分辨率规格应该是哪种呢?是现在市面手机分辨率最大可达到1080X1920的分辨率(dpi=xxdpi=480)吗?

 

xhdpi应该是首选。原因如下:

  • xhdpi分辨率以内的手机需求量最旺盛

    目前市面上最普遍的高端机的分辨率还多集中在720X1080范围内(xhdpi),所以目前来看xhpdi规格的图片资源成为了首选。

  •  节省设计资源&工作量

    在现在的App开发中(iOSAndroid版本),有些设计师为了保持App不同版本的体验交互一致,可能会以iPhone手机为基础进行设计,包括后期的切图之类的。

 

设计师们一般都会用最新的iPhone6iPhone5s5s5的尺寸以及分辨率都一样)来做原型设计,所有参数请看下图

 

机型

分辨率(px

屏幕尺寸(inch

系统密度(dpi

iPhone 5s

640X1164

4

332

iPhone 6

1334x750 

4.7

326

iPhone 6 Plus

1080x1920

5

400


iPhone主流的屏幕dpi约等于320, 刚好属于xhdpi,所以选择xhdpi作为唯一一套dpi图片资源,可以让设计师不用专门为Android端切图,直接把iPhone的那一套切好的图片资源放入drawable-xhdpi文件夹里就好,这样大大减少的设计师的工作量!

转载请注明:本文来自常州做安卓APP开发http://www.czwew.com紫竹云科技公司!




易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!