Android屏幕適配講解與實戰

来源:https://www.cnblogs.com/WUXIAOCHANG/archive/2019/03/16/10544545.html
-Advertisement-
Play Games

文章大綱 一、屏幕適配是什麼二、 重要概念講解三、屏幕適配實戰四、項目源碼下載 一、屏幕適配是什麼 Android中屏幕適配就是通過對尺寸單位、圖片、文字、佈局這四種類型的資源進行合理的設計和規劃,在佈局時合理利用各種類型的資源,讓佈局擁有適應能力,能在各種設備下保持良好的展現效果。 二、常見屏幕適 ...


文章大綱

一、屏幕適配是什麼
二、 重要概念講解
三、屏幕適配實戰
四、項目源碼下載

 

一、屏幕適配是什麼

  Android中屏幕適配就是通過對尺寸單位、圖片、文字、佈局這四種類型的資源進行合理的設計和規劃,在佈局時合理利用各種類型的資源,讓佈局擁有適應能力,能在各種設備下保持良好的展現效果。

二、常見屏幕適配方法介紹

1 屏幕尺寸

  屏幕尺寸是指屏幕對角線的長度,單位是英寸,1英寸=2.54釐米

2 屏幕解析度

  屏幕解析度是指橫縱向上的像素點數,單位是px,1px=1個像素點,一般以縱向像素橫向像素,如19201080,解析度越高,顯示效果越好。

3 屏幕像素密度

  屏幕像素密度是指每英寸上的像素點數,單位是dpi,屏幕像素密度與屏幕尺寸和屏幕解析度有關。

4. px、dp、sp

(1)安卓裡面獲取屏幕寬和高,也是以px作為單位的。
(2)在160dpi(即解析度是480*320)基準下,1dip=1px(也就是px不能適配所有機型),如下圖所示,要充滿屏幕,箭頭的px值是不一樣的。1dp=那個機型dpi/160px。所以用dp會比px好。

 

(3)在使用sp(設置文字的)時候,使用偶數,不要使用奇數或者小數,最最推薦的是12.14.18,22sp的文字大小(儘量不要使用12sp以下的大小,用戶可能看不清楚)。

5. mdpi,hdpi,xdpi,xxdpi

安卓軟體運行時,會自動根據屏幕像素去不同文件夾載入對應圖片。

 

三、屏幕適配實戰

1. 使用dp設置控制項大小,sp設置字體大小(不可行)

activity_main2.xml佈局代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:textSize="20sp"
        android:text="按鈕1"/>

    <Button
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_marginTop="20dp"
        android:textSize="20sp"
        android:text="按鈕2"/>

</LinearLayout>

運行結果如下:

 

得出結論:即使使用dp設置控制項大小,sp設置字體大小,也是無法適配所有手機的。因為這是谷歌自己的一個標準。dp是根據屏幕像素和解析度一起來解決的。但是有些手機像素和解析度不是對應關係,所以不行。

2. weight屬性使用

activity_main3.xml佈局代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context=".MainActivity">

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="20sp"
        android:text="按鈕1"/>

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:textSize="20sp"
        android:text="按鈕2"/>

</LinearLayout>

運行結果如下:

 

得出結論:採用weight,可以使得組件按屏幕大小進行放大縮小,weight的計算方式如下:

 

如果將xml中的android:layout_weight屬性值1和2互換,則結果是相反的,有興趣伙伴可以下載源碼看看效果。

3. 使用自動拉伸點陣圖.9圖

什麼是.9圖
  因為Android有太多的解析度了,當圓角矩形控制項在被拉伸放大的時候,圓角的部分就會出現模糊的情況。而點九切圖就不同,它可以保證不管你上下還是左右拉伸,放大都可以保持原有的清晰度。
.9圖存放位置

 

4. 屏幕方向限定符large

  比如我們想在屏幕豎屏時候載入什麼佈局,在屏幕橫線時候載入什麼佈局。在手機載入什麼佈局,在平板電腦載入什麼佈局。
  該文章暫不展開討論,將在Fragment使用中進行講解。

5.多文件適配(重要)

  大家經過上面的學習之後,已經知道有些手機像素和解析度不是對應關係,無法使用dp等單位來解決,那麼我們可以以某個常見的屏幕解析度作為基準,自定義需要適配到的屏幕解析度的xml文件,如下圖所示:

   

使用生成器生成對應的文件
生成器代碼(使用320*480作為基準)如下:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

/**
 * Created by 吳曉暢
 */
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";

    private final static String VALUE_TEMPLATE = "values-{0}x{1}";

    //新增文件的解析度,以x,x;隔開
    private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;768,1280;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());

    }

    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) {
        
        //基準大小,比如320.480,其他則以這個基準進行放大縮小
        int baseW = 320;
        int baseH = 480;
        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();
    }

}

運行代碼,結果會在項目的res文件夾中生成對應的內容,如下圖所示:

   

溫馨提示:上圖每個文件夾是以320*480作為基準進行放大縮小後的px值

將上面生成的文件夾複製到實際項目中
複製所有文件夾,右擊studio中的res文件夾進行粘貼

 

xml佈局中進行引用

activity_main4.xml代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:layout_width="@dimen/x200"
        android:layout_height="@dimen/y30"
        android:text="按鈕1"/>

    <Button
        android:layout_width="@dimen/x200"
        android:layout_height="@dimen/y30"
        android:layout_marginTop="@dimen/y30"
        android:text="按鈕2"/>

</LinearLayout>

運行結果如下圖所示:

 

溫馨提示:

  1. 如果運行後發現某個尺寸的屏幕沒有是配到,那麼可以在生成器中添加對應屏幕尺寸,重新生成文件夾,之後拷貝到項目中即可
  2. 圖片適配則可以採用圖片放在不同文件夾裡面,系統會自動選圖,但最好每次切圖都包含多種解析度的圖片,例如某一測試的機器是xxhdpi密度的,所以當把圖片放在xxhdpi時候(其他文件夾沒放),載入時候占用記憶體是較小的。預設是沒有載入任何東西(運行一個空白app)占用的記憶體。如果載入其他像素下的圖片,則會占用很多內容。所以總結來說就是要各個文件夾都放有圖片,可以減少占用記憶體的載入。
 

四、項目源碼下載

鏈接:https://pan.baidu.com/s/1xDRVaSS9Kk9OGLzloBeneA
提取碼:0zyt

 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在本節中,我們將講述抓取政府官網地方新聞。並將抓取的新聞數據融入到以下兩張數據表news_site和news中。 ...
  • 數據完整性主要指的是數據的精確性和可靠性,目的就是為了防止資料庫中存放的數值,以及字元具有合法性(即按照管理員定義的規則進行存放) 分為以下四類: 實體完整性要求每一個表中的主鍵欄位都不能為空或者重覆的值。實體完整性指表中行的完整性。要求表中的所有行都有唯一的標識符,稱為主關鍵字。主關鍵字是否可以修 ...
  • 1.給表添加列 預設情況下,添加的列會添加到最後一列。 如果要求添加到指定位置,語句如下: 如果想要添加到第一列,語句如下: 如果要求不可為空,語句如下: 2.給表添加註釋 3.給列添加註釋 以上語句是給supplier_seller表的company_name列添加註釋:供應主體名稱 4.參考鏈接 ...
  • 首先,新建數據表aaa、bbb以及他們相關聯的數據表avb;欄位名如下圖 填充點數據,如下: 上面設計表的時候,故意在兩個表中有相同欄位con,如果不做處理的話,在php程式中,看看什麼情況?得到的結果集中的con是aaa表的,還是avb表的? 如果將aaa LEFT JOIN avb 改為 avb ...
  • Apriori演算法 首先,Apriori演算法是關聯規則挖掘中很基礎也很經典的一個演算法。 轉載來自:鏈接:https://www.jianshu.com/p/26d61b83492e 所以做如下補充: 關聯規則:形如X→Y的蘊涵式,其中, X和Y分別稱為關聯規則的先導(antecedent或left- ...
  • 什麼是事務 事務(Transaction),一般是指要做的或所做的事情。資料庫中事務是指多個sql語句,要麼全部執行成功,要麼全部執行失敗。 begin; # 開始事務 commit; # 提交事務 rollback; # 回滾 四個特性,ACID 原子性(Atomicity):事務作為一個整體被執 ...
  • 一個數據表,需要兩個欄位聯合起來一塊做主鍵的時候。舉例如下: 直接用sql語句的話如下 或者在phpmyadmin中操作,如下圖: 完成後,這時候插入數據就會發現,a_id和b_id組合來看,數據有重覆會提示插入錯誤的 設置後,我又後悔了,要取消數據表的主鍵,sql語句如下: ...
  • Gradle sync failed: Unable to start the daemon process. ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...