摘自:http://www.it165.net/pro/html/201509/54281.html
当您的Android应用即将发布的时候,如果你想让更多的用户去使用你的应用,摆在工程师面前的一个重要问题就是如何让你的应用能在各种各样的终端上运行,这里的各种各样首当其冲的就是不同的屏幕分辨率和尺寸。
屏幕适配主要从图片和距离(文字)进行下手。从以往的方式适配方式中,开发者可能会考虑各种各样的分辨率,比如480*800、1280*800、1920*1080等,为此在资源文件夹里面创建了一大堆子文件夹,那么有什么更好的方式吗?首先我们看下genymotion模拟其中一些流行的镜像的屏幕参数信息:

1.
Configuration config = getResources().getConfiguration();
2.
int
smallestScreenWidth = config.smallestScreenWidthDp;
3.
L.i(
'smallest width : '
+ smallestScreenWidth);
文字和尺寸的适配
我们这里需要将代码跑在一个1920*1200分辨率320dpi的平板上,发现所有的字体都变大了,看似1920*1200的分辨率比之前的1280*800要大一大圈,但是因为dpi也高,所以导致字体变大。 运行上面的获取smallestScreenWidth的代码后,发现值为600。(base size的平板电脑这个值是800) 首先在values文件夹中建立一个dimens.xml文件







001.
public
class
DimenTool {
002.
003.
public
static
void
gen() {
004.
005.
File file =
new
File(
'./app/src/main/res/values/dimens.xml'
);
006.
BufferedReader reader =
null
;
007.
StringBuilder sw480 =
new
StringBuilder();
008.
StringBuilder sw600 =
new
StringBuilder();
009.
StringBuilder sw720 =
new
StringBuilder();
010.
StringBuilder sw800 =
new
StringBuilder();
011.
StringBuilder w820 =
new
StringBuilder();
012.
013.
014.
try
{
015.
System.out.println(
'生成不同分辨率:'
);
016.
reader =
new
BufferedReader(
new
FileReader(file));
017.
String tempString;
018.
int
line =
1
;
019.
// 一次读入一行,直到读入null为文件结束
020.
021.
while
((tempString = reader.readLine()) !=
null
) {
022.
023.
if
(tempString.contains(
'</dimen>'
)) {
024.
//tempString = tempString.replaceAll(' ', '');
025.
String start = tempString.substring(
0
, tempString.indexOf(
'>'
) +
1
);
026.
String end = tempString.substring(tempString.lastIndexOf(
'<'
) -
2
);
027.
int
num = Integer.valueOf(tempString.substring(tempString.indexOf(
'>'
) +
1
, tempString.indexOf(
'</dimen>'
) -
2
));
028.
029.
sw480.append(start).append((
int
) Math.round(num *
0.6
)).append(end).append('
030.
');
031.
sw600.append(start).append((
int
) Math.round(num *
0.75
)).append(end).append('
032.
');
033.
sw720.append(start).append((
int
) Math.round(num *
0.9
)).append(end).append('
034.
');
035.
sw800.append(tempString).append('
036.
');
037.
w820.append(tempString).append('
038.
');
039.
040.
}
else
{
041.
sw480.append(tempString).append('
042.
');
043.
sw600.append(tempString).append('
044.
');
045.
sw720.append(tempString).append('
046.
');
047.
sw800.append(tempString).append('
048.
');
049.
w820.append(tempString).append('
050.
');
051.
}
052.
line++;
053.
}
054.
reader.close();
055.
System.out.println(
'<!-- sw480 -->'
);
056.
System.out.println(sw480);
057.
System.out.println(
'<!-- sw600 -->'
);
058.
System.out.println(sw600);
059.
060.
System.out.println(
'<!-- sw720 -->'
);
061.
System.out.println(sw720);
062.
System.out.println(
'<!-- sw800 -->'
);
063.
System.out.println(sw800);
064.
065.
String sw480file =
'./app/src/main/res/values-sw480dp-land/dimens.xml'
;
066.
String sw600file =
'./app/src/main/res/values-sw600dp-land/dimens.xml'
;
067.
String sw720file =
'./app/src/main/res/values-sw720dp-land/dimens.xml'
;
068.
String sw800file =
'./app/src/main/res/values-sw800dp-land/dimens.xml'
;
069.
String w820file =
'./app/src/main/res/values-w820dp/dimens.xml'
;
070.
writeFile(sw480file, sw480.toString());
071.
writeFile(sw600file, sw600.toString());
072.
writeFile(sw720file, sw720.toString());
073.
writeFile(sw800file, sw800.toString());
074.
writeFile(w820file, w820.toString());
075.
}
catch
(IOException e) {
076.
e.printStackTrace();
077.
}
finally
{
078.
if
(reader !=
null
) {
079.
try
{
080.
reader.close();
081.
}
catch
(IOException e1) {
082.
e1.printStackTrace();
083.
}
084.
}
085.
}
086.
}
087.
088.
public
static
void
writeFile(String file, String text) {
089.
PrintWriter out =
null
;
090.
try
{
091.
out =
new
PrintWriter(
new
BufferedWriter(
new
FileWriter(file)));
092.
out.println(text);
093.
}
catch
(IOException e) {
094.
e.printStackTrace();
095.
}
096.
097.
out.close();
098.
}
099.
100.
public
static
void
main(String[] args) {
101.
gen();
102.
}
103.
}
图片的适配
文字和空间宽度适配后,大家可能发现部分的ImageView或者ImageButton部分还有些变大或者变小,有的变模糊了,这里需要美工提供多套图片,大家请看这张图:


以上是Google官方给出的分类标准( 虽然 Android 也支持低像素密度 (LDPI) 的屏幕,但无需为此费神,系统会自动将 HDPI 尺寸的图标缩小到 1/2 进行匹配 。) 所以对于我们的例子中1920*1200分辨率320dpi的平板,我们应该让美工制作放大2x的版本的图片,同时将图片放到drawable-xhdpi文件夹中,原来的图片放到drawable-mdpi文件夹中。这里需要注意一下,对于drawable你可能会写很多的比如shape或者selector的xml形式的drawable,他们本身不是图片而是一个xml文件,但是他们都会去引用真实的drawable图片,对于这种xml最好是要放到无dpi影响的drawable文件夹中(无后缀) 这样子以来,我们再把代码跑到1920*1200分辨率320dpi的平板上,发现图片部分也OK了,适配完毕。 这里还需要提醒的一点,并不是每个地方的图片都需要提供多套图片这种方案来解决,因为这种方案会带来使apk的size变大的副作用。所以大家可以根据实际需求,若可以通过上一节的方式来修改imageView的尺寸大小来解决(而非用wrap_content来指定layout_width和layout_height)的话,就不需要用多套图片的方式。
应用启动图标的适配
对于高分辨率低dpi的设备,我们经常会发现在launcher中我们的应用的启动icon被拉伸的模糊了,严重影响了门面的形象。 这里我们也通过提供多套icon的方式来解决,下面列表给出了不同屏幕密度中推荐的icon的size大小

在Android4.2以上的版本中,提供了对mipmaps的支持,说简单点就是他能对bitmap进行缩放的时候减少一些性能的耗损。如果你用Andorid Studio开发Android程序会发现Android Studio自动帮你创建了几个mipmaps文件夹,你可将应用的启动图标放到不同的mipmaps文件夹中而不是上述的drawable文件夹中,比如:

这里你至少要提供一个xxxhdpi类型的启动图标,因为Android会帮你自动缩小图标到对应的别的分辨率上(放大是会变模糊的),这样子可以节省些apk size。