Android 屏幕适配
Posted wanglongjiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 屏幕适配相关的知识,希望对你有一定的参考价值。
一、概念
1.1 屏幕像素密度 PPI、DPI
PPI(Pixels Per Inch)屏幕每英寸容纳多少个像素点,DPI(Dots Per Inch)这个“点”是根据屏幕物理概念产生的一个软件概念,在不同行业有不同理解,印刷行业每英寸打印多少个墨点,鼠标移动一英寸光标移动多少像素点,在Android中被用来表示屏幕每英寸显示多少个像素点,概念上可以当作没有区别。
1.2 密度无关像素 dp
density-independent pixel,是 Android 特有的单位,只与DPI有关,保证了在不同屏幕像素密度的设备上显示相同的效果。以DPI=160为基准1dp=1px,用设备实际DPI值/160=density密度,即1dp=多少px。用屏幕宽或高的px/density=屏幕宽或高最大dp长度。
px = density * dp
density = dpi / 160
1.3 独立比例像素 sp
scale-independent pixel,是 Android 特有的单位,用于设置字体大小。
二、AndroidStudi目录说明
Android会根据手机屏幕分辨率选择对应文件夹中的资源,如果没有对应的文件夹,则从最高分辨率的文件夹依次往低处寻找,找到高分辨率的就压缩后显示,找到低分辨率的就放大显示。
mipmap只用来放桌面应用图标(Manifest中application标签配置的icon项),drawable用来存放图片资源,values用来针对不同分辨力编写对应资源文件。
三、屏幕适配
市面上的机型,不同分辨率*不同屏幕尺寸=无限多种DPI组合。当美工给的图以px为单位使用4.1的dimen适配、以dp为单位使用4.2的字节跳动density适配、更推荐的是smallestWidth限定符适配。
dimen宽高适配
穷举市面上所有 Android 手机的屏幕像素尺寸来实现适配,通过比例换算来为不同分辨率的屏幕分别准备一套 dimens 文件,应用在运行时再去引用和当前设备完全匹配的 dimens 文件,以此来实现屏幕适配。
缺点:缺点是容错率低,只有精准匹配分辨率才能适配,否则只能引用默认dimens文件夹,显示效果就会有很大出入。
smallestWidth限定符适配
根据屏幕最短的那个边(不考虑屏幕方向)适配,适配原理和宽高限定符方案一样,也是通过比例换算来为不同尺寸的屏幕分别准备一套 dimens 文件,应用在运行时再去引用和当前设备最匹配的 dimens 文件。
优点:容错率高,没有找到对应dimens文件会向下寻找接近的。在 320 ~ 460 dp 之间每 10 dp 就提供一套 dimens 文件就足够使用了,想要囊括更多设备的话也可以再缩短步长,基本不用担心最终效果会与设计稿偏差太多,且不会影响到三方库。
缺点:需要生成多套 dimens 文件,增大了 apk 体积。
density字节跳动密度适配
基于系统将 dp 转换为 px 的公式 px = dp * density 来实现适配,通过在运行时动态修改 density 值的大小,使得修改后计算出的屏幕宽度就等于设计稿的宽度,从而使得在不同屏幕尺寸下我们都可以直接使用设计稿给出的 dp 值,且无需准备多套 dimens 文件。
优点:可以直接使用设计稿中的 dp 值,无需准备多套 dimens 文件进行映射,因此不会增大 apk 体积,且在三种方案中 UI 还原度最高,其它两种方案都需要精准命中屏幕尺寸后才能达到此方案的还原度。
缺点:由于此方案会影响到应用全局,对于已经迭代了很久的项目来说,中途引入此方案大概率会影响到现有的适配方案;即使是新项目,又需要考虑到此方案对于三方库的影响,不能由于主项目的变动导致三方库自身界面变形。
3.1 dimen宽高适配
public class DimenUtils private final static String rootPath = "C:/Users/Administrator/Desktop/layoutroot/values-0x1/"; //注意将Administrator替换为实际用户名 private final static float dw = 300f; //屏幕横向分为多少等份 private final static float dh = 500f; //屏幕纵向分为多少等份 private final static String WTemplate = "<dimen name=\\"x0\\">1px</dimen>\\n"; //xml中横向条目的内容:<dimen name="x1">2.4px</dimen> private final static String HTemplate = "<dimen name=\\"y0\\">1px</dimen>\\n"; //xml中纵向条目的内容:<dimen name="y1">2.56px</dimen> public static void main(String[] args) //AndroidStudio运行失败的话选择 Run \'DimenUtils.main()\' with Coverage //720P makeString(720, 1280); // makeString(720, 1520); // makeString(720, 1600); // makeString(720, 1650); //1080P // makeString(1080, 1920); // makeString(1080, 2160); // makeString(1080, 2220); makeString(1080, 2340); // makeString(1080, 2376); makeString(1080, 2400); // makeString(1080, 2412); //1.5K // makeString(1220, 2712); // makeString(1240, 2772); // makeString(1260, 2800); //2K // makeString(1440, 2560); // makeString(1440, 2960); // makeString(1440, 3040); makeString(1440, 3200); 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 < dw; i++) sb.append(WTemplate.replace("0", i + "").replace("1", change(cellw * i) + "")); sb.append(WTemplate.replace("0", "300").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 < dh; i++) sb2.append(HTemplate.replace("0", i + "").replace("1", change(cellh * i) + "")); sb2.append(HTemplate.replace("0", "500").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;
//将生成的文件夹直接拖进 AndroidStudio 中的 res 中,使用的时候就 @dimen/ 后跟方向和份数。 <TextView android:layout_width="@dimen/x100" android:layout_height="@dimen/y250"/>
3.2 smallestWidth 限定符适配
GitHub - ladingwu/dimens_sw: Android UI适配方案
3.3 density 字节跳动密度适配
Android 屏幕适配屏幕适配基础概念 ④ ( 屏幕适配限定符 | 手机/平板电脑设备屏幕适配 )
文章目录
参考文档 :
一、屏幕适配限定符
Android 系统加载应用资源时 , 会根据当前运行应用的设备的相关属性 , 如 : 屏幕尺寸 / 屏幕像素密度 / 宽高比 / 屏幕方向 等属性 , 加载不同的屏幕适配限定符目录下的资源 ;
如 : 横竖屏切换时 , res/layout-land 目录中 , 存放的是横屏布局 , res/layout-port 目录中 , 存放的是竖屏布局 ;
屏幕尺寸限定符 :
- small : 小屏幕 ;
- normal : 标准屏幕 ;
- large : 大屏幕 ;
- xlarge : 超大屏幕 ;
屏幕密度限定符 :
- ldpi : 低屏幕像素密度 , 0 < d p i ≤ 120 \\rm 0 < dpi \\leq 120 0<dpi≤120 ;
- mdpi : 中屏幕像素密度 , 120 < d p i ≤ 160 \\rm 120 < dpi \\leq 160 120<dpi≤160 ;
- hdpi : 高屏幕像素密度 , 160 < d p i ≤ 240 \\rm 160 < dpi \\leq 240 160<dpi≤240 ;
- xhdpi : 超高屏幕像素密度 , 240 < d p i ≤ 320 \\rm 240 < dpi \\leq 320 240<dpi≤320 ;
- xxhdpi : 超超高屏幕像素密度 , 320 < d p i ≤ 480 \\rm 320 < dpi \\leq 480 320<dpi≤480 ;
- xxxhdpi : 超超超高屏幕像素密度 , 480 < d p i ≤ 640 \\rm 480 < dpi \\leq 640 480<dpi≤640 ;
屏幕方向限定符 : 一般是用于横竖屏切换时进行适配 ;
- land : 横线屏幕 ;
- port : 纵向屏幕 ;
屏幕宽高比限定符 : 标准屏幕宽高比为 16 : 9 16:9 16:9 ;
- long : 比标准屏幕要长的屏幕 , 如 20 : 9 20:9 20:9 , 21 : 9 21:9 21:9 ;
- notlong : 标准屏幕 ;
二、手机/平板电脑设备屏幕适配
平板电脑市场占有率
Android 平板市场占有率如下 , 大概还是占了 40% 左右 , 因此平板适配还是很重要的 ;
密度无关像素计算
一般情况下 , 平板电脑的布局或图片资源 , 放在 res/layout-swxxdp 目录下 , 其中的 xx 是横向的 密度无关像素 ( DIP , Desity Independent Pixels ) 值 , 单位是 dp / dip ;
在 【Android 屏幕适配】屏幕适配基础概念 ① ( Android 与 iOS 屏幕宽高比种类 | 屏幕像素密度 DPI ) 博客中 , 计算了 6.5 6.5 6.5 寸屏幕 , 1920 × 1080 1920 \\times 1080 1920×1080 像素的屏幕的 屏幕像素密度 ( Dots Per Inch , 每英寸的像素点个数 ) , 值为 500 , 也就是每英寸有 500 500 500 个像素点 ;
将其转为 dp 单位 , 根据公式 :
p x = d p × d p i 160 \\rm px = dp \\times \\cfracdpi160 px=dp×160dpi
d
p
=
p
x
×
160
d
p
i
\\rm dp = px \\times \\cfrac160dpi
dp=px×dpi160
=
1080
×
160
500
=
345.6
\\rm = 1080 \\times \\cfrac160500 = 345.6
=1080×500160=345.6
该设备的横向 密度无关像素 ( DIP , Desity Independent Pixels ) 值为 345.6 345.6 345.6 ;
手机设备限定符
在 布局 或 图片 目录名称中 , 加上 sw360dp 限定符 , 几乎兼容所有的手机设备 ; 当前市面上的手机 , 屏幕宽度 很少有超过 360 360 360 dp 的 ;
只要横向 密度无关像素 ≤ 360 d p \\rm \\leq 360 dp ≤360dp , 就可以使用 sw360dp 限定符下的资源 , 如 res/layout-sw360dp 目录下的资源 ;
平板设备限定符
在 布局 或 图片 目录名称中 ,
- 加上 sw480dp 限定符 , 对应 7 7 7 寸平板电脑 ;
- 加上 sw560dp 限定符 , 对应 8 8 8 寸平板电脑 ;
- 加上 sw720dp 限定符 , 对应 10 10 10 寸平板电脑 ;
以上是关于Android 屏幕适配的主要内容,如果未能解决你的问题,请参考以下文章
Android 屏幕适配屏幕适配基础概念 ④ ( 屏幕适配限定符 | 手机/平板电脑设备屏幕适配 )