作為一個開發(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)格線攘轩。
這里只是簡單畫一畫,并不是很精準码俩。但是在畫圖的過程中加深了對px以及ui設計的了解。專業(yè)的畫圖工具功能會更全,但是一般都收費笨篷。
首先瞳秽,這張圖上的單位都是px,因為圖片設計基本單位是px率翅,要如何把px換成dp呢练俐?
以下部分出處:
安卓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計算公式如下圖。
由于示例圖片在設計的時候是適配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)泡挺。
然后重新調整大小至800 x 800 px,擴大4倍命浴。
此時,正方形寬度變成了400px 贱除,中心坐標(400,400)生闲,左上角坐標(200,200),右下角坐標(600月幌,600)碍讯。隨著圖片大小放大,正方形大小也放大了扯躺。不同分辨率中捉兴,正方形的寬度不一致(可以把正方形想象成如TextView、Button之類的控件)录语。
在有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()'妈踊。
將生成的文件copy至src\main\res目錄下。
又由于必須在默認values里面也創(chuàng)建對應默認lay_x.xml和lay_y.xml文件泪漂。
由于我這里以480x320為基準分辨率廊营,因此將values-480x320下的lay_x.xml和lay_y.xml中的px先全部通過notepad++替換成dp,再放到values目錄下萝勤。
在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分辨率時運行結果分別如下圖所示睬棚。
運行結果控件大小雖然效果一致,但是字體大小效果不一致抑党,可以代碼中動態(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文件莱革。
<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臺設備上運行結果如下瓢湃。
在橫豎屏中運行效果一致『丈撸看起來是比較理想的方法绵患。官方推了一段時間這個,但是最后還是將其廢棄悟耘,原因未知落蝙。因此隨著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)典布局。
首先使用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>
這個在一個橫屏和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ū)中去黔宛。
添加2條Guideline。
選中Guideline擒贸,可以直接設置layout_constraintGuide_percent臀晃。
填0.25就是25%的位置。
或者可以選中Guideline酗宋,點擊Cycle Guideline积仗,切到百分比疆拘。
然后分別手動拖到25%和75%的地方蜕猫。
然后把最左邊的TextView控件的右邊連到25%那條Guideline,最右邊的TextView控件的左邊連到75%那條Guideline哎迄,中間的TextView控件左右分別連到25%和75%的Guideline回右,其余部分連離各自最近的邊框隆圆。
然后再設置每個TextView控件大小以及邊距。修改箭頭所示部分翔烁。
修改后如下渺氧。
然后每個都這樣改,最后為了更好區(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臺設備上運行結果如下所示。
這個布局與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/