文章大纲
一, 屏幕适配是什么
二, 重要概念讲解
三, 屏幕适配实战
四, 项目源码下载
一, 屏幕适配是什么
Android 中屏幕适配就是通过对尺寸单位, 图片, 文字, 布局这四种类型的资源进行合理的设计和规划, 在布局时合理利用各种类型的资源, 让布局拥有适应能力, 能在各种设备下保持良好的展现效果.
二, 常见屏幕适配方法介绍
1 屏幕尺寸
屏幕尺寸是指屏幕对角线的长度, 单位是英寸, 1 英寸 = 2.54 厘米
2 屏幕分辨率
屏幕分辨率是指横纵向上的像素点数, 单位是 px,1px=1 个像素点, 一般以纵向像素横向像素, 如 19201080, 分辨率越高, 显示效果越好.
3 屏幕像素密度
屏幕像素密度是指每英寸上的像素点数, 单位是 dpi, 屏幕像素密度与屏幕尺寸和屏幕分辨率有关.
4. px,dp,sp
(1)安卓里面获取屏幕宽和高, 也是以 px 作为单位的.
(2)在 160dpi(即分辨率是 480*320)基准下, 1dip=1px(也就是 px 不能适配所有机型), 如下图所示, 要充满屏幕, 箭头的 px 值是不一样的. 1dp = 那个机型 dpi/160px. 所以用 dp 会比 px 好.
(3)在使用 sp(设置文字的)时候, 使用偶数, 不要使用奇数或者小数, 最最推荐的是 12.14.18,22sp 的文字大小(尽量不要使用 12sp 以下的大小, 用户可能看不清楚).
5. mdpi,hdpi,xdpi,xxdpi
安卓软件运行时, 会自动根据屏幕像素去不同文件夹加载对应图片.
三, 屏幕适配实战
1. 使用 dp 设置控件大小, sp 设置字体大小(不可行)
activity_main2.xml 布局代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- xmlns:App="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent"
- Android:orientation="vertical"
- tools:context=".MainActivity">
- <Button
- Android:layout_width="200dp"
- Android:layout_height="50dp"
- Android:textSize="20sp"
- Android:text="按钮 1"/>
- <Button
- Android:layout_width="200dp"
- Android:layout_height="50dp"
- Android:layout_marginTop="20dp"
- Android:textSize="20sp"
- Android:text="按钮 2"/>
- </LinearLayout>
运行结果如下:
得出结论: 即使使用 dp 设置控件大小, sp 设置字体大小, 也是无法适配所有手机的. 因为这是谷歌自己的一个标准. dp 是根据屏幕像素和分辨率一起来解决的. 但是有些手机像素和分辨率不是对应关系, 所以不行.
2. weight 属性使用
activity_main3.xml 布局代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- xmlns:App="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent"
- Android:orientation="horizontal"
- tools:context=".MainActivity">
- <Button
- Android:layout_width="0dp"
- Android:layout_height="wrap_content"
- Android:layout_weight="1"
- Android:textSize="20sp"
- Android:text="按钮 1"/>
- <Button
- Android:layout_width="0dp"
- Android:layout_height="wrap_content"
- Android:layout_weight="2"
- Android:textSize="20sp"
- Android:text="按钮 2"/>
- </LinearLayout>
运行结果如下:
得出结论: 采用 weight, 可以使得组件按屏幕大小进行放大缩小, weight 的计算方式如下:
如果将 xml 中的 Android:layout_weight 属性值 1 和 2 互换, 则结果是相反的, 有兴趣伙伴可以下载源码看看效果.
3. 使用自动拉伸位图. 9 图
什么是. 9 图
因为 Android 有太多的分辨率了, 当圆角矩形控件在被拉伸放大的时候, 圆角的部分就会出现模糊的情况. 而点九切图就不同, 它可以保证不管你上下还是左右拉伸, 放大都可以保持原有的清晰度.
.9 图存放位置
4. 屏幕方向限定符 large
比如我们想在屏幕竖屏时候加载什么布局, 在屏幕横线时候加载什么布局. 在手机加载什么布局, 在平板电脑加载什么布局.
该文章暂不展开讨论, 将在 Fragment 使用中进行讲解.
5. 多文件适配(重要)
大家经过上面的学习之后, 已经知道有些手机像素和分辨率不是对应关系, 无法使用 dp 等单位来解决, 那么我们可以以某个常见的屏幕分辨率作为基准, 自定义需要适配到的屏幕分辨率的 xml 文件, 如下图所示:
使用生成器生成对应的文件
生成器代码 (使用 320*480 作为基准) 如下:
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.PrintWriter;
- /**
- * Created by 吴晓畅
- */
- public class GenerateValueFiles {
- private int baseW;
- private int baseH;
- private String dirStr = "./res";
- 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 VALUE_TEMPLATE = "values-{0}x{1}";
- // 新增文件的分辨率, 以 x,x; 隔开
- private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;768,1280;800,1280;1080,1812;1080,1920;1440,2560;";
- private String supportStr = SUPPORT_DIMESION;
- public GenerateValueFiles(int baseX, int baseY, String supportStr) {
- this.baseW = baseX;
- this.baseH = baseY;
- if (!this.supportStr.contains(baseX + "," + baseY)) {
- this.supportStr += baseX + "," + baseY + ";";
- }
- this.supportStr += validateInput(supportStr);
- System.out.println(supportStr);
- File dir = new File(dirStr);
- if (!dir.exists()) {
- dir.mkdir();
- }
- System.out.println(dir.getAbsoluteFile());
- }
- private String validateInput(String supportStr) {
- StringBuffer sb = new StringBuffer();
- String[] vals = supportStr.split("_");
- int w = -1;
- int h = -1;
- String[] wh;
- for (String val : vals) {
- try {
- if (val == null || val.trim().length() == 0)
- continue;
- wh = val.split(",");
- w = Integer.parseInt(wh[0]);
- h = Integer.parseInt(wh[1]);
- } catch (Exception e) {
- System.out.println("skip invalidate params : w,h =" + val);
- continue;
- }
- sb.append(w + "," + h + ";");
- }
- return sb.toString();
- }
- public void generate() {
- String[] vals = supportStr.split(";");
- for (String val : vals) {
- String[] wh = val.split(",");
- generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1]));
- }
- }
- private void generateXmlFile(int w, int h) {
- StringBuffer sbForWidth = new StringBuffer();
- sbForWidth.append("<?xml version=\"1.0\"encoding=\"utf-8\"?>\n");
- sbForWidth.append("<resources>");
- float cellw = w * 1.0f / baseW;
- System.out.println("width :" + w + "," + baseW + "," + cellw);
- for (int i = 1; i <baseW; i++) {
- sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}",
- change(cellw * i) + ""));
- }
- sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}",
- w + ""));
- sbForWidth.append("</resources>");
- StringBuffer sbForHeight = new StringBuffer();
- sbForHeight.append("<?xml version=\"1.0\"encoding=\"utf-8\"?>\n");
- sbForHeight.append("<resources>");
- float cellh = h *1.0f/ baseH;
- System.out.println("height :"+ h + "," + baseH + "," + cellh);
- for (int i = 1; i <baseH; i++) {
- sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}",
- change(cellh * i) + ""));
- }
- sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}",
- h + ""));
- sbForHeight.append("</resources>");
- File fileDir = new File(dirStr + File.separator
- + VALUE_TEMPLATE.replace("{0}", h + "")//
- .replace("{1}", w + ""));
- fileDir.mkdir();
- File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml");
- File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml");
- try {
- PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
- pw.print(sbForWidth.toString());
- pw.close();
- pw = new PrintWriter(new FileOutputStream(layyFile));
- pw.print(sbForHeight.toString());
- pw.close();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- }
- public static float change(float a) {
- int temp = (int) (a * 100);
- return temp / 100f;
- }
- public static void main(String[] args) {
- // 基准大小, 比如 320.480, 其他则以这个基准进行放大缩小
- int baseW = 320;
- int baseH = 480;
- String addition = "";
- try {
- if (args.length>= 3) {
- baseW = Integer.parseInt(args[0]);
- baseH = Integer.parseInt(args[1]);
- addition = args[2];
- } else if (args.length>= 2) {
- baseW = Integer.parseInt(args[0]);
- baseH = Integer.parseInt(args[1]);
- } else if (args.length>= 1) {
- addition = args[0];
- }
- } catch (NumberFormatException e) {
- System.err
- .println("right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;");
- e.printStackTrace();
- System.exit(-1);
- }
- new GenerateValueFiles(baseW, baseH, addition).generate();
- }
- }
运行代码, 结果会在项目的 res 文件夹中生成对应的内容, 如下图所示:
温馨提示: 上图每个文件夹是以 320*480 作为基准进行放大缩小后的 px 值
将上面生成的文件夹复制到实际项目中
复制所有文件夹, 右击 studio 中的 res 文件夹进行粘贴
xml 布局中进行引用
activity_main4.xml 代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android" xmlns:App="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" Android:layout_width="match_parent" Android:layout_height="match_parent" Android:orientation="vertical" tools:context=".MainActivity"> <Button Android:layout_width="@dimen/x200" Android:layout_height="@dimen/y30" Android:text="按钮 1"/> <Button Android:layout_width="@dimen/x200" Android:layout_height="@dimen/y30" Android:layout_marginTop="@dimen/y30" Android:text="按钮 2"/> </LinearLayout>
运行结果如下图所示:
温馨提示:
如果运行后发现某个尺寸的屏幕没有是配到, 那么可以在生成器中添加对应屏幕尺寸, 重新生成文件夹, 之后拷贝到项目中即可
图片适配则可以采用图片放在不同文件夹里面, 系统会自动选图, 但最好每次切图都包含多种分辨率的图片, 例如某一测试的机器是 xxhdpi 密度的, 所以当把图片放在 xxhdpi 时候 (其他文件夹没放), 加载时候占用内存是较小的. 默认是没有加载任何东西(运行一个空白 App) 占用的内存. 如果加载其他像素下的图片, 则会占用很多内容. 所以总结来说就是要各个文件夹都放有图片, 可以减少占用内存的加载.
四, 项目源码下载
链接: https://pan.baidu.com/s/1xDRVaSS9Kk9OGLzloBeneA
提取码: 0zyt
来源: https://www.cnblogs.com/WUXIAOCHANG/p/10544545.html