介于目前的Android设备存在有不同的屏幕尺寸,屏幕分辨率,像素密度,Android应用在开发的过程必须要考虑到屏幕尺寸适配的问题,以保证在不同尺寸的Android设备上都能够正常运行。
在开始说明适配方案之前,我们首先需要对如下几个概念了若指掌:屏幕尺寸,屏幕分辨率,屏幕像素密度。
屏幕尺寸是指的设备对角线的物理尺寸,常用单位为英寸。
1英寸 = 2.54cm
屏幕分辨率指的是设备在横向、纵向上的像素总和,常用宽*高的方式来描述。
宽指的是在横向上的像素点数,高是在纵向上的像素点数。
如480*600,则表示在横向上有480个像素点,在纵向上有600个像素点。
屏幕像素密度指的是设备每英寸的像素点数,单位dpi。
屏幕尺寸以160个像素作为基准,假设设备的每英寸有160个像素,则设备密度为160dpi,为1倍图适配。
倍图对应关系:
密度类型 | 分辨率 | dpi | dp换算 |
---|---|---|---|
低密度(ldpi) | 240x320 | 120 | 1dp=0.75px |
中密度(mdpi) | 320x480 | 160 | 1dp=1px |
高密度(hdpi) | 480x800 | 240 | 1dp=1.5px |
超高密度(xhdpi) | 720x1280 | 320 | 1dp=2px |
超超高密度(xxhdpi) | 1080x1920 | 480 | 1dp= 3px |
Android常见的UI适配方案主要包括如下几种:
多layout适配主要是针对某个分辨率,新建一个layout文件夹,名称为:layout-1024*600
,横屏layout-land-1024*600
。
这种方法多见于横屏的特殊适配,如果横屏的UI和竖屏的UI差距非常大的情况下,可以为横屏单独设置布局。
屏幕限定符适配,是针对不同屏幕的分辨率创建values-xxx的文件夹,在遇到对应的屏幕分辨率时就可以找到对应的values文件夹,查找文件夹下的dimens.xml文件,确定每个屏幕尺寸下显示控件的大小。如下图:
然后对每个values对应的不同屏幕分辨率,生成各种分辨率下面的dimens.xml文件。
720px
需要注意的是采用此种方法,在每个dimens.xml文件里定义的尺寸大小多为px(像素),然而我们在实际的Android开发过程中遇到的开发尺寸多为dp,因此在实际的开发中此种方法使用场景并不是很频繁。
smallestWidth限定符适配原理和屏幕分辨率限定符适配一样,都是通过创建多个values文件夹,系统根据限定符去寻找对应的dimens.xml文件,以确定不同设备上的大小展示,如下图:
和屏幕分辨率限定符屏幕分辨率限定符适配是拿 px 值等比例缩放不同的是, smallestWidth 限定符适配是拿 dp 值来等比缩放。
需要注意的是,最小宽度的宽度是不区分方向的,也就是对于设备来说无论是宽度还是高度,哪一边更小就认为哪一边是“最小宽度”。
如果要在代码中设置大小,可以使用如下工具类:
public class ScreenSizeUtil {
/**
* 计算当前的SP的值
* @param context
* @param spSize :R.dimen.sp_16
* @return
*/
public static int getSP(Context context,@DimenRes int spSize){
float pxValue = context.getResources().getDimension(spSize);//获取对应资源文件下的sp值
//将px值转换成sp值
return px2sp(context, pxValue);
}
/**
* 计算当前的DP的值
* @param context
* @param dpSize :R.dimen.dp_16
* @return
*/
public static int getDP(Context context,@DimenRes int dpSize){
float pxValue = context.getResources().getDimension(dpSize);//获取对应资源文件下的sp值
//将px值转换成sp值
return px2dip(context, pxValue);
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
if (context == null) {
return (int) dpValue;
}
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
if (context == null) {
return (int) pxValue;
}
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* px转换为sp
* @param context
* @param pxValue
* @return
*/
public static int px2sp(Context context,float pxValue){
if (context == null) {
return (int) pxValue;
}
final float scale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / scale + 0.5f);
}
}
虽然和分辨率限定符适配原理相同,都需要设置多个dimens.xml文件,但是在实际的开发过程中,还是相对建议使用smallestWidth限定符适配,其具有如下优势:
和IOS设备不一样的是,Android设备有着多种多样的屏幕分辨率,因此如果采用屏幕分辨率来适配的话,则需要非常多的values,如果你没有适配对应分辨率的设备,则很有可能导致适配变形。
而实际上绝大部分的设备的最小宽度都大于360dp,这样的话smallestWidth限定符适配就不需要进行大量适配,而只需要添加少量的dimens.xml文件即可。
屏幕分辨率适配的单位是px(像素),而基于Android设备不同的像素密度,这个单位在实际的开发中是很少会用到的。
smallestWidth限定符适配中的dan’wi单位是dp,对于文本大小也支持采用sp适配,在开发过程中十分便捷。
屏幕分辨率限定符适配需要设备分辨率与 values-xx 文件夹完全匹配才能达到适配,如果不能完全匹配,则适配有可能无效而导致UI大幅变形。
而 smallestWidth 限定符适配寻找 dimens.xml 文件的原理是从大往小找,例如设备的最小宽度为 360dp,就会先去找 values-360dp,发现没有则会向下找 values-320dp,如果还是没有才找默认的 values 下的 demens.xml 文件,所以即使没有完全匹配也能达到不错的适配效果。
鉴于需要生成多个dimens.xml文件,手动添加的代价过于高昂,而且当前已经有插件可以自动生成,目前推荐使用插件:ScreenMatch。
和其他插件的安装一样,Android Studio可以通过Plugin Marketplace中查找插件,如下(图中由于我已经安装成功):
在MarketPlace中找到ScreenMatch点击安装即可。
有可能在访问插件库时,MarketPlace加载不出来,可能需要魔法上网;或者访问插件库地址下载插件安装到本地也可以:https://plugins.jetbrains.com/
我们需要添加一分dimens.xml文件作为适配的基准,文件内容主要声明尺寸,可参考附录。
在插件导入之后,可以在values文件夹右键,选择ScreenMatch选项,然后选择在你添加了dimens.xml文件的module下执行,即可生成多个values文件夹。
在使用了ScreenMatch时,在Module层级的目录下会有一个ScreenMatch配置文件——screenMatch.properties,在其中可以更新配置,如果要更新需要适配的尺寸,可以在如下的代码中进行变动:
base_dp=600
# Also need to match the phone screen of [match_dp].
# If you have another dp values.
# System default values is 320,360,384,400,432,446.5,480,540,592,600,640,662,720,768,800,820,960,1024,1280,1365
base_dp
是你的基准尺寸,可以在System default values
中添加你需要适配的尺寸,然后重新执行第三步重新生成values及对应的dimens.xml文件。
接下来就是在布局xml文件中去使用大小了,可以采用@dimen/dp_12
类似的方式来获取大小。
举例来说,如果要设计一个大小为宽为100dp,高为80dp的按钮,文字大小为20sp,可以在布局中这么写:
这样的话,系统就会根据当前设备的宽度dp去对应的dimens.xml文件中查到对应的长度了。
代码中的话则需要通过getDimension()
方法获取对应资源文件下的大小,工具类如下:
public class ScreenSizeUtil {
/**
* 计算当前的SP的值
* @param context
* @param spSize :R.dimen.sp_16
* @return
*/
public static int getSP(Context context,@DimenRes int spSize){
float pxValue = context.getResources().getDimension(spSize);//获取对应资源文件下的sp值
//将px值转换成sp值
return px2sp(context, pxValue);
}
/**
* 计算当前的DP的值
* @param context
* @param dpSize :R.dimen.dp_16
* @return
*/
public static int getDP(Context context,@DimenRes int dpSize){
float pxValue = context.getResources().getDimension(dpSize);//获取对应资源文件下的sp值
//将px值转换成sp值
return px2dip(context, pxValue);
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
if (context == null) {
return (int) dpValue;
}
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
if (context == null) {
return (int) pxValue;
}
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* px转换为sp
* @param context
* @param pxValue
* @return
*/
public static int px2sp(Context context,float pxValue){
if (context == null) {
return (int) pxValue;
}
final float scale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / scale + 0.5f);
}
}
本文简述了smallestWidth这一常见的UI适配方法,相对于屏幕尺寸适配和多layout适配来说更加常见。
dimens.xml文件
@dimen/dp_15
-60dp
-30dp
-20dp
-12dp
-10dp
-8dp
-5dp
-2dp
-1dp
0dp
0.1dp
0.5dp
1dp
1.5dp
2dp
2.5dp
3dp
3.5dp
4dp
4.5dp
5dp
6dp
7dp
8dp
9dp
10dp
11dp
12dp
13dp
14dp
15dp
16dp
17dp
18dp
19dp
20dp
21dp
22dp
23dp
24dp
25dp
26dp
27dp
28dp
29dp
30dp
31dp
32dp
33dp
34dp
35dp
36dp
37dp
38dp
39dp
40dp
41dp
42dp
43dp
44dp
45dp
46dp
47dp
48dp
49dp
50dp
51dp
52dp
53dp
54dp
55dp
56dp
57dp
58dp
59dp
60dp
61dp
62dp
63dp
64dp
65dp
66dp
67dp
68dp
69dp
70dp
71dp
72dp
73dp
74dp
75dp
76dp
77dp
78dp
79dp
80dp
81dp
82dp
83dp
84dp
85dp
86dp
87dp
88dp
89dp
90dp
91dp
92dp
93dp
94dp
95dp
96dp
97dp
98dp
99dp
100dp
101dp
102dp
103dp
104dp
105dp
106dp
107dp
108dp
109dp
110dp
111dp
112dp
113dp
114dp
115dp
116dp
117dp
118dp
119dp
120dp
121dp
122dp
123dp
124dp
125dp
126dp
127dp
128dp
129dp
130dp
131dp
132dp
133dp
134dp
135dp
136dp
137dp
138dp
139dp
140dp
141dp
142dp
143dp
144dp
145dp
146dp
147dp
148dp
149dp
150dp
151dp
152dp
153dp
154dp
155dp
156dp
157dp
158dp
159dp
160dp
161dp
162dp
163dp
164dp
165dp
166dp
167dp
168dp
169dp
170dp
171dp
172dp
173dp
174dp
175dp
176dp
177dp
178dp
179dp
180dp
181dp
182dp
183dp
184dp
185dp
186dp
187dp
188dp
189dp
190dp
191dp
192dp
193dp
194dp
195dp
196dp
197dp
198dp
199dp
200dp
201dp
202dp
203dp
204dp
205dp
206dp
207dp
208dp
209dp
210dp
211dp
212dp
213dp
214dp
215dp
216dp
217dp
218dp
219dp
220dp
221dp
222dp
223dp
224dp
225dp
226dp
227dp
228dp
229dp
230dp
231dp
232dp
233dp
234dp
235dp
236dp
237dp
238dp
239dp
240dp
241dp
242dp
243dp
244dp
245dp
246dp
247dp
248dp
249dp
250dp
251dp
252dp
253dp
254dp
255dp
256dp
257dp
258dp
259dp
260dp
261dp
262dp
263dp
264dp
265dp
266dp
267dp
268dp
269dp
270dp
271dp
272dp
273dp
274dp
275dp
276dp
277dp
278dp
279dp
280dp
281dp
282dp
283dp
284dp
285dp
286dp
287dp
288dp
289dp
290dp
291dp
292dp
293dp
294dp
295dp
296dp
297dp
298dp
299dp
300dp
301dp
302dp
303dp
304dp
305dp
306dp
307dp
308dp
309dp
310dp
311dp
312dp
313dp
314dp
315dp
316dp
317dp
318dp
319dp
320dp
321dp
322dp
323dp
324dp
325dp
326dp
327dp
328dp
329dp
330dp
331dp
332dp
333dp
334dp
335dp
336dp
337dp
338dp
339dp
340dp
341dp
342dp
343dp
344dp
345dp
346dp
347dp
348dp
349dp
350dp
351dp
352dp
353dp
354dp
355dp
356dp
357dp
358dp
359dp
360dp
365dp
370dp
400dp
410dp
422dp
472dp
500dp
600dp
640dp
720dp
376dp
383dp
412dp
420dp
441dp
460dp
552dp
554dp
622dp
6sp
7sp
8sp
9sp
10sp
11sp
12sp
13sp
14sp
15sp
16sp
17sp
18sp
19sp
20sp
21sp
22sp
23sp
24sp
25sp
27sp
28sp
30sp
31sp
32sp
34sp
36sp
38sp
40sp
42sp
44sp
48sp
56sp
64sp
70sp
72sp
```![多layout.jpg](https://img-blog.csdnimg.cn/img_convert/685686ef374b0567b7ebeae112419655.png)