前言
Android屏幕碎片化严重,适配ui是一件让人头疼的问题。想完成屏幕适配,深入了解Android UI展示机制是有必要的。
本文参考了:
- Android开发者文档-Supporting Different Screens
- Android开发者文档-Supporting Multiple Screens
- 郭霖-Android官方提供的支持不同屏幕大小的全部方法有问题或者不好的地方欢迎评论互相探讨,你的评论是我的最大动力
需了解的概念
- 屏幕尺寸
指屏幕对角线的物理尺寸(inch),1英寸=2.54cm
- 屏幕分辨率
指屏幕横纵向像素点(px),例:1920x1080、2560x1440
- 屏幕像素密度
每英寸的像素点(dpi)
- 屏幕无关像素
指与屏幕像素点无关的表示单位(dp/dip),主要用于限定控件大小
密度类型 | 分辨率 | 像素密度 | 像素密度范围 | 换算(dp->px) |
---|---|---|---|---|
ldpi | 320x240 | 120 | 0~120 | 1dp -> 0.75px |
mdpi | 480x320 | 160 | 120~160 | 1dp -> 1px |
hpdi | 800x480 | 240 | 160~240 | 1dp -> 1.5px |
xhdpi | 1280x720 | 320 | 240~320 | 1dp -> 2px |
xxhdpi | 1920x1080 | 480 | 320~480 | 1dp -> 3px |
xxxhdpi | 2560x1440 | 640 | 480~640 | 1dp -> 4px |
- 独立比例像素
指文字的统一度量单位(sp),主要用于限定字体大小,会根据用户的字体大小首选项进行缩放
- 比较dp-sp
<!--分析applyDimension-->
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 22, getResources().getDisplayMetrics())
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->px公式:value * metrics.density
sp->px公式:value * metrics.scaledDensity
调整首选项中字体大小,density不会变化,scaledDensity跟随字号变化。因此有特殊需求的情况,不让应用字体跟随设置中字号变化,可直接调整scaledDensity的值。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Resources.getSystem().getDisplayMetrics().scaledDensity = Resources.getSystem().getDisplayMetrics().density;
getResources().getDisplayMetrics().scaledDensity = getResources().getDisplayMetrics().density;
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Resources.getSystem().getDisplayMetrics().scaledDensity = Resources.getSystem().getDisplayMetrics().density;
getResources().getDisplayMetrics().scaledDensity = getResources().getDisplayMetrics().density;
}
}
- Android资源加载流程
假设手机分辨率为1920x1080,屏幕密度为480dpi
1. 系统首先会寻找是否有480dpi(即xxhdpi)的目录,是否存在对应图片
2. 如果找到就使用该目录下的图片,如果没有就一直往更高屏幕密度的目录寻找
3. 如果更高的屏幕密度目录下存在该图片,则直接使用,如果不存在则寻找低屏幕密度的目录,直至找到
使用RelativeLayout(这个就不详细解释了)
较其他的布局,更能精确的调整view位置
使用wrap_content和match_parent(这个就不详细解释了)
确保你的布局能够自适应各种不同屏幕大小
使用.9图片
避免图片拉伸、变形
限定符
从上到下,优先级依次递减
配置 | 限定符 |
---|---|
MCC MNC | mcc310 |
语言 | en-rUS |
布局方向 | ldrtl ldltr |
最小宽度限定符 | sw320dp |
可获得宽度 | w720dp |
可获得高度 | h720dp |
屏幕尺寸 | large |
屏幕方面 | long notlong |
屏幕方向 | port land |
UI模式 | car appliance watch |
夜晚模式 | night notnight |
屏幕像素密度 | mdpi nodpi |
触摸屏幕类型 | notouch finger |
* 例如values-xxhdpi-1080x1800要和values-xxhdpi配合使用,当在xxhdpi没匹配到对应分辨率的数据时,将会在xxhdpi中去匹配,不会匹配错分辨率
百分比布局
动态生成px
- 代码生成某一分辨率下的dp对应px值
使用分辨率限定符,创建不同分辨率下的dp数值文件
- 注意:最好加上屏幕密度限定符一起限制会更加精准(values-xxhdpi-1080x1800)。在分辨率1080x1800下,可能适配不到values-1800x1080目录,使用以下代码检查对应分辨率及密度。
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int widthPixels = displayMetrics.widthPixels; // 真实宽度分辨率
int heightPixels = displayMetrics.heighthPixels; // 真实高度分辨率
int densityDPI = displayMetrics.densityDpi; // 屏幕密度