進階之 -- 螢幕自適應

來源:互聯網
上載者:User

標籤:

夏至 歡迎轉載,也請保留這段申明,謝謝

以前在做小東西的時候,覺得只要適應了自己的手機就可以了,發現真的給自己挖了很多坑。今天終於好好地研究了一下,這是個痛苦的事情,但是卻又真的很有趣。
首先,先理解幾個概念。

1、螢幕尺寸
 螢幕尺寸指螢幕的對角線的長度,單位是英寸 : 1 英寸 =  2.54 mm 常見的尺寸有: 2.4 、2.8、3.5 、3.7,4.2、5.0等等
2、螢幕解析度
 螢幕解析度是指在橫縱向上的像素點數,單位是px ,1px = 1個像素點
3、螢幕像素密度

螢幕像素密度是指每 英寸上的像素點數,單位是dpi (也叫dp),螢幕像素密度與螢幕尺寸和螢幕解析度有關,在單一變化條件下,螢幕尺寸越小,解析度越高,像素密度越大,反之越小。

4、dp、dip、dpi、sp、px

dip 和 dp 是一個意思,即螢幕密度。至於 dpi 是什嗎?可以這樣理解,假如 1 英寸 裡面有160個像素,那麼這個螢幕的像素密度就是160dpi。在這種情況下,dp 和 px 換算非常簡單,如所示:

比如你在一個480x320的手機上布好了局,一看霸道炫酷,但你的單位是用px的,一到了800x480或者更高解析度的手機的時候,就是東倒西歪的了。所以,我們一般不建議用px做單位。

5、mdpi 、hdpi、xdpi、xxdpi

中還有個ldpi 的,不過現在基本沒人用這麼慘不忍睹的解析度了,所以就可以不用去管它了。用eclipse的我們經常會在 res 檔案夾中看到這樣定義的 drawable 檔案夾,那麼它們究竟是什麼意思呢?Google 官方指定按照下列標準進行區分:

在進行開發的時候,我們也需要對應不同的檔案夾放入不同的圖片:

如果是對縮放不是特別重要的,我們可以把它放在drawable檔案夾中,比如.9圖等

6、支援屏邊螢幕尺寸

回到我們的重點,我們今天要講的就是螢幕的自適應。

- 使用wrap_content、match_parent、weight

為了確保布局的靈活性並適應各種不同的螢幕,我們一般建議使用 wrap_content 內容包裹,和match_parent 填充整個容器,這樣就是不是絕對布局,而是可以根據螢幕的大小而自適應,但我們布局那麼多,不可能每個都用這兩個屬性,所以,局限性也很大。
至於 weight 權重這個屬性呢,好用是好用,不過一般是線上性布局中,但線性布局有個尷尬的地方就是,如果你的布局很多,那麼它的樹根就會很長,這個對於 UI 的最佳化是很不利的,而Google一般建議我們的布局層數不要超過10層,所以,如果是相對比較複雜的,都是建議使用 Reativelayout 相對布局。所以,局限也很大。

- 使用 dp 和百分比

這個時候,你可能會說,使用 dp 和 sp 啊,dp 是密度,你解析度不同,用 dp 也能很好的適應。 在網上找到兩張圖。使用相同的代碼在兩種不同的機型上啟動並執行效果如下:

很尷尬是不是,都使用了 dp 了,為什麼還會出現這樣的問題?其實很簡單,因為螢幕的多樣性,並不是所有的螢幕都是相同的 dp 長度,比如 Nexus One 屬於hdpi ,螢幕寬度是320dp,而 Nexus 5屬於xxhdpi ,螢幕寬度是360dp。所以,就算你用了dp也一樣存在問題。比如,你在320 dp 裡,寫了一個TextView ,字型大小為24 sp,在兩個不同的裝置下,大小顯而易見的不一樣。
這個時候,你是不是很絕望,感覺生無可戀的感覺。解析度不一樣,所以不能用px;螢幕寬度不一樣,所以不能用 dp ,還讓不讓人活了。別急,還是有解決方案的。參考兩位大神的神作:
鴻洋大神的:http://blog.csdn.net/lmj623565791/article/details/45460089
一葉飄舟的:http://blog.csdn.net/jdsjlzx/article/details/45891551

基本看了它們的你就會了。我自己只是把我的理解也寫一下而已。
當然,在安卓 5.0 之後,安卓也支持度百分比的了。這無疑是個好訊息。大家可以看到,為什麼我們在電腦瀏覽網頁什麼的,那些控制項大小,總能根據我們螢幕大小的不同而變化,就是人家用了百分比的效果啊,百分比就是佔據整個螢幕的比例,這個很容易懂吧。但是它的局限性就是在也在這裡,需5.0系統,我自己試了一下,效果真心不錯,但是放到4.3的系統,就亂套了。所以,可以適當瞭解。如果你想更近一步的瞭解,請參考鴻洋大神的作品:http://blog.csdn.net/lmj623565791/article/details/46695347

好了,言歸正傳,我們的方案很簡單,就是在項目中添加你的解析度的不同檔案夾,如:


自動產生 解析度包的 Java 代碼如下:

import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.PrintWriter;/** * Created by zhy on 15/5/3. */public class GenerateValueFiles {    private int baseW;    private int baseH;    private String dirStr = "./res";    private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";    private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n";    /**     * {0}-HEIGHT     */    private final static String VALUE_TEMPLATE = "values-{0}x{1}";    private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;800,1280;1080,1812;1080,1920;1440,2560;";    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());    }    /**     * @param supportStr     *            w,h_...w,h;     * @return     */    private String validateInput(String supportStr) {        StringBuffer sb = new StringBuffer();        String[] vals = supportStr.split("_");        int w = -1;        int h = -1;        String[] wh;        for (String val : vals) {            try {                if (val == null || val.trim().length() == 0)                    continue;                wh = val.split(",");                w = Integer.parseInt(wh[0]);                h = Integer.parseInt(wh[1]);            } catch (Exception e) {                System.out.println("skip invalidate params : w,h = " + val);                continue;            }            sb.append(w + "," + h + ";");        }        return sb.toString();    }    public void generate() {        String[] vals = supportStr.split(";");        for (String val : vals) {            String[] wh = val.split(",");            generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1]));        }    }    private void generateXmlFile(int w, int h) {        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>");        StringBuffer sbForHeight = new StringBuffer();        sbForHeight.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");        sbForHeight.append("<resources>");        float cellh = h *1.0f/ baseH;        System.out.println("height : "+ h + "," + baseH + "," + cellh);        for (int i = 1; i < baseH; i++) {            sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}",                    change(cellh * i) + ""));        }        sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}",                h + ""));        sbForHeight.append("</resources>");        File fileDir = new File(dirStr + File.separator                + VALUE_TEMPLATE.replace("{0}", h + "")//                        .replace("{1}", w + ""));        fileDir.mkdir();        File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml");        File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml");        try {            PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));            pw.print(sbForWidth.toString());            pw.close();            pw = new PrintWriter(new FileOutputStream(layyFile));            pw.print(sbForHeight.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 = 320;        int baseH = 400;        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();    }}

要修改的就一個地方,即基準,比如上面的是以 480 x 320 為基準的。,我們可以改成我們所需要的。當然,你也可以產生 jar 包,然後在命令列下,產生不同的代碼:

先把過程打包成jar包,然後輸入:

Java -jar xx.jar width height width,height_width,height

什麼意思呢,前面兩個是基準的意思。後面的是你要額外擴充的包。比如
我要一個1280x720 的基準,再額外擴充 一個 1366x768的包。就可以這樣寫:
java -jar test.jar 1280x720 1366,768

後面也是要擴充的,這裡可以根據不同而選擇不同。、

當然你也可以直接你要的基準的包:

但這裡也有局限性,看到網上很多螢幕說,如果帶有虛擬鍵的手機,這個方案也不適合了,只能跟著虛擬鍵來重新適配,當然這裡還是適用於很多記性的。這裡把常用的兩個基準 480x320 、800x480,和1280x720 基準的res包發給大家,當然我建議你自己弄。CSDN 的附件太蛋疼了,用360好了:
160 基準 https://yunpan.cn/cPFiutXhwhdpB 訪問密碼 1bc7
240 基準 https://yunpan.cn/cPFiFXihU7ytz 訪問密碼 29df
320 基準 https://yunpan.cn/cPFixBsSQqrrX 訪問密碼 91da

如果消失了,請聯絡我。

7、安卓 TV 跟手機的不同

這裡我們要 講講安卓TV 跟手機的不同。在手機上,我們可以以一個480x320的基準來設計螢幕大小,因為手機撐死的就5.0寸,所以,這個基準還是非常不錯的。但是安卓TV不一樣,都是平板類的,而且是比較大的液晶屏。所以,我們的基準就是要變一下。要用1280x720 的為基準,當然,這個只是個人理解。有錯誤也歡迎指出。

進階之 -- 螢幕自適應

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.