在學習控件的使用之前,瞭解下佈局的相關知識是十分必要的。今天就來看看ConstraintLayout佈局。
ConstraintLayout是Android Studio 2.2中主要的新增功能之一,ConstraintLayout是使用可視化的方式來編寫界面。它的出現主要是爲了解決佈局嵌套過多的問題,以靈活的方式定位和調整小部件。
約束佈局ConstraintLayout 是一個ViewGroup,可以在Api9以上的Android系統使用。ConstraintLayout是採用約束的方式來指定各個控件的位置和關係的。
關鍵聽說阿里都讓使用這玩意。。。。。。
在項目中使用ConstraintLayout
首先,我們的確認在我們項目的build.gradle文件中是否添加了google存儲倉庫,對於使用高一點版本的Android Studio來說這一點不需要擔心。。
下一步在我們app的build.gradle文件中添加ConstraintLayout依賴,這一步新一點的版本我們也不需要去手動添加。。。不放心的可以確認下。
現在ConstraintLayout在我們創建佈局文件的時候已經是默認的佈局了。可想這些事我們都不需要操心了。
如果上面兩個你檢查完了,發現得自己添加的話,那麼再多做一件事情吧。
點解"Sync Project with Gradle Files"進行一下同步吧.
好了,新建一個空的Activity,並勾選生成佈局文件選項,看看出來的佈局文件:
編寫佈局可以拖也可以寫,這裏選擇手寫xml佈局文件。習慣了還是覺得寫的來的快,勿噴。。。
使用相對定位(Relative positioning)
相對定位是我們在ConstraintLayout佈局中很基礎的一種使用姿勢了,使用相對定位允許我們將給定的控件相對於另一個控件進行定位。常見的使用姿勢是:控件給定一側限制爲任何其他控件的另一側。
看個示意圖:
那麼該如何設置呢?
語法格式示例: app:layout_constraintLeft_toRightOf="控件id"
如果目標控件爲父控件則id可以直接寫成parent,否則寫控件的id。
在上面的佈局文件中添加一個Button,不做任何佈局約束。
可用的約束:
layout_constraintLeft_toLeftOf
: 當前控件的Left在目標控件的Left上
layout_constraintLeft_toRightOf
: 當前控件的Left在目標控件的Right上
layout_constraintRight_toLeftOf
: 當前控件的Right在目標控件的Left上
layout_constraintRight_toRightOf
: 當前控件的Right在目標控件的Right上
layout_constraintTop_toTopOf
: 當前控件的Top在目標控件的Top上
layout_constraintTop_toBottomOf
: 當前控件的Top在目標控件的Bottom上
layout_constraintBottom_toTopOf
: 當前控件的Bottom在目標控件的Top上
layout_constraintBottom_toBottomOf
: 當前控件的Bottom在目標控件的Bottom上
layout_constraintBaseline_toBaselineOf
:當前控件的Baseline在目標控件的Baseline上
layout_constraintStart_toEndOf
: 當前控件的Start在目標控件的End上
layout_constraintStart_toStartOf
: 當前控件的Star在目標控件的Star上
layout_constraintEnd_toStartOf
: 當前控件的End在目標控件的Start上
layout_constraintEnd_toEndOf
: 當前控件的End在目標控件的End上
上下左右就不多說了,都明白啥意思,start和end這裏給張示意圖大家腦部一下:
首先我們添加一個Button,讓其位於屏幕中央位置:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="屏幕居中">
</Button>
當然我們也可以使用left,right來實現水平居方向的約束:
`
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="屏幕居中">
</Button>
在添加兩個Button:
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn1"
app:layout_constraintBottom_toTopOf="@+id/btn1"
android:text="按鈕2">
</Button>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toLeftOf="@+id/btn1"
app:layout_constraintTop_toBottomOf="@+id/btn1"
android:text="按鈕3">
</Button>
使用Margins
可用列表:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
我們修改下佈局文件:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="50dp"
android:layout_marginRight="50dp"
android:layout_marginBottom="100dp"
android:text="按鈕1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
注意:margin屬性需要配合約束來設置,比如你設置了左邊的約束,那麼你就可以使用android:layout_marginStart和android:layout_marginLeft,否則不會生效。
看個例子:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="50dp"
android:text="按鈕1"
app:layout_constraintEnd_toStartOf="@+id/btn2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
></Button>
<Button
android:id="@+id/btn2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_marginRight="20dp"
android:text="按鈕2"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
運行結果:
這裏去掉右邊和btn2的約束,大家再看下效果:
//app:layout_constraintEnd_toStartOf="@+id/btn2"
總之就是一句話,控件和誰有約束,在哪個方向的約束那麼就可以在哪個方向設置Margin。
這裏還有一種情況,那就是我們添加約束的目標控件在某些場合需要隱藏(即設置屬性爲GONE)的時候,我們可指定控件相對於其他控件的邊距。此時需要使用下面的屬性:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
看個例子:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕2"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginLeft="20dp"></Button>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕3"
app:layout_constraintStart_toEndOf="@id/btn2"
app:layout_constraintTop_toTopOf="parent"></Button>
這裏擺放了三個在一行的按鈕:
將按鈕1的visibility設置爲gone
android:visibility="gone"
此時按鈕2左邊的約束就相對於是parent了,那麼此時按鈕2應該距離左邊20dp:
當然了,實際的使用比這複雜的多, 這裏只希望通過這樣的例子能大概明白是怎麼用的,到了實際使用的時候能夠快速入手。
Bias
首先我們看個例子:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"></Button>
有如上設置的button,那麼這個button到底是怎麼在屏幕顯示的呢?
我剛開始以爲是這個樣子的:
我們想一下start與parent左側對其,end與parent右側對其,那不是相當於設置爲match_parent嗎?可實際上我們給按鈕的寬度設定是wrap_content,也就是說button是沒有辦法向兩邊撐開的。顯然這個猜測是不正確的。
那麼如果我們把layout_width設爲0dp,是不是就能 達到這樣的效果呢?驗證之後發現果然是的。
官方文檔的解釋是:當給控件在水平方向添加相反的約束(當然了是針對同一個target)時,constraintlayout佈局會將控件顯示在target寬度的中間。就像兩個相反的力一樣,使控件兩邊的空白相同。
對於上面的例子來說,就是將按鈕1居中顯示:
遇到上面的情況,我們可能希望按鈕靠左邊顯示,此時我們就需要藉助Bias屬性來進行控制。
可選值:
layout_constraintHorizontal_bias
//水平方向偏移
layout_constraintVertical_bias// 垂直方向偏移
這兩個值得取值範圍時:0 ~ 1,默認爲0.5,即居中。不在這個範圍的話,在屏幕中無法顯示出來。
爲按鈕1添加水平方向的偏移,方向時從左到右。
app:layout_constraintHorizontal_bias="0"
將值設置爲0,意味着我們的控件將在水平方向的左邊開始位置開始顯示。
那麼設置爲1的時候,自然就在最右邊了。
設置爲0.3:
垂直方向就不再演示了,效果一樣的。
Circular positioning
這個該怎麼翻譯呢,直譯的話就是圓形定位。官方給出的解釋大概意思是這樣的;
我們可以相對於一個控件的中心位置,以一定的角度和半徑來約束目標控件的中心位置。
所以我還是將之稱呼爲圓心定位算了,不喜勿怪,英語水平有限。。。
看張示意圖:
簡單來說就是使用圓心定位進行約束,那麼目標控件的中心點一定在以該控件中心,半徑爲n的圓角度爲m的位置處。
可用屬性:
layout_constraintCircle :
目標控件id
layout_constraintCircleRadius :圓半徑
layout_constraintCircleAngle :角度 (取值: 0 ~ 360)
看個實例:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕1"
app:layout_constraintCircle="@+id/btn1"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="100dp" />
這裏我們指定半徑爲100dp,然後角度爲90度,也就是和按鈕1的中心點平齊。
Dimensions constraints
尺寸約束,這裏針對的是對ConstraintLayout佈局本身,注意:這些最小和最大尺寸將在ConstraintLayout的尺寸設置爲WRAP_CONTENT時使用。
可用參數;
android:minWidth
android:minHeight
android:maxWidth
android:maxHeight
看個例子:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="@color/colorPrimaryDark"
tools:context=".QConstraintLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:minWidth="200dp"
android:minHeight="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorPrimaryDark"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
實際上這些屬性在將尺寸設置爲match_parent的時候同樣可用,不過存在佈局顯示差異,有興趣的朋友可以試試。
Widgets dimension constraints:控件尺寸約束
我們可通過以下3種不同方式設置android:layout_width和android:layout_height屬性值指定控件的尺寸。
使用指定數值
使用wrap_content
使用0dp,相當於match_constraint
不建議對ConstraintLayout中包含的控件使用MATCH_PARENT。
如果我們在指定 wrap_content屬性的情況下,還想對控件進行特別的約束,那麼可以使用下面的屬性進行設置:
app:layout_constrainedWidth=”true|false”
app:layout_constrainedHeight=”true|false”
這裏在說一下當設置layout_width或者layout_height爲0dp的時候,默認行爲是使結果大小佔用所有可用空間。注意只有兩邊都存在約束的時候才能看到效果哦。
示例:
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:text="測試1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="測試22"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
運行效果:
如果我們去掉右邊的約束:
app:layout_constraintEnd_toEndOf="parent"
看到這裏大家應該清楚該怎麼用了吧。。。要想有效果至少我的有一個寬度和高度讓我去適應吧。。
Ratio
簡單點就是百分比佈局。
使用前提是:ayout_width或者layout_height至少有一個設置爲0dp。
屬性:
layout_constraintDimensionRatio
可選值:
浮點值,表示寬度和高度之間的比率
“寬度:高度”形式的比率,添加H約束高度,添加W約束寬度。
示例:
<Button
android:id="@+id/btn1"
android:layout_width="150dp"
android:layout_height="0dp"
android:background="@color/colorPrimaryDark"
android:text="測試1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:3"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn2"
android:layout_width="150dp"
android:layout_height="0dp"
android:background="@color/colorAccent"
android:text="測試22"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:3"
app:layout_constraintTop_toTopOf="@+id/btn1" />
效果圖:
Chains
在橫軸或或者豎軸上的控件相互約束時,可以組成一個鏈式約束。鏈在單個軸(水平或垂直)上提供類似行的行爲。另一個軸可以獨立約束。
如果一組控件通過雙向連接鏈接在一起,則它們被視爲鏈。鏈由鏈的第一個元素(鏈的“頭部”)上設置的屬性控制.鏈頭是水平鏈的最左側控件,垂直鏈的最頂部控件。
可用屬性:
app:layout_constraintHorizontal_chainStyle
app:layout_constraintVertical_chainStyle
可選值:
spread模式:元素將展開(默認樣式);
spread_inside模式: 類似spread模式,但鏈的端點不會分散;
含有權重spread模式:如果設置了某個或某些控件MATCH_CONSTRAINT(0dp),這個或這些控件將分割可用空間;
packed模式:鏈條的元素將被包裝在一起。然後,子項的水平或垂直偏差屬性將影響打包元素的定位;
下圖是各種取值的表現形式。
具體示例就貼出來了。