自 Android 智能手机于2008年10月发布至今,已有十几年的历史,在这十几年里,Android 版本不断发生变化,搭载 Android 系统的设备也在不断的发生变化,屏幕的分辨率也从一开始的 320x480 分辨率到 1440x2560 分辨率。
Android 官方似乎一开始就意识到 app 的适配问题,推出了多达六种的像素单位,不同的单位针对不同的使用场景,分别是:dp
、px
、sp
、pt
、mm
、in
。
- dp :用于布局尺寸。
- px :表示屏幕上的实际像素数目。
- sp :用于文本大小。
- pt :用于印刷和排版。
- mm :用于确保在屏幕上的物理尺寸一致。
- in :用于确保物理尺寸一致。
虽然推出了 '如此之多' 的像素单位,但并不能根治屏幕适配的问题,于是,第一种适配方案应运而生。
系统自适应
系统自适应,是什么意思呢?
其实就是,准备好多个屏幕的尺寸,应用在安装的时候根据设备屏幕的密度自动选择合适的资源文件。
它的原理与 drawable
、mipmap
文件的原理相同,都是安装应用后,Android 系统会根据设备屏幕的密度自动选择合适的资源文件。这也就是为什么优化安装包大小时,部分博主会给出尽量只使用 mipmap-xhdpi
的原因之一,图片资源是真的占用 App 大小。
通过系统自适应的方式实现系统自适应屏幕大小,需要运行一套 Java
代码,运行 Java
代码的 main
函数来创建对应的屏幕分辨率。
java
public class MakeXml {
// 生成地址 C 盘layoutroot目录下,这个路径可以更改
private final static String rootPath = "C:\\layoutroot\\values-{0}x{1}\\";
/**
* 设置基准分辨率
* 一般标注按照多大的图标,这里我们就设置多大尺寸,单位:px
*/
private final static float dw = 1080f;
private final static float dh = 1920f;
private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";
private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n";
private final static String INDENTATION_TAG1 = " ";
// 手机分辨率
public static void main(String [] args){
makeString(320, 480);
makeString(480, 800);
makeString(480, 854);
makeString(540, 960);
makeString(600, 1024);
makeString(720, 1184);
makeString(720, 1196);
makeString(720, 1280);
makeString(768, 1024);
makeString(800, 1280);
makeString(1080, 1812);
makeString(1080, 1920);
makeString(1440, 2560);
}
public static void makeString(int w, int h) {
StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sb.append("<resources>\n");
float cellw = w / dw;
for (int i = 0; i < dw; i++) {
sb.append(INDENTATION_TAG1);
sb.append(WTemplate.replace("{0}", i + "").replace("{1}", change(cellw * i) + ""));
}
//此处可将1080换为自己的基准尺寸宽度
sb.append(INDENTATION_TAG1);
sb.append(WTemplate.replace("{0}", "1080").replace("{1}", w + ""));
sb.append("</resources>");
StringBuffer sb2 = new StringBuffer();
sb2.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sb2.append("<resources>\n");
float cellh = h / dh;
for (int i = 0; i < dh; i++) {
sb2.append(INDENTATION_TAG1);
sb2.append(HTemplate.replace("{0}", i + "").replace("{1}", change(cellh * i) + ""));
}
//此处可将1920换为自己的基准尺寸高度
sb2.append(INDENTATION_TAG1);
sb2.append(HTemplate.replace("{0}", "1920").replace("{1}", h + ""));
sb2.append("</resources>");
String path = rootPath.replace("{0}", h + "").replace("{1}", w + "");
File rootFile = new File(path);
if (!rootFile.exists()) {
rootFile.mkdirs();
}
File layxFile = new File(path + "lay_x.xml");
File layyFile = new File(path + "lay_y.xml");
try {
PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
pw.print(sb.toString());
pw.close();
pw = new PrintWriter(new FileOutputStream(layyFile));
pw.print(sb2.toString());
pw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static float change(float a) {
int temp = (int) (a * 100);
return temp / 100f;
}
}
执行成功后会在指定的地址生成各种屏幕分辨率的目录,根据自己设计图的尺寸,添加相对应的尺寸的 dimen
值放至 res/values/dimen.xml
,作为基本的设计尺寸。然后再其它的文件拷贝至项目的 res
目录下,使用 xml
编写 UI
时,组件的宽度从 dimen
中选择,接着运行项目,即可完成适配。
PS:
1、该方式目前在手机上测试是正常的,不同的分辨率系统会在打开应用的时候自动切换成对应的分辨率。问题出在于开发板上,
部分开发板只支持默认的分辨率,应用打开后系统不会自动选择合适的分辨率
。2、屏幕适配工作在项目开发初期就应该去做了,越是拖后面,屏幕的适配难度就越大。
AndroidAutoSize
如果 系统自适应 的适配方式不起效果,可以使用 AndroidAutoSize
框架去实现屏幕适配。
AndroidAutoSize
和 系统自适应 的方式实现的原理各不相同,因此 系统自适应 实现不了适配的时候可以使用 AndroidAutoSize
去做,虽然也会有点坑,但完全可以通过 AndroidAutoSize
的 issues
给出的方式去处理问题。
AndroidAutoSize
的使用出奇的简单,只需要两个步骤即可实现适配:
- 第一步:添加依赖
groovy
dependencies {
implementation 'me.jessyan:autosize:1.2.1'
}
- 第二步:在
AndroidManifest.xml
文件添加屏幕尺寸
xml
<manifest>
<application>
<!-- 设计稿大小,根据项目自行设置 -->
<meta-data
android:name="design_width_in_dp"
android:value="360" />
<meta-data
android:name="design_height_in_dp"
android:value="640" />
</application>
</manifest>
这样就完成了 AndroidAutoSize
对屏幕的适配工作。
点击前往 👉 AndroidAutoSize
AndroidAutoSize 存在的问题
1、无法适配
Dialog
,需要自己手动去设置、自定义的方式去调整Dialog
的大小。2、横屏应用部分情况会适配失败,
AndroidAutoSize
出现的问题可查看Github
的issues
,作者已在issues
公布了部分问题出现的原因与处理方法。