android UI適配簡單記錄三

作為一個開發(fā)人員但校,屁股決定腦袋,偶爾需要換位思考啡氢,站在UI設計人員的角度考慮下状囱,想想UI設計是怎么來的。

這里可以先簡單看下 Material Design倘是,了解下ui設計亭枷。
https://material.io/design/layout/understanding-layout.html#usage

Material是一個適應性指南,組件和工具系統(tǒng)搀崭,支持用戶界面設計的最佳實踐叨粘。在開源代碼的支持下,Material簡化了設計人員和開發(fā)人員之間的協(xié)作瘤睹,并幫助團隊快速構建精美的產(chǎn)品升敲。

Material上的示例標識的單位是dp,但是現(xiàn)實中可能你拿到的圖片標識單位還是px轰传。


例如下圖這種圖驴党。

圖片出處:
Android 應用設計開發(fā)有沒有更好的 UI 適配方法? - captain的回答 - 知乎
https://www.zhihu.com/question/22181844/answer/58124185

想象一下获茬,如何畫一張這樣簡單的界面的圖并標識尺寸港庄。
打開電腦自帶畫圖軟件,新建一個400x400像素大小的文件(隨便畫畫)锦茁,單擊查看,勾選標尺和狀態(tài)欄,網(wǎng)格線攘轩。

image.png

這里只是簡單畫一畫,并不是很精準码俩。但是在畫圖的過程中加深了對px以及ui設計的了解。專業(yè)的畫圖工具功能會更全,但是一般都收費笨篷。


首先瞳秽,這張圖上的單位都是px,因為圖片設計基本單位是px率翅,要如何把px換成dp呢练俐?


image.png
以下部分出處:
安卓UI圖px標注適配攻略:批量轉化px為dp
https://blog.csdn.net/zengd0/article/details/52464627

px轉dp的公式:dp = px/density
density是設備密度,有了設備密度冕臭,我們才可以將px轉為dp腺晾。
這時候你可能會想,Android系統(tǒng)不是提供了api供我們轉換嗎辜贵,或者Android系統(tǒng)獲取設備密度:context.getResources().getDisplayMetrics().density悯蝉,然后將UI圖的px去除以desity?
非也托慨。density值是獲取了鼻由,但是請問UI圖上的px值是按照你的手機來標注的嗎?如果UI圖是以iPhone6手機(4.7寸屏幕厚棵,分辨率1334*750)為基準進行設計的蕉世,那么你用這個px值去除以你自己安卓手機的設備密度,怎么可能對婆硬。
也就是說狠轻,我們要獲取UI圖的設備密度(density)。

這里說的設備密度是指density 彬犯。
計算公式:density = PPI/160哈误。
ppi計算公式如下圖。

image.png

由于示例圖片在設計的時候是適配640 * 1136機型的圖,屏幕尺寸應該是4.0英寸(根據(jù)分辨率搜索所得)。因此ppi ≈ 326划乖。
density = 326/160 = 2.0族檬。
所以為640 * 1136機型設計的ui圖中, 一個 寬度為 50 px的圖形轉換 dp : dp =50 px/2.0 = 25dp。

640 * 1136并不是主流機型,這里以市面上較為主流720 * 1280機型分辨率為例,簡單看下如何適配分辨率720 * 1280的屏幕。
這里計算下720 * 1280 與640 * 1136的寬高比率戈鲁。720/640 = 1.125 1280/1136 ≈ 1.127,屏幕分辨率比率幾乎相等嘹叫,就按1.125 去計算婆殿,進行縮放。50 px應該 乘以 1.125罩扇, 50 px * 1.125 = 56.25px婆芦。

640 x 1136中寬度為 50 px的圖形在720 x1280 中對應的圖形大小是56.25px怕磨。
而720 * 1280的屏幕,縮放因子density一般是2.0消约,因此
dp = 56.25px / 2.0 ≈ 28.13dp 肠鲫。因此在控件里寫28.13dp。

如果不能理解可以看下下面的例子或粮。
打開window自帶畫圖工具导饲,新建一個200 x 200 像素大小的圖,以中心為原點畫一個寬度100px的正方形氯材,中心坐標(100,100)渣锦,左上角坐標(50,50),右下角坐標(150氢哮,150)泡挺。


image.png

然后重新調整大小至800 x 800 px,擴大4倍命浴。



此時,正方形寬度變成了400px 贱除,中心坐標(400,400)生闲,左上角坐標(200,200),右下角坐標(600月幌,600)碍讯。隨著圖片大小放大,正方形大小也放大了扯躺。不同分辨率中捉兴,正方形的寬度不一致(可以把正方形想象成如TextView、Button之類的控件)录语。
image.png

在有su權限的設備上倍啥,執(zhí)行命令,將屏幕分辨率調整至

adb shell wm size 200x200

由于這臺設備帶有底部虛擬鍵并且android默認帶狀態(tài)欄和工具欄澎埠,所以需要這里先隱藏下虽缕。

//因此狀態(tài)欄和底部導航欄
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        View decorView = getWindow().getDecorView();
        int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);
    }
}

因此工具欄則需要修改manifest文件中,application節(jié)點下的 android:theme蒲稳,修改結果如下所示氮趋。

 android:theme="@style/Theme.AppCompat.Light.NoActionBar"

xml文件如所示。由于設備density為1.0江耀,所以layout_width寫100dp剩胁。

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

  <TextView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="test"
        android:textSize="12sp"
        android:gravity="center"
        android:background="@color/colorPrimary"/>

</LinearLayout>

運行結果如下所示。白色部分內(nèi)為界面內(nèi)祥国,黑色部分為界外昵观,黑色部分可忽略。


此時再將屏幕分辨率調到800x800

adb shell wm size 800x800

屏幕上會變成如下所示。



可以發(fā)現(xiàn)控件寬度為100px索昂,要想使控件寬度為400px建车,此時就需要修改xml文件了。將layout_width和textSize都放大4倍椒惨。

  <TextView
        android:layout_width="400dp"
        android:layout_height="400dp"
        android:text="test"
        android:textSize="48sp"
        android:gravity="center"
        android:background="@color/colorPrimary"/>

運行結果如下所示


將截屏圖片與設計圖片簡單對比缤至,大小基本一致,控件的寬度達到了設計圖的寬度為400px的效果康谆。


這是比較極端的情況领斥,僅用于舉例。

但是其實剛剛將屏幕分辨率調到800x800后,要想使控件寬度為400px沃暗,除了修改xml文件月洛,還有另一種修改方法:修改屏密度。
首先將layout_width和layout_height改回100dp孽锥,textSize改回12sp嚼黔。

    <TextView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="test"
        android:textSize="12sp"
        android:gravity="center"
        android:background="@color/colorPrimary"/>

然后運行以下命令修改dpi。

//160*4 = 640 這是設置android中的Dpi 值
adb shell wm density 640

運行該命令可以修改屏幕密度惜辑。
此時縮放因子density = dpi/160 = 4唬涧。
又 px = dp * density
所以當layout_width為100dp時, 控件的實際物理大小為100dp*4 即 400px盛撑。
運行結果如下所示碎节,與方法一結果一致。


這個例子很直觀的顯示出抵卫,UI受density和分辨率的影響狮荔。

我們先控制單一變量去思考適配ui。
先以分辨率為變量為例進行說明介粘。
由于UI受屏幕分辨率影響殖氏,屏幕分辨率限定符法就出現(xiàn)了。這個方法我真的沒有找到出處姻采。
屏幕分辨率限定符法受葛,即每種屏幕分辨率的設備需要定義一套 dimens.xml 文件。這種方法也有人稱之為偎谁,百分比適配方法总滩。
以某一分辨率為基準,生成所有分辨率對應像素數(shù)列表巡雨。
現(xiàn)在我們以200x200的分辨率為基準:
將屏幕的寬度分為200份闰渔,取值為x1~x200
將屏幕的高度分為200份,取值為y1~y200
在values目錄下新建lay_x.xml和lay_y.xml文件铐望。

簡單來說冈涧,就是將 android:layout_width茂附,android:layout_height, android:textSize等尺寸大小督弓,按不同的分辨率营曼,定義在不同的values下。

在android studio中新建MakeXml .java文件愚隧,根據(jù)MakeXml 生成xml文件蒂阱。
代碼如下。由于我手上屏幕為橫屏狂塘,所以稍微修改了一點录煤,以480x320為基準分辨率。

代碼出處:
Android-屏幕適配全攻略(絕對詳細)(二)
http://www.reibang.com/p/ad563d169871

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

public class MakeXml {
    private final static String rootPath = "D:\\layoutroot\\values-{0}x{1}\\";

  /*  private final static float dw = 320f;
    private final static float dh = 480f;*/
  private final static float dw = 480f;
    private final static float dh = 320f;


    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";

    public static void main(String[] args) {
/*        makeString(320, 480);
        makeString(480, 800);
        makeString(480, 854);
        makeString(540, 960);
        makeString(600, 1024);
        makeString(720, 1184);
        makeString(720, 1196);
        makeString(720, 1280);
        makeString(768, 1024);
        makeString(800, 1280);
        makeString(1080, 1812);
        makeString(1080, 1920);
        makeString(1440, 2560);*/
        makeString(480, 320);
        makeString(800, 480);
        makeString(854, 480);
        makeString(960, 540);
        makeString(1024 ,600 );
        makeString(1184 ,720 );
        makeString(1196 ,720 );
        makeString(1280 , 720);
        makeString( 1024 ,768 );
        makeString(1280 ,800 );
        makeString( 1812 ,1080 );
        makeString(1920 ,1080 );
        makeString(2560 ,1440 );
    }

    public static void makeString(int w, int h) {

        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        sb.append("<resources>");
        float cellw = w / dw;
        for (int i = 1; i < 480; i++) {
            sb.append(WTemplate.replace("{0}", i + "").replace("{1}",
                    change(cellw * i) + ""));
        }
        sb.append(WTemplate.replace("{0}", "480").replace("{1}", w + ""));
        sb.append("</resources>");

        StringBuffer sb2 = new StringBuffer();
        sb2.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        sb2.append("<resources>");
        float cellh = h / dh;
        for (int i = 1; i < 320; i++) {
            sb2.append(HTemplate.replace("{0}", i + "").replace("{1}",
                    change(cellh * i) + ""));
        }
        sb2.append(HTemplate.replace("{0}", "320").replace("{1}", h + ""));
        sb2.append("</resources>");

        String path = rootPath.replace("{0}", w + "").replace("{1}", h + "");
        File rootFile = new File(path);
        if (!rootFile.exists()) {
            rootFile.mkdirs();
        }
        File layxFile = new File(path + "lay_x.xml");
        File layyFile = new File(path + "lay_y.xml");
        try {
            PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
            pw.print(sb.toString());
            pw.close();
            pw = new PrintWriter(new FileOutputStream(layyFile));
            pw.print(sb2.toString());
            pw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

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

}

選中java文件后右鍵荞胡,然后選擇run 'MakeXml.main()'妈踊。


image.png

將生成的文件copy至src\main\res目錄下。


image.png

image.png

又由于必須在默認values里面也創(chuàng)建對應默認lay_x.xml和lay_y.xml文件泪漂。
由于我這里以480x320為基準分辨率廊营,因此將values-480x320下的lay_x.xml和lay_y.xml中的px先全部通過notepad++替換成dp,再放到values目錄下萝勤。


image.png

在activity中增加測試textview控件大小的代碼露筒。

 mTextView.post(new Runnable() {
            @Override
            public void run() {
                int width = mTextView.getWidth();
                int height = mTextView.getHeight();
                Log.d(TAG,"width = " + width + " , height =" + height);
            }
        });

然后將TextView屬性改為如下所示。

   <TextView
        android:id="@+id/test_text_view"
        android:layout_width="@dimen/x240"
        android:layout_height="@dimen/y160"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="test" />

運行程序后纵刘,不斷通過wm size命令修改屏幕分辨率,并且運行程序荸哟。運行結果如下假哎。

07-05 17:19:06.547 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 480 , screenHeight =320
07-05 17:19:06.641 3859-3859/com.demo.myapplication D/MainActivity: width = 240 , height =160
07-05 17:19:31.083 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 480 , screenHeight =800
07-05 17:19:31.132 3859-3859/com.demo.myapplication D/MainActivity: width = 240 , height =160
07-05 17:19:31.468 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 800 , screenHeight =480
07-05 17:19:31.517 3859-3859/com.demo.myapplication D/MainActivity: width = 240 , height =160
07-05 17:20:11.736 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 854 , screenHeight =480
07-05 17:20:11.782 3859-3859/com.demo.myapplication D/MainActivity: width = 240 , height =160
07-05 17:20:26.221 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 960 , screenHeight =540
07-05 17:20:26.259 3859-3859/com.demo.myapplication D/MainActivity: width = 427 , height =240
07-05 17:20:51.721 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1024 , screenHeight =600
07-05 17:20:51.774 3859-3859/com.demo.myapplication D/MainActivity: width = 480 , height =270
07-05 17:21:23.098 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1024 , screenHeight =768
07-05 17:21:23.138 3859-3859/com.demo.myapplication D/MainActivity: width = 512 , height =300
07-05 17:21:57.911 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1184 , screenHeight =720
07-05 17:21:57.959 3859-3859/com.demo.myapplication D/MainActivity: width = 512 , height =300
07-05 17:22:36.078 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1196 , screenHeight =720
07-05 17:22:36.128 3859-3859/com.demo.myapplication D/MainActivity: width = 512 , height =300
07-05 17:22:51.951 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1280 , screenHeight =720
07-05 17:22:52.002 3859-3859/com.demo.myapplication D/MainActivity: width = 512 , height =300
07-05 17:22:59.092 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1280 , screenHeight =800
07-05 17:22:59.142 3859-3859/com.demo.myapplication D/MainActivity: width = 640 , height =360
07-05 17:23:18.623 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1812 , screenHeight =1080
07-05 17:23:18.678 3859-3859/com.demo.myapplication D/MainActivity: width = 640 , height =400
07-05 17:23:48.159 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 1920 , screenHeight =1080
07-05 17:23:48.200 3859-3859/com.demo.myapplication D/MainActivity: width = 640 , height =400
07-05 17:24:16.942 3859-3859/com.demo.myapplication D/MainActivity: screenWidth = 2560 , screenHeight =1440
07-05 17:24:16.997 3859-3859/com.demo.myapplication D/MainActivity: width = 960 , height =540

但是從運行結果上來看,效果并不理想鞍历。
screenWidth = 800 , screenHeight =480時舵抹, width = 240 , height =160。
但是我定義的values-800x480下劣砍。

values-800x480
lay_x.xml
<dimen name="x240">400.0px</dimen>
lay_y.xml
<dimen name="y160">240.0px</dimen>

按定義去工作惧蛹,結果應該是 width = 400 , height =240。這里values-800x480并沒有生效刑枝。
而且wm size 2560x1440時香嗓, width = 960 , height =540,匹配的是values-1920x1080下的dimen。

values-1920x1080
lay_x.xml
<dimen name="x240">960.0px</dimen>
lay_y.xml
<dimen name="y160">540.0px</dimen>
values-2560x1440
lay_x.xml
<dimen name="x240">1280.0px</dimen>
lay_y.xml
<dimen name="y160">720.0px</dimen>

分辨率限定符根本沒有按我的想象去工作W俺?坑椤!
后來我找到了解釋掠兄,一直以來其實都誤用了分辨率限定符像云。
詳細解釋可以看這里锌雀。
被誤用的屏幕分辨率限定符
http://www.reibang.com/p/b0253e457031

這個方案后面基本上也沒有人推薦了,基本上退出歷史舞臺了迅诬。

現(xiàn)在來看看以density為變量為例進行ui適配腋逆。這種方案最近比較火,由 字節(jié)跳動技術團隊 提出侈贷。
https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA

可以參考這個鏈接惩歉,簡單看看下效果。
Android今日頭條UI適配完善版
http://www.reibang.com/p/41930fde7aac
這個方案從豎屏測試結果上來看铐维,效果還不錯柬泽。不過橫屏仍需要另外布局。

上面介紹了屏幕分辨率和density適配ui2種方法嫁蛇,其實還有一種寫法锨并,就是把TextView嵌套進LinearLayout然后通過android:layout_weight這個屬性讓其控件大小自適應。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/colorPrimary"
                android:gravity="center"
                android:text="test" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

200x200和800x800分辨率時運行結果分別如下圖所示睬棚。


200x200
800x800

運行結果控件大小雖然效果一致,但是字體大小效果不一致抑党,可以代碼中動態(tài)調節(jié),或者去定義 不同dimens.xml 文件雕凹。
先來看看通過代碼去適配的做法殴俱。
大致思路是以200x200為基準,設置一個大小枚抵,例如12sp.
在values下新建一個dimens文件线欲。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="text_size">12sp</dimen>
</resources>

然后再獲取屏幕分辨率,例如800x800汽摹,去計算放大或縮小比例询筏,例如這里是倍數(shù)是4,通過setTextSize設置大小為48sp竖慧。

        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getRealMetrics(dm);
        int screenWidth = dm.widthPixels;
        int screenHeight = dm.heightPixels;
        Log.d(TAG,"screenWidth = " + screenWidth + " , screenHeight =" + screenHeight);

        int dimen = getResources().getDimensionPixelSize(R.dimen.text_size);
        if (screenWidth != 200){
            dimen = dimen * screenWidth/200;
            Log.d(TAG,"dimen = " + dimen);
        }
        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,dimen);

運行結果如下嫌套,字體變大了逆屡。



看完代碼中動態(tài)調節(jié)的方式,下面來看看通過定義不同dimens.xml 文件去適配的方式踱讨。
除了前面的 根據(jù) 屏幕分辨率限定符 定義 dimens魏蔗,還可以用另一種方式定義dimens,那就是 android中的 sw(smallestWidth)限定符 (這個限定符android官網(wǎng)是有介紹的)痹筛。
下面來介紹下給 smallestWidth(最小寬度) 限定符方式定義dimens.xml 文件莺治,這種方式定義dimens可以使apk體積更小。
先看看什么是smallestWidth帚稠。
android中定義了配置修飾符-sw谣旁。例如-sw600dp。

//以下部分出處:android編程權威指南
配置修飾符-sw600dp的作用是:如果設備尺寸大于某個指定值滋早,就使用對應的資源文件榄审。
sw是smallest width(最小寬度)的縮寫。雖然字面上是寬度的含義杆麸,但它實際指的是屏幕最小尺寸(dimension)搁进,因而sw與設備的當前方向無關。
在確定可選資源時昔头,-sw600dp配置修飾符表明:對任何最小尺寸為600dp或更高dp的設備饼问,都使用該資源。

在res目錄下新建values-sw800dp文件夾揭斧,再新建一個dimens文件莱革。


image.png
    <dimen name="text_size">48sp</dimen>

在TextView中增加屬性 android:textSize="@dimen/text_size",當屏幕分辨率為800x800時(這里是隨便測試用的分辨率)讹开,android會自動適配values-sw800dp下的dimens文件盅视。

 <TextView
                android:id="@+id/test_text_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/colorPrimary"
                android:gravity="center"
                android:text="test"
                android:textSize="@dimen/text_size"/>

這種最后運行結果與通過代碼去適配一致。

這種sw限定符 相對于 屏幕分辨率限定符 萧吠,所需的dimens.xml文件更少左冬,匹配度也更好一些桐筏。
因此這種sw限定符 的方法廣泛使用纸型。
但是上面的這種定義xml文件的方法,布局嵌套層級太深了梅忌,會增加渲染層次狰腌,致使性能下降。針對這種情況google為我們提供了一個百分比布局兼容庫:Android Percent Support Library牧氮。


但是后面這個方法又被廢棄了琼腔,推薦我們?nèi)ナ褂肅onstraintLayout 。

所以我們到底是為了什么一直在學習這種要被廢棄的東西踱葛?丹莲?我們一直在不停地使用輪子光坝,然后再這個過程中無數(shù)的輪子都被拋棄了。如果只會用輪子我們還剩什么甥材?
em盯另。。還是要學會思想洲赵,原理鸳惯,理論結合實踐,轉換成自己的東西叠萍。多寫文章芝发,好記性不如爛筆頭。
下面來粗略看下谷歌提供的百分比庫的簡單使用苛谷。
首先在gradle中添加依賴辅鲸。

implementation 'com.android.support:percent:28.0.0'

定義xml文件。

<android.support.percent.PercentRelativeLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:id="@+id/one"
        android:background="#f0f000"
        app:layout_heightPercent="30%"
        app:layout_widthPercent="70%"
        android:text="Hello World!"
         />
    <TextView
        android:layout_width="0dp"
        android:layout_toRightOf="@id/one"
        android:layout_height="0dp"
        app:layout_heightPercent="30%"
        app:layout_widthPercent="30%"
        android:background="#ff0000"
        android:text="Hello World!"
        />
    <TextView
          android:layout_width="0dp"
          android:layout_below="@id/one"
          android:layout_height="0dp"
          app:layout_heightPercent="70%"
          app:layout_widthPercent="100%"
          android:background="#ff00ff"
          android:text="Hello World!"
            />

</android.support.percent.PercentRelativeLayout>

預覽圖如下抄腔。



在3臺設備上運行結果如下瓢湃。


1
2
3

在橫豎屏中運行效果一致『丈撸看起來是比較理想的方法绵患。官方推了一段時間這個,但是最后還是將其廢棄悟耘,原因未知落蝙。因此隨著android系統(tǒng)的更新,后續(xù)的使用會有問題暂幼。這個是別人在使用中遇到的一些問題筏勒。

關于使用百分比布局導致布局設定失效的記錄
https://blog.csdn.net/wzgl708937822/article/details/80880492

廢棄百分比布局兼容庫后又推出了ConstraintLayout 。到今天(2019.7.8)為止使用android studio新建project都會默認生成以ConstraintLayout 為根節(jié)點的xml文件旺嬉。
思考:上面寫了多種使用方法管行,那么到底什么時候該用什么方法呢?各自的使用場景最佳使用邪媳?

先不管了捐顷,看看ConstraintLayout (約束布局)再說。
ConstraintLayout 目前為止并沒有完全代替LinearLayout 雨效、 RelatvieLayout等迅涮,并且學習成本較高,我經(jīng)歷過入門到放棄的過程徽龟。
而且屬性特別多叮姑,很容易迷失在一堆資料中,思緒亂掉据悔。應對這種情況我的解決辦法是找簡單的demo去練習(越簡單的demo越好传透,太復雜真的不容易入門耘沼,容易勸退的,這篇文章入門我覺得還可以。哲♂學三幻神帶你學習ConstraintLayout(約束布局) http://www.reibang.com/p/639fa7377cc0)朱盐,然后再自己寫一遍耕拷,再對照官方文檔查屬性。
//從寫這篇文開始到寫到這里其實已經(jīng)過了一周多了雖然字不多但是真的很難憋出來

這里可以先通過使用ConstraintLayout 代替代替常見布局LinearLayout 托享、 RelatvieLayout 骚烧、 PercentLayout等,來簡單對比他們之間的差異闰围。
先使用LinearLayout 赃绊、 RelatvieLayout實現(xiàn)如下兩種經(jīng)典布局。


image.png

首先使用LinearLayout 羡榴。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context=".MainActivity">
    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="1"
        android:gravity="center"
        android:textSize="30sp"
        android:background="#f0f000"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:text="2"
        android:gravity="center"
        android:textSize="30sp"
        android:background="#ff0000"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="3"
        android:gravity="center"
        android:textSize="30sp"
        android:background="#ff00ff"/>
</LinearLayout>
image.png

這個在一個橫屏和2個豎屏設備上顯示效果基本一致碧查。
然后再來看RelatvieLayout。
下面的xml是針對我手中分辨率為1080x1920校仑,density為3的設備去寫的忠售。
但是在分辨率為 720x1280,density為2的時候顯示效果也基本一致迄沫。
但是在橫屏上這個xml顯示效果就不太行了稻扬。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/text_view_1"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:text="1"
        android:gravity="center"
        android:textSize="30sp"
        android:background="#f0f000"/>

    <TextView
        android:id="@+id/text_view_2"
        android:layout_width="240dp"
        android:layout_height="140dp"
        android:layout_below="@id/text_view_1"
        android:text="2"
        android:gravity="center"
        android:textSize="30sp"
        android:background="#ff0000"/>
    <TextView
        android:id="@+id/text_view_3"
        android:layout_width="120dp"
        android:layout_height="140dp"
        android:layout_below="@id/text_view_1"
        android:layout_toEndOf="@id/text_view_2"
        android:text="3"
        android:gravity="center"
        android:textSize="30sp"
        android:background="#ff00ff"/>
</RelativeLayout>

運行結果如下。


豎屏
橫屏

PercentLayout這里就不用看了羊瘩,前文有寫√┘眩現(xiàn)在就來看ConstraintLayout 要怎么去寫這2種布局。
先看LinearLayout 尘吗。
首先在根目錄下寫上ConstraintLayout逝她,然后切到design界面。
選中TextView控件睬捶,拖到3個TextView下面的區(qū)域區(qū)中去黔宛。



image.png

添加2條Guideline。


image.png

選中Guideline擒贸,可以直接設置layout_constraintGuide_percent臀晃。



填0.25就是25%的位置。


image.png

或者可以選中Guideline酗宋,點擊Cycle Guideline积仗,切到百分比疆拘。


image.png
image.png

然后分別手動拖到25%和75%的地方蜕猫。


然后把最左邊的TextView控件的右邊連到25%那條Guideline,最右邊的TextView控件的左邊連到75%那條Guideline哎迄,中間的TextView控件左右分別連到25%和75%的Guideline回右,其余部分連離各自最近的邊框隆圆。


image.png

然后再設置每個TextView控件大小以及邊距。修改箭頭所示部分翔烁。


image.png

修改后如下渺氧。


image.png

然后每個都這樣改,最后為了更好區(qū)分蹬屹,給TextView加上背景色并且調大字體侣背,并且把字改成123。

最終xml文件如下所示慨默。

<android.support.constraint.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#f0f000"
        android:text="1"
        android:textSize="30sp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff0000"
        android:text="2"
        android:textSize="30sp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff00ff"
        android:text="3"
        android:textSize="30sp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline2"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.25" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.75" />
</android.support.constraint.ConstraintLayout>

在3臺設備上運行結果如下所示。

1
2

3

這個布局與LinearLayout 相比,寫的過程中沒感覺到有什么優(yōu)勢宏侍,可能勝在性能吧喳整。
為了減少代碼量,一般這種統(tǒng)一風格的屬性,可以通過定義一個style虾攻,讓TextView等控件去引用就好铡买。
在values下的styles.xml文件中,定義如下style霎箍。

    <style name="style_main_text">
        <item name="android:gravity">center</item>
        <item name="android:textSize">30sp</item>
    </style>

然后再在TextView中加上一句

style="@style/style_main_text"

再來看RelativeLayout 奇钞。
新建一個horizontal方向的Guideline,設置百分比為0.78125(500/640),一個vertical方向的Guideline漂坏,設置百分比為667(240/360)蛇券,再拖3個Textview,并且將其與Guideline連接起來樊拓。
最后xml文件如下纠亚。

<android.support.constraint.ConstraintLayout 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"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/textView1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#f0f000"
        android:text="1"
        android:textSize="30sp"
        android:gravity="center"
        app:layout_constraintBottom_toTopOf="@+id/guideline4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff0000"
        android:text="2"
        android:textSize="30sp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/guideline11"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline4" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff00ff"
        android:text="3"
        android:textSize="30sp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline11"
        app:layout_constraintTop_toTopOf="@+id/guideline4" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.78125" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline11"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.6667" />

</android.support.constraint.ConstraintLayout>

從運行結果上來看,橫豎屏效果基本一致筋夏,效果比RelativeLayout 要好蒂胞。
由此可見,ConstraintLayout使用場景上來說應該更適用于復雜布局条篷,用來代替RelativeLayout 效果還不錯骗随。
總結:ConstraintLayout+sw限定符方式應該是不錯的ui適配組合。
以上只是個人分析赴叹,具體情況具體操作鸿染。

參考鏈接:
屏幕兼容性概覽
https://developer.android.com/guide/practices/screens_support?hl=zh-CN

支持不同屏幕尺寸
https://developer.android.com/training/multiscreen/screensizes.html?hl=zh-CN#flexible-layout

Android UI 設計規(guī)范
http://www.reibang.com/p/b38e81be51ca

安卓UI圖px標注適配攻略:批量轉化px為dp
https://blog.csdn.net/zengd0/article/details/52464627

Material Design
https://material.io/design/layout/understanding-layout.html#usage

iPhone不同設備屏幕尺寸和分辨率
http://www.reibang.com/p/0bb66e4cc732

小豬淺談Android屏幕適配
https://blog.csdn.net/coder_pig/article/details/78193938

Android adb 修改手機分辨率與DPI
https://blog.csdn.net/Jumenglo/article/details/79140071

Android中的工具欄(ActionBar和ToolBar)
http://www.reibang.com/p/4df8709a76fa

Android屏幕適配之百分比布局
http://www.reibang.com/p/0c2a8db91bda

https://developer.android.com/training/constraint-layout/index.html

百分比布局支持庫
https://mrfu.me/android/2015/08/31/percent_support_library/

屏幕適配(一)--屏幕分辨率限定
http://www.reibang.com/p/8a67cd0f6ccb

一種非常好用的Android屏幕適配
http://www.reibang.com/p/1302ad5a4b04

Android 屏幕適配:最全面的解決方案
http://www.reibang.com/p/ec5a1a30694b

被誤用的屏幕分辨率限定符
http://www.reibang.com/p/b0253e457031

Android今日頭條UI適配完善版
http://www.reibang.com/p/41930fde7aac

哲♂學三幻神帶你學習ConstraintLayout(約束布局)
http://www.reibang.com/p/639fa7377cc0

[譯] ConstraintLayout深入系列之代替常見布局
https://biaomingzhong.github.io/2017/constraintlayout-layouts-common/

https://developer.android.com/reference/android/support/constraint/ConstraintLayout

ConstraintLayout使用指南
http://tinycoder.cc/2018/06/01/ConstraintLayout%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乞巧,隨后出現(xiàn)的幾起案子涨椒,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚕冬,死亡現(xiàn)場離奇詭異免猾,居然都是意外死亡,警方通過查閱死者的電腦和手機囤热,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門猎提,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旁蔼,你說我怎么就攤上這事锨苏。” “怎么了棺聊?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵蚓炬,是天一觀的道長。 經(jīng)常有香客問我躺屁,道長肯夏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任犀暑,我火速辦了婚禮驯击,結果婚禮上,老公的妹妹穿的比我還像新娘耐亏。我一直安慰自己徊都,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布广辰。 她就那樣靜靜地躺著暇矫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪择吊。 梳的紋絲不亂的頭發(fā)上李根,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音几睛,去河邊找鬼房轿。 笑死,一個胖子當著我的面吹牛所森,可吹牛的內(nèi)容都是我干的囱持。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼焕济,長吁一口氣:“原來是場噩夢啊……” “哼纷妆!你這毒婦竟也來了?” 一聲冷哼從身側響起晴弃,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤掩幢,失蹤者是張志新(化名)和其女友劉穎逊拍,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粒蜈,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年旗国,在試婚紗的時候發(fā)現(xiàn)自己被綠了枯怖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡能曾,死狀恐怖度硝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寿冕,我是刑警寧澤蕊程,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站驼唱,受9級特大地震影響藻茂,放射性物質發(fā)生泄漏。R本人自食惡果不足惜玫恳,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一辨赐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧京办,春花似錦掀序、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至财饥,卻和暖如春换吧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钥星。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工式散, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人打颤。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓暴拄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親编饺。 傳聞我的和親對象是個殘疾皇子乖篷,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容