Android布局控件之LinearLayout詳解
創(chuàng)新互聯(lián)公司主營七臺河網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶App定制開發(fā),七臺河h5微信平臺小程序開發(fā)搭建,七臺河網(wǎng)站營銷推廣歡迎七臺河等地區(qū)企業(yè)咨詢
LinearLayout是線性布局控件,它包含的子控件將以橫向或豎向的方式排列,按照相對位置來排列所有的widgets或者其他的containers,超過邊界時,某些控件將缺失或消失。因此一個垂直列表的每一行只會有一個widget或者是container,而不管他們有多寬,而一個水平列表將會只有一個行高(高度為最高子控件的高度加上邊框高度)。LinearLayout保持其所包含的widget或者是container之間的間隔以及互相對齊(相對一個控件的右對齊、中間對齊或者左對齊)。
xml屬性
android:baselineAligned:是否允許用戶調(diào)整它內(nèi)容的基線。
android:baselineAlignedChildIndex:當(dāng)一個線性布局與另一個布局是按基線對齊的一部分,它可以指定其內(nèi)容的基線對齊方式。
android:gravity:指定如何在該對象中放置此對象的內(nèi)容(x/y坐標(biāo)值)。
android:orientation:設(shè)置它內(nèi)容的對其方向(橫向/豎向)。
gravity 這個英文單詞是重心的意思,在這里就表示??课恢玫囊馑?。
android:layout_gravity 和 android:gravity 的區(qū)別
從名字上可以看到,android:gravity是對元素本身說的,元素本身的文本顯示在什么地方靠著換個屬性設(shè)置,不過不設(shè)置默認(rèn)是在左側(cè)的。
android:layout_gravity是相對與它的父元素說的,說明元素顯示在父元素的什么位置。
比如說button:android:layout_gravity 表示按鈕在界面上的位置。 android:gravity表示button上的字在button上的位置。
可選值
這兩個屬性可選的值有:top、bottom、left、right、center_vertical、fill_vertical、center_horizontal、fill_horizontal、center、fill、clip_vertical。
而且這些屬性是可以多選的,用“|”分開。
默認(rèn)這個的值是:Gravity.LEFT
LinearLayout還支持為其包含的widget或者是container指定填充權(quán)值。好處就是允許其包含的widget或者是container可以填充屏幕上的剩余空間。這也避免了在一個大屏幕中,一串widgets或者是containers擠成一堆的情況,而是允許他們放大填充空白。剩余的空間會按這些widgets或者是containers指定的權(quán)值比例分配屏幕。默認(rèn)的 weight 值為0,表示按照widgets或者是containers實際大小來顯示,若高于0的值,則將Container剩余可用空間分割,分割大小具體取決于每一個widget或者是container的layout_weight及該權(quán)值在所有widgets或者是containers中的比例。例如,如果有三個文本框,其中兩個指定的權(quán)值為1,那么,這兩個文本框?qū)⒌缺壤胤糯?,并填滿剩余的空間,而第三個文本框不會放大,按實際大小來顯示。如果前兩個文本框的取值一個為2,一個為1,顯示第三個文本框后剩余的空間的2/3給權(quán)值為2的,1/3大小給權(quán)值為1的。也就是權(quán)值越大,重要度越大。
如果LinearLayout包含子LinearLayout,子LinearLayout之間的權(quán)值越大的,重要度則越小。如果有LinearLayout A包含LinearLayout C,D,C的權(quán)值為2,D的權(quán)值為1,則屏幕的2/3空間分給權(quán)值為1的D,1/3分給權(quán)值為2的C。在LinearLayout嵌套的情況下,子LinearLayout必須要設(shè)置權(quán)值,否則默認(rèn)的情況是未設(shè)置權(quán)值的子LinearLayout占據(jù)整個屏幕
Android常見的5個布局,我想大家一定不會陌生。LinearLayout、RelativeLayout和FrameLayout也是使用頻率較高的布局方式,做Android開發(fā)的一定使用過。
傳統(tǒng)的5種布局方式:
不過我的問題并不是問面試者如何使用這些基礎(chǔ)的布局,而是要看面試者怎么解決布局嵌套(影響性能)和屏幕適配問題。
我們都清楚Android界面的布局太復(fù)雜,嵌套層次過深,會使整個界面的測量、布局和繪制變得更復(fù)雜,對性能會造成影響。所以我們在寫Layout文件時,也要盡量避免布局的嵌套層次過深的問題。
在怎么解決問題之前,我們得有一個好方法先判斷當(dāng)前的問題情況。Android SDK工具箱中有一個叫做Hierarchy Viewer的工具,能夠在App運行時分析Layout。
注意: 在ROOT的手機,或者是安裝開發(fā)版的ROM的手機可以直接使用Hierarchy Viewer。如果沒有Root的手機(SDK 4.1及以上),需要在你的PC端添加一個環(huán)境變量“ANDROID_HVPROTO=ddm”。
下面列舉一些面試者常使用的方式。
merge merge標(biāo)簽的作用是合并UI布局,使用該標(biāo)簽?zāi)芙档蚒I布局的嵌套層次。
merge標(biāo)簽可用于兩種情況:
ViewStub ViewStub標(biāo)簽引入的布局默認(rèn)不會inflate,既不會顯示也不會占用位置。 ViewStub常用來引入那些默認(rèn)不會顯示,只在特殊情況下顯示的布局,如數(shù)據(jù)加載進(jìn)度布局、出錯提示布局等。
需要在使用時手動inflate:
ViewStub在一定的程度可以起到減少嵌套層次的作用,特別是很多時候我們的程序可能不需要走到ViewStub的界面。
include 將可復(fù)用的組件抽取出來并通過include標(biāo)簽使用,但include標(biāo)簽?zāi)軠p少布局的層次嗎?
我認(rèn)為不能。include主要解決的是相同布局的復(fù)用問題,它并不能減少布局的層次。
用RelativeLayout代替LinearLayout
很多人為了減少布局層次喜歡用RelativeLayout代替LinearLayout,不過可能達(dá)到的效果并不會很明顯。層次是減少了,但本身RelativeLayout就會比LinearLayout性能差一點。
有一些界面,比如一個圖片和一個文本的布局(ListItem常見的布局方式),可以利用TextView有drawableLeft, drawableRight等屬性,完全不需要RelativeLayout或者LinearLayout布局。
傳統(tǒng)的布局方式存在一定的缺陷,如RelativeLayout要兩次測量(measure)它的子View才能知道確切的高度;如果LinearLayout布局的子View有設(shè)置了layout_weight,那么它也需要測量兩次才能獲得布局的高度。
相對于傳統(tǒng)的布局方式,Android官方還推出了兩種新的布局方式:ConstraintLayout和FlexboxLayout。
ConstraintLayout ConstraintLayout即約束布局,在2016年由Google I/O推出。ConstraintLayout和RelativeLayout有點類似,控件之間根據(jù)依賴關(guān)系而存在,但比RelativeLayout更加靈活。創(chuàng)建大型復(fù)雜的布局仍然可以使用扁平的層級(不用嵌套View Group),說的簡單些就是,再復(fù)雜的界面也可以只有2層層次。
要使用ConstraintLayout需要在build.gradle中添加相關(guān)的support庫:
使用ConstraintLayout可以有效的解決布局嵌套過多導(dǎo)致的性能問題,官方也對其渲染性能進(jìn)行了優(yōu)化,并且ConstraintLayout支持可視化的方式編寫布局。
不過學(xué)會熟練使用ConstraintLayout會需要一點時間,但這是值得的。
FlexBoxLayout 做過前端開發(fā)(CSS方面)的同學(xué)對FlexBox一定不會陌生,最近我在做微信小程序開發(fā)時也涉及到FlexBox。FlexBox(彈性布局)是w3c在2009年提出的一種新的布局方案,解決以前那種傳統(tǒng)css的盒模型的局限性。
Google開源了FlexboxLayout布局和前端CSS FlexBox布局具有相同的功能(肯定有不一樣的地方),但已經(jīng)足夠在Android上改進(jìn)布局的構(gòu)建方式。
FlexBoxLayout可以理解成一種更高級的LinearLayout,不過比LinearLayout更加強大和靈活。如果我們使用LinearLayout布局的話,那么不同的分辨率,也許我們要重新調(diào)整布局,勢必會需要跟多的布局文件放在不同的資源目錄。而使用FlexBoxLayout來布局的話,它可以適應(yīng)各種界面的改變(所以叫響應(yīng)式布局)。
如果對前端的Flexbox不太了解的話,你還需要補一些概念,好在這些東西在網(wǎng)上很容易找到。
可能很多讀者會覺這樣的面試題是吹毛求疵,很多項目中哪有這么復(fù)雜的界面,根本就用不到這些優(yōu)化措施。
可以說厲害的人,或者叫高手,可能只是比較多在意這些細(xì)節(jié)而已。在實踐中的經(jīng)歷告訴我,很多難于解決的性能問題,并不是因為有一個影響性能的問題無法攻克,而是沒有一個明顯的制約因素,是有各種小問題一點一點堆積起來,最終積重難返。
所以,把細(xì)節(jié)做好,或者意識到細(xì)節(jié)的地方可能引發(fā)的問題,對我們解決問題是很有幫助的,不要浪費了讓你可以成長的細(xì)節(jié)。
有需要更多Android高級進(jìn)階和面試資料的朋友可以私信我獲取
例如設(shè)置一個圖片寬高 關(guān)鍵代碼:
//取控件當(dāng)前的布局參數(shù)
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imageView.getLayoutParams();
//設(shè)置寬度值
params.width = dip2px(MainActivity.this, width);
//設(shè)置高度值
params.height = dip2px(MainActivity.this, height);
//使設(shè)置好的布局參數(shù)應(yīng)用到控件
imageView.setLayoutParams(params);
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
高度除了可以設(shè)置成以上固定的值,也可以設(shè)置成wrap_content或match_content
ViewGroup.LayoutParams.WRAP_CONTENT
ViewGroup.LayoutParams.MATCH_PARENT
1
2
1
2
在這里插入圖片描述
xml
1 .FrameLayout簡介
設(shè)計FrameLayout是為了顯示單一項widget。通常,不建議使用FrameLayout顯示多項內(nèi)容;因為它們的布局很難調(diào)節(jié)。不用layout_gravity屬性的話,多項內(nèi)容會重疊;使用layout_gravity的話,能設(shè)置不同的位置。layout_gravity可以使用如下取值:
top :將對象放在其容器的頂部,不改變其大小.
bottom:將對象放在其容器的底部,不改變其大小.
left:將對象放在其容器的左側(cè),不改變其大小.
right:將對象放在其容器的右側(cè),不改變其大小.
center_vertical:將對象縱向居中,不改變其大小.
垂直對齊方式:垂直方向上居中對齊。
fill_vertical:必要的時候增加對象的縱向大小,以完全充滿其容器.?
垂直方向填充
center_horizontal:將對象橫向居中,不改變其大小.?
水平對齊方式:水平方向上居中對齊
fill_horizontal:必要的時候增加對象的橫向大小,以完全充滿其容器.?
水平方向填充:center
將對象橫縱居中,不改變其大小.
fill:必要的時候增加對象的橫縱向大小,以完全充滿其容器.
clip_vertical:附加選項,用于按照容器的邊來剪切對象的頂部和/或底部的內(nèi)容. 剪切基于其縱向?qū)R設(shè)置:頂部對齊時,剪切底部;底部對齊時剪切頂部;除此之外剪切頂部和底部.
垂直方向裁剪
clip_horizontal
附加選項,用于按照容器的邊來剪切對象的左側(cè)和/或右側(cè)的內(nèi)容. 剪切基于其橫向?qū)R設(shè)置:左側(cè)對齊時,剪切右側(cè);右側(cè)對齊時剪切左側(cè);除此之外剪切左側(cè)和右側(cè).
水平方向裁剪
注意:?區(qū)分“android:gravity”和“android:layout_gravity”。
android:gravity ? :是對控件本身來說的,是用來設(shè)置“控件自身的內(nèi)容”應(yīng)該顯示在“控件自身體積”的什么位置,默認(rèn)值是左側(cè)。
android:layout_gravity :是相對于控件的父元素來說的,設(shè)置該控件在它的父元素的什么位置
2. FrameLayout示例
創(chuàng)建一個activity,包含2組FrameLayout:1組設(shè)置android:layout_gravity屬性,另1組不設(shè)置android:layout_gravity屬性。
layout文件
?xml version="1.0" encoding="utf-8"?
LinearLayout xmlns:android=""
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
!-- 示例1 FrameLayout內(nèi)容重疊 --
TextView
? ? android:text="示例1, FrameLayout內(nèi)容重疊"
? ? android:layout_width="wrap_content"
? ? android:layout_height="wrap_content"
? ? /
FrameLayout
? ? android:layout_width="300dp"
? ? android:layout_height="80dp"
? ? TextView
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:text="我是TextView,內(nèi)容比較長"
? ? ? ? android:background="#ff0000"/
? ? Button
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:background="#ffff00"
? ? ? ? android:text="我是按鈕"/
/FrameLayout
!-- 示例2 FrameLayout使用layout_gravity屬性 --
TextView
? ? android:text="示例2, 設(shè)置layout_gravity"
? ? android:layout_width="wrap_content"
? ? android:layout_height="wrap_content"
? ? /
FrameLayout
? ? android:layout_width="300dp"
? ? android:layout_height="120dp"
? ? TextView
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:text="文本居左"
? ? ? ? android:background="#ff0000"
? ? ? ? android:gravity="center"
? ? ? ? android:layout_gravity="left"
? ? ? ? android:layout_margin="10dp"/
? ? TextView
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:text="文本居中"
? ? ? ? android:background="#ffff00"
? ? ? ? android:gravity="center"
? ? ? ? android:layout_gravity="center"/
/FrameLayout
/LinearLayout
在線性布局LinearLayout里加入view比較簡單,因為屬性比較少,布局簡單
示例,加入一個TextView
LinearLayout?layout?=?(LinearLayout)findViewById(R.id.layout);
TextView?tv?=?new?TextView(this);
tv.setText("hello,world");
LayoutParams?lp?=?new?LayoutParams(LayoutParams.WRAP_CONTENT,?LayoutParams.WRAP_CONTENT);
layout.addView(tv,lp);
在相對布局中RelativeLayout中加入view,屬性較多
示例,加入TextView和Button,讓TextView居中,并且設(shè)置Button在TextView的下方
RelativeLayout?layout;
TextView?tv?=?new?TextView(this);
tv.setText("hello,world");
Button?btn?=?new?Button(this);
btn.setText("button");
tv.setId(0x011);
btn.setId(0x012);
LayoutParams?tvLp?=?new?LayoutParams(LayoutParams.WRAP_CONTENT,?LayoutParams.WRAP_CONTENT);
LayoutParams?btnLp?=?new?LayoutParams(LayoutParams.WRAP_CONTENT,?LayoutParams.WRAP_CONTENT);
//添加布局規(guī)則,居中于父類
tvLp.addRule(RelativeLayout.CENTER_IN_PARENT,RelativeLayout.TRUE);
//添加布局規(guī)則,在tv的下方
btnLp.addRule(RelativeLayout.BELOW,?tv.getId());
layout.addView(tv,tvLp);
layout.addView(btn,btnLp);
public void addRule(int verb, int anchor) 方法就是給view設(shè)定布局規(guī)則,verb是規(guī)則屬性,就是xml文件中的各種屬性值,anchor是依靠的view的id或者比如上面的RelativeLayout.CENTER_IN_PARENT的時候就是設(shè)置true或false