巧用dimens適配多個分辨率


巧用dimens適配多個分辨率(一)

一、關於佈局適配
1、不要使用絕對佈局
2、儘量使用match_parent 而不是fill_parent 。
3、能夠使用權重的地方儘量使用權重(android:layout_weight)
4、如果是純色背景,儘量使用androidshape 自定義。
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圖標的大小是48mdpi),72hdpi),96xhdpi)得出的最小公約數)。
第二,長寬最好是偶數。因爲奇數在進行等比壓縮的時候可能有問題。
第三,根據上面兩條,如果長寬是6的倍數最理想。
第四,如果可以拉伸而不改變設計意圖的情況下,比如純色背景,則使用android9path工具製作成.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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章