巧用dimens适配多个分辨率


巧用dimens适配多个分辨率(一)

一、关于布局适配
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 ,下面的图标制作也在次基础上进行比例的换算)上设计。
先了解一下屏幕的级别:
屏幕级别
屏幕密度
比率(相对)
物理大小(英寸)
像素大小
通常的分辨率
ldpi
120
3
0.75
1
120
 
mdpi
160
4
1
1
160
320*480
hdpi
240
6
1.5
1
240
480*800
xhdpi
320
8
2
1
320
720*1280
xxhdpi
480
12
3
1
480
1080*1800
说明:
屏幕级别:
注意屏幕级别是按照密度分级,和像素没有关系。如果非要让密度和像素扯上关系,则需要一个参照系, 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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值