最近做了个项目需要适配7寸的平板分辨率(800 x 1280)和5寸的手机分辨率(1280 x 720)针对这两种机型做一个适配,分享下两种手机的适配方案。
可以将安卓适配分为屏幕、图片、尺寸三个方面给大家分享!
屏幕适配
屏幕适配使用的方案有
- 尺寸限定词
- 最小宽度限定词
- 使用布局别名
下面我就来一一介绍,并在项目中使用的例子说明。
首先介绍尺寸限定词
尺寸限定词 | 描述 |
small | small:用于小屏手机,最小布局尺寸大约是320x426dp |
normal | normal:用于中屏手机,最小布局尺寸大约是320x470dp |
large | large:用于大屏手机,最小布局尺寸大约是480x640dp |
xlarge | xlarge :适用于超大屏手机,最小布局尺寸大约是720x960dp |
- 格外提一个屏幕方向限定词
屏幕方向限定词 | 描述 |
port | port:纵向设备(垂直) |
land | land:横向设备(水平) |
如果用户旋转屏幕,这个限定能够在应用程序运行期间改变。 |
很多小伙伴要开始问了,我怎么知道我适配的手机使用什么限定词?
有问题是好事,其实我们能通过创建模拟器页面知道大众手机的分辨率和使用的限定词是什么。
下面介绍 -宽高限定词
- 最小宽度限定词
最小宽度限定词 | 描述 |
sw320dp | 320,针对以下屏幕配置的设备: 240x320ldpi(QVGA手持设备)320x480mdpi(手持设备)480x800hdpi(高分辨率手持设备) |
sw480dp | 480,针对480x800mdpi的屏幕(平板或手持设备) |
sw600dp | 600,针对600x1024mdip的屏幕(7英寸平板) |
sw720dp | 720,针对720x1280mdip的屏幕(10英寸平板) |
系统会使用最接近(不超出)设备最小宽度的那个资源。 |
这段话来自官方教程
最小宽度限定词只能在android3.2或者更高的版本上使用。因此,你还是需要使用抽象尺寸(small,normal,large,xlarge)来兼容以前的版本。比如,你想要将你的UI设计为在手机上只显示一个方框的布局,而在7寸平板或电视,或者其他大屏幕设备上显示多个方框的布局,你可能得提供这些文件:
- res/layout/main.xml:单个窗格布局
- res/layout-large:多个窗格布局
- res/layout-sw600dp:多个窗格布局
最后两个文件都是一样的,因为其中一个将会适配Android3.2的设备,而另外一个则会适配其他Android低版本的平板或者电视。 为了避免这些重复的文件(维护让人感觉头痛就是因为这个),你可以使用别名文件。比如,你可以定义如下布局:
- res/layout/main.xml,单个方框布局
- res/layout/main_twopans.xml,两个方框布局
然后添加这两个文件:
- res/values-large/layout.xml:
<resources>
<item name="main" type="layout">@layout/main_twopanes</item>
</resources>
- res/values-sw600dp/layout.xml:
<resources>
<item name="main" type="layout">@layout/main_twopanes</item>
</resources>
最后两个文件拥有相同的内容,但它们并没有真正意义上的定义布局。它们只是将main_twopanes设置成为了别名main,它们分别处在large和sw600dp选择器中,所以它们能适配Android任何版本的平板和电视(在3.2之前平板和电视可以直接匹配large,而3.2或者以上的则匹配sw600dp)。
根据我们的需求适配平板和手机的横屏
在res下建立
手机的使用默认的Layout文件夹
- res/layout-large-port:超大屏 横向限定词
图片适配
下面贴上一张百度对比图,首先感谢前人的总结,然后谢谢我不花钱无耻的引用!
因为这个大家日常都在使用就不过多介绍了!平板的图片放置在mdpi下 手机的图放置在xhdpi下,通过代码和布局我们可以只使用一套图 都放在xhdpi下!
字体适配
对于字体的适配,我们考虑了以下方案
- 放弃sp使用dp为单位然后使用dimen适配
- 引入字体包使用dimen适配
最终使用了dp为单位。
在values文件下建立dimens.xml,然后适配手机的文字大小
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="font_14">14dp</dimen>
<dimen name="font_16">16dp</dimen>
<dimen name="font_18">18dp</dimen>
<dimen name="font_32">32dp</dimen>
<dimen name="size_20">20dp</dimen>
<dimen name="size_30">30dp</dimen>
<dimen name="size_45">45dp</dimen>
</resources>
我这里推荐在dimens.xml中不采取带业务含义的命名,简单的使用数值命名比如size_45、font_14 大多的UI图上都会指定一个值 不断的加入不重复的数值即可。以前在项目中使用带业务命名的数值,经过多次交接和迭代开发项目中dimen杂乱、重复值极多。还是简单明了的好!
通过dimen生成文件的代码生成不同的文件选择引入即可。
自动生成Android屏幕适配的dimens.xml
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 根据values/dimens.xml, 自动计算比例并生成不同分辨率的dimens.xml
* 注意用dp和sp,不要用dip,否则生成可能会出错;xml值不要有空格
* Created by zhangxitao on 15/9/22.
*/
public class DimenTool {
public static void gen() {
File file = new File("./app/src/main/res/values/dimens.xml");
BufferedReader reader = null;
StringBuilder sw480 = new StringBuilder();
StringBuilder sw600 = new StringBuilder();
StringBuilder sw720 = new StringBuilder();
StringBuilder sw800 = new StringBuilder();
StringBuilder w820 = new StringBuilder();
try {
System.out.println("生成不同分辨率:");
reader = new BufferedReader(new FileReader(file));
String tempString;
int line = 1;
// 一次读入一行,直到读入null为文件结束
while ((tempString = reader.readLine()) != null) {
if (tempString.contains("</dimen>")) {
//tempString = tempString.replaceAll(" ", "");
String start = tempString.substring(0, tempString.indexOf(">") + 1);
String end = tempString.substring(tempString.lastIndexOf("<") - 2);
int num = Integer.valueOf(tempString.substring(tempString.indexOf(">") + 1, tempString.indexOf("</dimen>") - 2));
sw480.append(start).append((int) Math.round(num * 0.6)).append(end).append("\n");
sw600.append(start).append((int) Math.round(num * 0.75)).append(end).append("\n");
sw720.append(start).append((int) Math.round(num * 0.9)).append(end).append("\n");
sw800.append(tempString).append("\n");
w820.append(tempString).append("\n");
} else {
sw480.append(tempString).append("\n");
sw600.append(tempString).append("\n");
sw720.append(tempString).append("\n");
sw800.append(tempString).append("\n");
w820.append(tempString).append("\n");
}
line++;
}
reader.close();
System.out.println("<!-- sw480 -->");
System.out.println(sw480);
System.out.println("<!-- sw600 -->");
System.out.println(sw600);
System.out.println("<!-- sw720 -->");
System.out.println(sw720);
System.out.println("<!-- sw800 -->");
System.out.println(sw800);
String sw480file = "./app/src/main/res/values-sw480dp-land/dimens.xml";
String sw600file = "./app/src/main/res/values-sw600dp-land/dimens.xml";
String sw720file = "./app/src/main/res/values-sw720dp-land/dimens.xml";
String sw800file = "./app/src/main/res/values-sw800dp-land/dimens.xml";
String w820file = "./app/src/main/res/values-w820dp/dimens.xml";
writeFile(sw480file, sw480.toString());
writeFile(sw600file, sw600.toString());
writeFile(sw720file, sw720.toString());
writeFile(sw800file, sw800.toString());
writeFile(w820file, w820.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
public static void writeFile(String file, String text) {
PrintWriter out = null;
try {
out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
out.println(text);
} catch (IOException e) {
e.printStackTrace();
}
out.close();
}
public static void main(String[] args) {
gen();
}
}
生成的最后效果可能跟需求相差很大,自己根据需求修改吧!
今天的基础介绍先到这里,明天给大家介绍项目中的使用方法。