巧用dimens适配多个分辨率
2015-07-24 09:31
489 查看
一、关于布局适配
1、不要使用绝对布局
2、尽量使用match_parent 而不是fill_parent 。
3、能够使用权重的地方尽量使用权重(android:layout_weight)
4、如果是纯色背景,尽量使用android的shape 自定义。
5、如果需要在特定分辨率下适配,可以在res目录上新建layout-HxW.xml的文件夹。比如要适配1080*1800的屏幕(魅族MX3采用此分辨率)则新建layout-1800x1080.xml的文件夹,然后在下面定义布局。Android系统会优先查找分辨率相同的布局,如果不存在则换使用默认的layout下的布局。
二、关于图片制作
1、关于设计:
设计图先定下一个要设计的尺寸,而且尽量采用在目前最流行的屏幕尺寸(比如目前占屏幕比重比较多的是480系列,也即是480*800或者400*854,下面的图标制作也在次基础上进行比例的换算)上设计。
先了解一下屏幕的级别:
[align=left]屏幕级别[/align] | [align=left]屏幕密度[/align] | [align=left]比率(相对)[/align] | [align=left]物理大小(英寸)[/align] | [align=left]像素大小[/align] | [align=left]通常的分辨率[/align] | |
[align=left]ldpi[/align] | [align=left]120[/align] | [align=left]3[/align] | [align=left]0.75[/align] | [align=left]1[/align] | [align=left]120[/align] | |
[align=left]mdpi[/align] | [align=left]160[/align] | [align=left]4[/align] | [align=left]1[/align] | [align=left]1[/align] | [align=left]160[/align] | [align=left]320*480[/align] |
[align=left]hdpi[/align] | [align=left]240[/align] | [align=left]6[/align] | [align=left]1.5[/align] | [align=left]1[/align] | [align=left]240[/align] | [align=left]480*800[/align] |
[align=left]xhdpi[/align] | [align=left]320[/align] | [align=left]8[/align] | [align=left]2[/align] | [align=left]1[/align] | [align=left]320[/align] | [align=left]720*1280[/align] |
[align=left]xxhdpi[/align] | [align=left]480[/align] | [align=left]12[/align] | [align=left]3[/align] | [align=left]1[/align] | [align=left]480[/align] | [align=left]1080*1800[/align] |
屏幕级别:
注意屏幕级别是按照密度分级,和像素没有关系。如果非要让密度和像素扯上关系,则需要一个参照系,android使用mdpi级别作为标准参照屏幕,也就是说在320*480分辨率的手机上一个密度可以容纳一个像素。然后其他密度级别则在此基础上进行对比。如果理想情况下,480*800的屏幕一个密度可以容纳1.5个像素。
物理大小:
单位是英寸而不是像素,也就说一个英寸在任何分辨率下显示的大小都是一样的,但是像素在密度不同的手机里面显示的实际的大小是不一样的(这就是为什么android手机需要适配的原因)。
然后就是重点。
假设1像素在160密度下显示1英寸,则1像素在240密度基础上显示大约0.67英寸,在320密度下显示0.5英寸。于是就出现一种情况,在电脑上的一个像素,在不同的手机上看实际的大小不一样。那么怎么让“设计效果”在不同的手机上看起来显示的区域一样呢?
还是假设一个像素在160密度下的显示在一个密度内,也假设就是一英寸。那么需要几个像素才能在240密度级别下显示在一英寸范围内呢?答案是1.5个像素(根据上图的比率换算)。
了解了这个关系,接下来就是图标的制作。
2、关于切图。
关于切图有几个建议:
第一,长宽最好是3的倍数(根据android的推荐logo图标的大小是48(mdpi),72(hdpi),96(xhdpi)得出的最小公约数)。
第二,长宽最好是偶数。因为奇数在进行等比压缩的时候可能有问题。
第三,根据上面两条,如果长宽是6的倍数最理想。
第四,如果可以拉伸而不改变设计意图的情况下,比如纯色背景,则使用android的9path工具制作成.9的图片。
3、关于图标的适配。
然后接下来的一切就和设计稿没什么关系。在切好图的基础上,根据屏幕密度、像素和实际大小的比例关系。假如设计司在480*800的分辨率下做好了设计图,并且切好图,如果你需要适配720*1280屏幕,该怎么做?根据比例,他们的关系是2:3,于是你需要按照1.5倍比例制作图标,比如你在480*800的设计稿上切下来一个20*20像素的图,那么你就需要制作一个等比放大成30*30像素的图标,这样同一个图标在480*800的屏幕和720*1280的屏幕上显示的实际大小才一样。同理,如果你需要适配xxhdpi则需要在20*20的基础上制作一个等比放大成40*40像素的图标。
4、关于图标的目录,480*800切下来的图我们放在drawable-hdpi目录下,按照2:3放大的图标放在drawable-xhdpi目录下,按照2倍放大的图标放在drawable-xxhdpi目录下。
android会根据手机的密度优先查找对应的目录的资源,
比如408*800分辨率下的手机如果密度是160,则自动加载drawable-hdpi这个目录下的图标,
如果720*1280密度是240的手机自动加载drawable-xhdpi这个目录下的图标。如果没有这个文件夹,则查找和240最接近的对应密度文件夹。
三、其它
接下来要说的估计会让你失望,根据上面的步骤也不能完全解决适配的问题,只能是大概适配,而就算根据上面的步骤大概适配了,实际在手机上的效果也有出入。
比如魅族MX3的分辨率是1080*1800,标准情况下密度是480,但是他的密度大约是524,和480接近,也就是会查找drawable-xxhdpi这个资源下的文件。也就是说你在480*800分辨率下切图然后按两倍放大的图标在这台手机上显示的效果还是比实际的小。
而另一个要说的问题是540*960或者640*960,他们的密度很可能是或者接近240也可能是320。于是在480*800的设计稿上切下来的图并且进行的适配制作,在这些手机上显示的实际大小也可能或大或小。
综上所述,我也只是把我的理解和经验分享一下,但是并不能完美适配屏幕,仅仅当做抛砖引玉,如果您路过并且看到这份建议,如果你正好有更好的方案能够进行适配,请不吝赐教。
巧用dimens适配多个分辨率(二)
上篇文章,介绍了使用dimension文件做适配。说道了使用代码自动生成所有的dimension文件,接下来我们给出相关代码。
DimensTools:
package com.example.test;
import java.io.*;
import java.util.*;
/**
*dimens数据自动生成工具
*
*/
public class DimensTools {
/**源文件 */
static String oldFilePath = "./res/values-nodpi/dimens.xml";
/**新生成文件路径 */
static String filePath720 = "./res/values-1280x720/dimens.xml";
/**新生成文件路径 */
static String filePath672 = "./res/values-1280x672/dimens.xml";
/**新生成文件路径 */
static String filePath1080 = "./res/values-1920x1080/dimens.xml";
/**缩小倍数 */
static float changes = 1.5f;
public static void main(String[] args) {
//生成1-1920px
String allPx= getAllPx();
DeleteFolder(oldFilePath);
writeFile(oldFilePath, allPx);
String st = convertStreamToString(oldFilePath, changes);
DeleteFolder(filePath720);
writeFile(filePath720, st);
DeleteFolder(filePath672);
writeFile(filePath672, st);
String st1 = convertStreamToString(oldFilePath, 1f);
DeleteFolder(filePath1080);
writeFile(filePath1080, st1);
}
/**读取文件 生成缩放后字符串 */
public static String convertStreamToString(String filepath, float f) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader bf = new BufferedReader(new FileReader(filepath));
String line = null;
System.out.println("q1");
String endmark = "px</dimen>";
String startmark = ">";
while ((line = bf.readLine()) != null) {
if (line.contains(endmark)) {
int end = line.lastIndexOf(endmark);
int start = line.indexOf(startmark);
String stpx = line.substring(start + 1, end);
int px = Integer.parseInt(stpx);
int newpx = (int) ((float) px / f);
String newline = line.replace(px + "px", newpx + "px");
sb.append(newline + "\r\n");
} else {
sb.append(line + "\r\n");
}
}
System.out.println(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
/**
*根据路径删除指定的目录或文件,无论存在与否
*
*@param sPath
* 要删除的目录或文件
*@return 删除成功返回 true,否则返回 false。
*/
public static boolean DeleteFolder(String sPath) {
File file = new File(sPath);
// // 判断目录或文件是否存在
if (!file.exists()) { // 不存在返回 false
return true;
} else {
// 判断是否为文件
if (file.isFile()) { // 为文件时调用删除文件方法
return deleteFile(sPath);
} else { // 为目录时调用删除目录方法
// return deleteDirectory(sPath);
}
}
return false;
}
/**存为新文件 */
public static void writeFile(String filepath, String st) {
try {
FileWriter fw = new FileWriter(filepath);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(st);
bw.flush();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**生成全px文件 */
public static String getAllPx() {
StringBuilder sb = new StringBuilder();
try {
sb.append("<resources>" + "\r\n");
sb.append("<dimen name=\"screen_width\">1920px</dimen>" + "\r\n");
sb.append("<dimen name=\"screen_height\">1080px</dimen>" + "\r\n");
for (int i = 1; i <= 1920; i++) {
System.out.println("i="+i);
sb.append("<dimen name=\"px" + i + "\">" + i + "px</dimen>"
+ "\r\n");
}
sb.append("</resources>" + "\r\n");
System.out.println(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
/**
*删除单个文件
*
*@param sPath
* 被删除文件的文件名
*@return 单个文件删除成功返回true,否则返回false
*/
public static boolean deleteFile(String sPath) {
boolean flag = false;
File file = new File(sPath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
flag = true;
}
return flag;
}
}
使用方法:cmd下使用javac ,java命令运行。这样有点费劲哈,改天用ant写个自动脚本放上来。
注:先建立好相应的文件夹,672也按照1.5的比例缩放的。可以根据自己的需要调整。
我们的做法是在 AndroidManifest.xml 设置
<!-- 屏幕适配 -->
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true" /> 然后每个分辩率都切一套图 就行
原文来自:http://www.67tgb.com/?p=574
相关文章推荐
- setting
- Linux declare声明
- 毕业生大礼包之论文查重
- 【算法学习】【图像增强】【Retinex】源码运行
- 无法连接到SQL Server 2008 R2
- eclipse运行maven的jetty插件内存溢出
- 程序员的作息时间表
- MongoDB 的使用
- 实名认证方案
- CentOS 6.5下GIT服务器、gitweb搭建
- HDU 5305 Friends(2015多校第二场 dfs + 剪枝)
- 博弈
- UITextField详解
- MongoDB  安全
- HDU 1535--Schedule Problem【差分约束】
- 链表,配合critical section
- 一个用户加入多个组
- 【system】利用Diskpart命令(cmd)解决装机分区格式不对,增大C盘空间问题
- 应用程序配置文件中的连接字符串不包含必需的 providerName 特性
- 事情高大谈话(智能家居)技术和平台