| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
这是一篇关于Android屏幕适配的介绍,首先声明,不建议使用px作为单位,原因大家都知道。 ###图片镇楼

看到这两张图相信大家都不陌生了,没错,这就是苦逼的适配,在2012年,OpenSignalMaps发布了第一份Android碎片化报告,统计数据表明,
2012年,支持Android的设备共有3997种。
2013年,支持Android的设备共有11868种。
2014年,支持Android的设备共有18796种。
···
2017年...?
首先需要介绍一些概念:
原文地址
换算关系:
px = dp * (dpi / 160),原来这里的dpi是归一化后的dpi。
则dp = px / (ppi / 160)
ppi = √(长度像素数² + 宽度像素数²) / 屏幕对角线英寸数
dp*ppi/160 = px。比如1dp x 320ppi/160 = 2px。
dependencies {
...
implementation 'com.github.sing1:UIAdapter:last_version'
}或者使用后面的代码自己生成,然后考到项目中,或者下载library中的代码拷贝,这个库适配的机型有:
| 240x320 120dpi | 240x400 120dpi | 240x432 120dpi | 320x480 160dpi | 480x640 240dpi |
|---|---|---|---|---|
| 480x800 120dpi | 480x800 160dpi | 480x800 240dpi | 480x854 120dpi | 480x854 160dpi |
| 480x854 240dpi | 640x960 320dpi | 600x1024 160dpi | 600x1024 240dpi | 600x1024 120dpi |
| 720x1280 160dpi | 720x1280 240dpi | 720x1280 320dpi | 768x1280 320dpi | 768x1024 160dpi |
| 768x1280 160dpi | 768x1280 240dpi | 800x1280 320dpi | 800x1280 160dpi | 800x1280 213dpi |
| 1080x1920 420dpi | 1080x1920 480dpi | 1200x1920 320dpi | 1440x2560 560dpi | 1152x1536 240dpi |
| 1152x1920 240dpi | 1200x1920 240dpi | 1536x2048 320dpi | 1536x2560 320dpi | 1600x2560 320dpi |
| 1080x2400 440dpi | 1080x2252 440dpi | 1080x2296 440dpi |
这个其中包括了横屏和竖屏,下面是生成文件的代码:
// 竖屏文件的输出路劲
private final static String rootPathPort = "/Users/Sing/Desktop/res/values-port-{0}dpi-{1}x{2}/";
// 横屏文件的输出路劲
private final static String rootPathLand = "/Users/Sing/Desktop/res/values-land-{0}dpi-{1}x{2}/";
// 水平方向(X)的值
private final static String templateX = " <dimen name=\"dp_{0}_x\">{1}dp</dimen>\n";
// 垂直方向(Y)的值
private final static String templateY = " <dimen name=\"dp_{0}_y\">{1}dp</dimen>\n";
// 默认模板信息,及参照尺寸,这里用的是1280x720 320dpi
private static int defaultDpi = 320;
private static int defaultWidth = 720;
private static int defaultHeight = 1280;
private static double defaultScale = 2.0;
// 将double类型的数据保留两位小数
public static String twoDemal(double num) {
DecimalFormat dFormat = new DecimalFormat("##0.00");
String result = dFormat.format(num);
return result;
}
// 传入宽、高、DPI生成
public static void makeString(int w, int h, int dpi) {
makeValue(w,h,dpi,0);// 竖屏X
makeValue(w,h,dpi,1);// 竖屏Y
makeValue(w,h,dpi,2);// 横屏X
makeValue(w,h,dpi,3);// 横屏Y
}
// type 0-3 分别为 竖屏X、竖屏Y、横屏X、横屏Y
private static void makeValue(int w, int h, int dpi, int type) {
double scale = ((double) dpi / 160); // 缩放比例
double totalWidthDp = defaultWidth / defaultScale; // 机型水平方向总共有多少个DP
double totalHeightDp = defaultHeight / defaultScale; // 机型垂直方向总共有多少个DP
double portWidthValue = (double) w / scale / totalWidthDp; // 竖屏情况下,参考模板水平方向(X) 每1dp对应的适配机型的值
double portHeightValue = (double) h / scale / totalHeightDp;// 竖屏情况下,参考模板垂直方向(Y) 每1dp对应的适配机型的值
double landWidthValue = ((double) h / w) * portWidthValue;// 横屏情况下,参考模板水平方向(X) 每1dp对应的适配机型的值
double landHeightValue = ((double) w / h) * portHeightValue;// 横屏情况下,参考模板垂直方向(Y) 每1dp对应的适配机型的值
String rootPath = "";// 实际输出的路径
File layFile = null;
String fileName = "";
StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");// 文件头
sb.append("<resources>\n");// 文件头
if (type == 0) { // 竖屏 X
for (int i = 1; i <= 200; i++) {
sb.append(templateX.replace("{0}", i + "").replace("{1}", twoDemal(portWidthValue * i) + ""));
}
rootPath = rootPathPort;
fileName = "dimens_x.xml";
} else if (type == 1) {// 竖屏 Y
for (int i = 1; i <= 200; i++) {
sb.append(templateY.replace("{0}", i + "").replace("{1}", twoDemal(portHeightValue * i) + ""));
}
rootPath = rootPathPort;
fileName = "dimens_y.xml";
} else if (type == 2) {// 横屏 X
for (int i = 1; i <= 200; i++) {
sb.append(templateX.replace("{0}", i + "").replace("{1}", twoDemal(landWidthValue * i) + ""));
}
fileName = "dimens_x.xml";
rootPath = rootPathLand;
} else if (type == 3) {// 横屏 Y
for (int i = 1; i <= 200; i++) {
sb.append(templateY.replace("{0}", i + "").replace("{1}", twoDemal(landHeightValue * i) + ""));
}
rootPath = rootPathLand;
fileName = "dimens_y.xml";
}
sb.append("</resources>");// 文件尾
String path = rootPath.replace("{0}", dpi + "").replace("{1}", h + "").replace("{2}", w + "");
File rootFile = new File(path);
if (!rootFile.exists()) {
rootFile.mkdirs();
}
layFile = new File(path + fileName);
try {
PrintWriter pw = new PrintWriter(new FileOutputStream(layFile));
pw.print(sb.toString());
pw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
// 入口在这里,想生成什么机型就传入什么机型的信息,
public static void main(String[] args) {
makeString(720, 1280, 320);
makeString(1080, 1920, 480);
// 这里可以输出你想要适配的机型
}传入相应的机型后输出效果图如下:
使用生成的代码进行适配:
从图中可以看出,在1280x720和1920x1080的手机上,不管是横屏还是竖屏,控件的宽度和高度分别占据屏幕的1/2和1/4的的大小,由此说明,生成的文件计算的还是准确的,但是竖屏是个接近正方形的在横屏上却变成了长方形,是哪里出问题了?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:layout_width="@dimen/dp_180_x"
android:layout_height="@dimen/dp_160_y"
android:background="#123123"
android:textAllCaps="false"
android:textColor="@android:color/white"
android:textSize="16sp" />
</LinearLayout>是因为控件的长度和高度是按手机的长宽计算的,所以适配的时候有时高度需要按照宽度来作为参考物,这个需要了解一下。
这个是第一版,如果有BUG的话欢迎指出!
| Back | FazBrowse Home | New Git URL |