Android 解決屏幕適配(尺寸)

聲明: 本文只講屏幕尺寸的問題,即px–VS–各種類型屏幕
先上個結果示例

<TextView 
        android:layout_height="@dimen/x540"
        android:layout_width="@dimen/x540"
        android:background="@android:color/holo_green_dark"/>

UI給出的設計圖基準1920*1080,圖爲540px對應的各個屏幕顯示效果
這裏寫圖片描述

一、屏幕適配的問題

相信很多Android開發人員都曾經頭疼過屏幕適配的問題,當UI妹妹把她的設計圖和尺寸標註圖拿來的時候,我們都會無奈的瞥一眼那些紅紅的px標註,其實對好多開發人員來說,那些亂七八糟的標註根本就沒有用,只是大致看看位置,然後憑自己的感覺去佈局。一邊是UI妹妹的px,一邊是市場上千百種手機屏幕,我們android攻城師的事情就來了–屏幕適配。

二、各種亂七八糟的單位

各種亂起八糟的單位不想說了,想必不少人都曾經在百度上搜索,關鍵詞爲“Android 手機屏幕適配”,結果balabala出來一大堆的屏幕單位的講解,相信大家也都能明白了。簡單羅列一下:dp、sp、px、in、pt、mm等等。我就不再逐個說明了,不懂得自行百度腦補。補充說一下,還有好多可以優化適配的方法,比如用weight,matchparent、ralativelayout佈局等等,在此我就不多說了。

另外想說一下我們開發時用到的values文件夾。
(a)文件夾名稱中各屬性的含義–(各屬性是按優先級先後排列出來的)
values-mcc310-en-sw320dp-w720dp-h720dp-large-long-port-car-night-ldpi-notouch-keysexposed-nokeys-navexposed-nonav-v7
b)上述例子屬性的中文說明
values-mcc310(sim卡運營商)-en(語言)-sw320dp(屏幕最小寬度)-w720dp(屏幕最佳寬度)-h720dp(屏幕最佳高度)-large(屏幕尺寸)-long(屏幕長短邊模式)-port(當前屏幕橫豎屏顯示模式)-car(dock模式)-night(白天或夜晚)-ldpi(屏幕最佳dpi)-notouch(觸摸屏模類型)-keysexposed(鍵盤類型)-nokey(硬按鍵類型)-navexposed(方向鍵是否可用)-nonav(方向鍵類型)-v7(android版本)

三、設計思路

現在在度娘上看到的各種適配方案,大部分是適配屏幕的像素密度,但是對於屏幕的寬度的適配卻寥寥無幾。
如果我們真的想把UI妹妹的px值完美的適配到我們各種屏幕上,我們通常的一個做法是計算原設計圖中的某一個px值所佔的比例,然後在各個value文件裏添加合適的dp值。所用的思路方法就相當於網頁設計中的百分比。舉個例子,UI給出的設計圖基準是1920*1080,然後一個寬度是100px,那我們在w720dp文件夾中,就添加(100/1080*720)dp。根據這個方法,我們可以根據UI的設計圖基準,每個values文件中都把對應的每個px值的dp值都計算出來,那我們在開發中不就可以省事多了麼。
剛聽過是不是有一絲的興奮,但是是不是又發現很麻煩?1080的寬度,我們要計算1080*5次(假設我們設定5個values文件夾)。但是我們是萬能的程序員,當然是寫代碼的啦。。。哈哈

四、代碼實現

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class GenerateValueFiles {
    private int baseW;
    private int baseH;
    private String dirStr = "./res";
    private final static String WTemplate = "<dimen name=\"x{0}\">{1}dp</dimen>\n";
    private final static String HTemplate = "<dimen name=\"y{0}\">{1}dp</dimen>\n";
    private final static String VALUE_TEMPLATE = "values-sw{0}dp";
    private static final String SUPPORT_DIMESION = "320;360;480;600;720;";
    private String supportStr = SUPPORT_DIMESION;
    public GenerateValueFiles(int baseX, int baseY, String supportStr) {
        this.baseW = baseX;
        this.baseH = baseY;
        if (!this.supportStr.contains(baseX + "," + baseY)) {
            this.supportStr += baseX + "," + baseY + ";";
        }
        this.supportStr += validateInput(supportStr);
        System.out.println(supportStr);
        File dir = new File(dirStr);
        if (!dir.exists()) {
            dir.mkdir();
        }
        System.out.println(dir.getAbsoluteFile());
    }
    private String validateInput(String supportStr) {
        StringBuffer sb = new StringBuffer();
        String[] vals = supportStr.split("_");
        int w = -1;
        String[] wh;
        for (String val : vals) {
            try {
                if (val == null || val.trim().length() == 0)
                    continue;
                wh = val.split(",");
                w = Integer.parseInt(wh[0]);
            } catch (Exception e) {
                System.out.println("skip invalidate params : w,h = " + val);
                continue;
            }
            sb.append(w);
        }
        return sb.toString();
    }
    public void generate() {
        String[] vals = supportStr.split(";");
        for (String val : vals) {
            String[] wh = val.split(",");
            generateXmlFile(Integer.parseInt(wh[0]));
        }
    }

    private void generateXmlFile(int w) {
        StringBuffer sbForWidth = new StringBuffer();
        sbForWidth.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        sbForWidth.append("<resources>");
        float cellw = w * 1.0f / baseW;
        System.out.println("width : " + w + "," + baseW + "," + cellw);
        for (int i = 1; i < baseW; i++) {
            sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}",
                    change(cellw * i) + ""));
        }
        sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}",
                w + ""));
        sbForWidth.append("</resources>");
        File fileDir = new File(dirStr + File.separator
                + VALUE_TEMPLATE//
                        .replace("{0}", w + ""));
        fileDir.mkdir();

        File layxFile = new File(fileDir.getAbsolutePath(), "dimens.xml");
        try {
            PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
            pw.print(sbForWidth.toString());
            pw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static float change(float a) {
        int temp = (int) (a * 100);
        return temp / 100f;
    }

    public static void main(String[] args) {
        int baseW = 1080;
        int baseH = 1920;
        String addition = "";
        try {
            if (args.length >= 3) {
                baseW = Integer.parseInt(args[0]);
                baseH = Integer.parseInt(args[1]);
                addition = args[2];
            } else if (args.length >= 2) {
                baseW = Integer.parseInt(args[0]);
                baseH = Integer.parseInt(args[1]);
            } else if (args.length >= 1) {
                addition = args[0];
            }
        } catch (NumberFormatException e) {

            System.err
                    .println("right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;");
            e.printStackTrace();
            System.exit(-1);
        }
        new GenerateValueFiles(baseW, baseH, addition).generate();
    }

}

五、另外的疑問

UI圖中給出的字體也是px值,不知道這個px值是怎麼算的,我們的sp又是怎麼算出來的,字體能不能精確的適配呢???還請各位大神不吝賜教。。。

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