一些关于屏幕的概念:
px
像素, 即 屏幕上最小的点 可以显示一个颜色值
inch
英寸, 外国单位,1英寸=2.54厘米
分辨率
宽高所拥有的像素值 720*1280 宽为720个像素 高位1280个px
ppi
pixels per inch : 每英寸的像素点 通常我们是算的屏幕对角线的
ppi=(斜对角线的像素个数)/(斜对角线长度 单位为英寸)
即
ppi=√(分辨率高的平方+分辨率宽的平方)/√(屏幕长度的平方+屏幕宽度的平方)
其实就是用勾股定理算出对角线的像素个数和对角线的长度 相除 比如
以720*1280 4.7寸屏为例(4.7寸屏就是指斜对角线长度) 即
ppi=√(1280^2+720^2)/4.7=312.469
Dpi跟ppi是一个概念 意思是屏幕密度 数字越大 表示一英寸里容纳了越多的像素点,屏幕看起来就越精细
这里 对android 对ppi的大小设置了几个级别
DENSITY_LOW = 120
DENSITY_MEDIUM = 160 //默认值
DENSITY_HIGH = 240 //高清
DENSITY_XHIGH = 320 //超清
DENSITY_XXHIGH = 480
DENSITY_XXXHIGH = 640
超过某个值 就大概在哪个级别,比如刚才算出来的312.469 其实就在hdpi与xhdpi之间. 差不多就是xhdpi 商家是肯定会这么号称:超清屏
android设备比较乱 所以跟标准值一样的很少
另外
同一个ppi下,分辨率越大就越清晰
同一个ppi下,屏幕越大就越模糊 大电视上的颜色块我们应该都见过.
我就遇到过一个奇葩手机,他的屏幕跟其他手机一样大, 但是分辨率很低, 结果就造成了 手机看上去跟其他手机一样,价格都差不多,然后显示就是比别人的粗糙 显示的控件就是比别人的大
接下来轮到dp了
dp
dp是一种我们计算出来的单位 , 它在不同ppi上表示的像素个数不同,具体换算公式如下:
px=dp*(实际ppi/160)
在上面分出的等级里 我们把 ppi=160 定义为标准屏幕密度(几年前的标注 那时普遍ppi都低)
dp的作用是:为了在不同屏幕手机上显示出一样的大小
问题的出现:
320像素
在ppi160屏幕上显示的是2(320/160)英寸
在ppi 320的屏幕上 就只有1(320/320)英寸了
在ppi 640的屏幕上 只有0.5(320/640)英寸
越清晰就显示得越小,在低分屏还能看清 到了高分屏上就难说了,所以我们用px作为单位 就很不合适了 因为不能随屏幕变化而变化
由此引进dp这个单位,对px和ppi进行统一
其实就是根据比例缩放
像素不是在高分屏上缩小了么 那么缩小多少 我就乘以多少,
比如上面的
320像素 在 ppi160屏幕上显示的是2英寸
到ppi320 1英寸要显示为2英寸 那么就乘以2
到ppi640 0.5英寸要显示为2英寸 那么就乘以4
dp就是这里的比例关系
dp=px*160/ppi
也就是说
dp是为了保证在不同屏幕手机上显示出一样物理的大小
google这个设置 大致解决了分辨率的问题 保证了你在这个手机上设置的东西在另一台手机上都能看清.但新的问题来了 我们上面看到的是这个效果
但是一般来说,高ppi手机屏幕实际上就比低的大,
有两台手机配置如下:
4.0英寸–800x480–233ppi
5.0英寸–1920x1080–441ppi
你按第一台手机上写了控件高度549dp(549*233/160=800),也就是整个屏幕,结果到了5.0英寸的手机上549dp占多长呢
549*441/160=1513px
也就是说在4.0手机上显示的全屏的控件 在5.0手机上只有78%(1513/1920),还有一部分是空余.
再说我们实际要求吧 其实我们想要的效果是显示比例相同
如图:
一个控件在小手机上显示占50% 那么 我想要在大屏幕上也显示占50%
相信大部分人都看过这样的文件夹
各种value 里面的dimen 配置不同的比例dp
这里用到了屏幕等分,让一个东西在所有手机上看起来比例都一样,我们把屏幕高等分成320(份数自己定 保证够细)份 然后计算出不同屏幕上 每一份对应的dp的值
比如
在800x480分辨率ppi233的屏幕上,将高分成320份,创建320个dimen值
dp=px*160/实际ppi=800*160/233=549.35
800px换成ppi下的dp就是549.35dp
dp与每一等份的关系如下
dimen_y_1=549.35 *1/320=1.716dp
dimen_y_2=549.35 *2/320=3.433dp
dimen_y_3=549.35 *3/320=4.609dp
...
...
...
dimen_y_320=549.35 *320/320=549.35dp
在720*1280分辨率ppi312屏幕上 同样也是分成320份 属性值和上面一样
dp=px*160/ppi=1280*160/312=656.41
1280px换成ppi下的dp就是656.41dp 将 656.41dp平均分成320份
dimen_y_1=2.05dp
dimen_y_2=4.10dp
dimen_y_3=6.15dp
...
...
...
dimen_320=656.41dp
这是设置高, 我们再设置宽的时候也加这个属性
dimen_x_1=XXXdp
这样我们设置的时候用我们自己的单位
android:layout_width=”@dimen/dimen_x_320”
android:layout_width=”@dimen/dimen_y_32”
如此 :
宽为全屏
高位10%
当然 分辨率太多不会要你自己一个个算,网上有写好的生成这些文件的脚本执行下就行了,代码如下:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class MakeXml {
private final static String rootPath = "D:\\layoutroot\\values-{0}x{1}\\";
private final static float dw = 320f;
private final static float dh = 480f;
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";
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>");
float cellw = w / dw;
for (int i = 1; i < 320; i++) {
sb.append(WTemplate.replace("{0}", i + "").replace("{1}",
change(cellw * i) + ""));
}
sb.append(WTemplate.replace("{0}", "320").replace("{1}", w + ""));
sb.append("</resources>");
StringBuffer sb2 = new StringBuffer();
sb2.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sb2.append("<resources>");
float cellh = h / dh;
for (int i = 1; i < 480; i++) {
sb2.append(HTemplate.replace("{0}", i + "").replace("{1}",
change(cellh * i) + ""));
}
sb2.append(HTemplate.replace("{0}", "480").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;
}
}