我平時項目開發必備框架html
譯爲"約束佈局", 是Google在AndroidStudio2.2引入的佈局. 在AndroidStudio 2.3直接替代了以前的Activity建立的默認佈局RelativeLayout. 能夠看到Google對其重視性.java
特色android
本文實時更新測試版最新特性git
官方文檔github
最新依賴版本bash
dependencies { compile 'com.android.support.constraint:constraint-layout:1.1.1' } 複製代碼
ConstraintLayout是至今對AndroidStudio的佈局編輯器支持最好的佈局.markdown
佈局編輯器左邊有個面板, 用於拖控件到佈局編輯器中網絡
在佈局編輯器的左邊就是所有的控件列表. 能夠經過直接拖動到佈局預覽界面來建立視圖控件. 而且不須要你手動導入依賴包.app
依次介紹:框架
順序依次
預覽圖主要顯示手機的實際效果(ConstraintLayout擁有佈局編輯器屬性, 因此存在預覽界面和實際應用不一樣的狀況), 藍圖主要清晰顯示佈局的信息
二者均可以直接編輯佈局, 看你的喜愛.
ConstraintLayout佈局屬性
這一欄是根據你選擇的ViewGroup變化的佈局屬性欄, 這裏我只介紹ConstraintLayout的佈局屬性欄, 其餘的沒什麼好介紹的一看就知道了.
依次功能:
這個相似磁鐵的圖標若是處於開啓狀態. 控件只要一拖到佈局編輯器中就會自動建立水平和垂直方向各一條約束.
該功能屬於一次性功能, 點擊一次就會自動計算而且給當前佈局編輯器中全部沒有進行約束處理的控件進行水平和垂直方向各一條約束.
ConstraintLayout能夠配合一些"輔助控件"使用
輔助線用戶是不可見的, 也沒有寬高參數(你給他設置也無效). 只是在約束佈局中作一個相對基準線而已.
<android.support.constraint.Guideline android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/guideline2" android:orientation="vertical" app:layout_constraintGuide_percent="0.41" /> 複製代碼
輔助線有三種屬性
app:layout_constraintGuide_begin="20dp" app:layout_constraintGuide_end="340dp" app:layout_constraintGuide_percent="0.055555556" 複製代碼
輔助線有水平和垂直兩種:
障礙物, 分爲垂直和水平(相似GuidLine).
使用場景:當兩個文本並排時右側有一個按鈕, 可是兩個文本可能長度都是不肯定的包裹類型. 把任何一個文本做爲按鈕的約束均可能致使按鈕覆蓋住另外一個文本內容. 這個時候就須要Barriers.
Barrier控件可使用屬性來同時約束多個控件
app:constraint_referenced_ids="tv_1,tv_2"
複製代碼
而後經過屬性指定在控件的方向
app:barrierDirection="right" 複製代碼
right和left等於垂直
bottom和top等於水平
int[] getReferencedIds() int getType() void setReferencedIds(int[] ids) void setType(int type) 複製代碼
組是Constraintlayout 1.1x版本增長的輔助工具, 目的在於同時分組控制多個控件的Visibility
屬性.
xml屬性
app:constraint_referenced_ids="tv_1,tv_2"
複製代碼
java方法
int[] getReferencedIds() void setReferencedIds(int[] ids) 複製代碼
經過以上屬性將多個控件的id填入, 就能夠同時控制多個控件的隱藏和顯示
示例:
<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="com.jiuxing.constraintlayout.MainActivity"> <TextView android:id="@+id/tv_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="64dp" android:layout_marginEnd="60dp" android:text="TextView" app:layout_constraintBottom_toTopOf="@+id/tv_1" app:layout_constraintEnd_toEndOf="parent" /> <android.support.constraint.Group android:id="@+id/group" android:layout_width="151dp" android:layout_height="126dp" android:layout_marginEnd="192dp" android:visibility="gone" android:layout_marginTop="24dp" android:background="@color/colorAccent" app:constraint_referenced_ids="tv_1,tv_2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout> 複製代碼
Tip: 設置背景顏色並不影響Group組內控件顏色. 只單單是Visibility屬性.
使用場景: 某些狀況你可能須要控制多個控件同步顯示或者隱藏, 在數據未加載成功時不少視圖不該該顯示給用戶(加載中佈局)
佔位控件; 經過不斷地setContent
來替換視圖內容;
示例:
<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="com.jiuxing.constraintlayout.MainActivity"> <android.support.constraint.Placeholder android:id="@+id/placeholder" android:layout_width="50dp" android:layout_height="50dp" android:layout_marginStart="64dp" android:layout_marginTop="48dp" app:content="@+id/iv" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/iv" android:layout_width="200dp" android:layout_height="100dp" android:src="@color/colorAccent" /> </android.support.constraint.ConstraintLayout> 複製代碼
PlaceHolder之因此強大在於同時也提供代碼設置內容id
// 設置內容視圖 View getContent() void setContentId(int id) 複製代碼
若是PlaceHolder沒有設置內容那麼一樣想顯示怎麼辦
// 設置空 void setEmptyVisibility(int visibility) int getEmptyVisibility() 複製代碼
示例:
要求在建立視圖的時候就設置好, 不然後面設置無效(例如在onCreate方法中就設置)
place.setEmptyVisibility(View.VISIBLE);
複製代碼
涉及到三個屬性
app:layout_constraintCircle="@id/btn_invoke" <!--圓心控件--> app:layout_constraintCircleRadius="100dp" <!--圓形半徑大小--> app:layout_constraintCircleAngle="80" <!--圓形的角度--> 複製代碼
示例:
<Button android:id="@+id/btn_invoke" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:onClick="invoke" android:text="執行" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> <Button android:id="@+id/btn_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="51dp" android:layout_marginTop="31dp" android:text="2" app:layout_constraintCircle="@id/btn_invoke" app:layout_constraintCircleRadius="100dp" app:layout_constraintCircleAngle="80" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> 複製代碼
效果圖:
在1.1以前若是佈局屬性是wrap_content
將沒法遵照約束, 這一問題如今能夠經過如下屬性修復了;
app:layout_constrainedWidth=」true」
複製代碼
說到Percent Dimensions就不得不說ConstraintLayout中的0dp問題,當控件設置爲0dp的時候(0dp的稱呼又叫match_constraint),默認的行爲是撐開(spread),佔滿可用空間,可是這個行爲是能夠用layout_constraintWidth_default 屬性來設置的。在 ConstraintLayout 1.0.x中,這個屬性還能夠把它設置爲wrap。而到了1.1.x,它又有了一個新的值:percent,容許咱們設置控件佔據可用空間的百分比。
下面的TextView控件將佔據剩餘寬度的50%和剩餘高度的50%。
<TextView android:id="@+id/textView6" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintHeight_default="percent" app:layout_constraintHeight_percent="0.5" app:layout_constraintWidth_default="percent" app:layout_constraintWidth_percent="0.5" /> 複製代碼
除了佈局編輯器寫佈局也應該要了解佈局的屬性, 否則有些問題你看不出來的.
該屬性並不會在Android上有任何影響, 只會影響AS的佈局編輯器座標
tools:layout_editor_absoluteY="246dp" tools:layout_editor_absoluteX="36dp" 複製代碼
佈局編輯器
真機上
一個控件有四個約束點/ 十二個約束屬性(左和右有各有兩個屬性start和end以及right和left)
約束只能是同一水平下才能相互約束, 例如左和右之間能約束, 左不能和上下約束點關聯.
約束並非相互關聯的關係. 而是
// 和父佈局關聯約束 app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" // 和其餘控件關聯約束 app:layout_constraintLeft_toRightOf="@+id/button3" app:layout_constraintRight_toLeftOf="@+id/button3" app:layout_constraintTop_toBottomOf="@id/button3" app:layout_constraintBottom_toTopOf="@id/button3" layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintEnd_toStartOf layout_constraintEnd_toEndOf 複製代碼
有些控件是包含文字內容的, 因此約束佈局的控件有一個文字基準線約束. 默認是隱藏,須要點擊開關顯示.
layout_constraintBaseline_toBaselineOf
複製代碼
注意: 使用了文字基準線對齊就不須要使用上下約束了
經過小數點(百分比)控制控件在屏幕垂直/水平的百分比位置.
注意: 只有水平位置(上下/左右約束點都添加了約束)都添加約束, 該控件才支持百分比偏移
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintVertical_bias="0.69" 複製代碼
注意: 若是是約束的ConstraintLayout, 不須要這兩個屬性也能夠設置百分比偏移
通常的邊距沒什麼好講的. 和之前同樣.
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
複製代碼
由於約束佈局控件以前的關聯性太強, 若是一個佈局隱藏(gone)就可能致使整個佈局的位置移動. 因此ConstraintLayout擁有隱藏邊距屬性
ConstraintLayout中使用Gone屬性值
根據官方圖能夠看出Constraintlayout若是控件被隱藏並不會像其餘佈局同樣座標變成0,0點. 只是margin和寬高變成0.
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
複製代碼
以上邊距屬性會根據其約束的控件是不是隱藏(invisible不算)來生效, 同時margin失效.
經過設置寬或者高中的一個爲match_constraint(0dp), 就能夠設置控件的寬高比
matc_constraint的寬或高會根據另外一邊的尺寸變化來符合比例
寬高比分兩種:
寬:高
app:layout_constraintDimensionRatio="2:1" 複製代碼
很簡單就是寬比高, 默認受約束的就是match_constraint(0dp)
的一邊.
受約束的會根據另外一邊發生尺寸比例的變化(若是是match_constraint和wrap_content時1:1比例會發生尺寸變化成正方形)
自定義
app:layout_constraintDimensionRatio="w,2:1" 複製代碼
我理解爲顛倒了比例. w即設置比例爲高比寬, h爲寬比高. 實際操做體驗吧
寬高屬性值
理論上ConstraintLayout的寬高再也不使用match_parent
這一屬性值. 取而代之的是0dp(稱爲match_constraint).
**Important: **
MATCH_PARENT
is not supported for widgets contained in aConstraintLayout
, though similar behavior can be defined by usingMATCH_CONSTRAINT
with the corresponding left/right or top/bottom constraints being set to"parent"
.
官方說明match_parent在ConstraintLayout中不被支持
match_constraint只有在水平或者垂直擁有兩條方向的約束時纔有效, 即匹配剩餘所有空間. 若是隻有水平只存在一條或者沒有約束至關於wrap_content.
示例圖:
若是你強行使用編輯器會自動幫你轉換成固定dp值, 不過若是你僅僅是約束ConstraintLayout佈局並無問題.不能理解我說的什麼本身動手試試.
兩個空間相互約束就會產生一個鎖鏈. (注意佈局編輯器中是沒法經過拖動約束點相互約束, 我認爲是bug)
只能經過多選居中的方式或者直接XML編輯.
app:layout_constraintHorizontal_chainStyle="packed" 複製代碼
連接在一塊兒主要是能夠設置不一樣的樣式達到適配父容器寬度或者高度的效果. 注: 一個鏈還有第一個控件才須要設置(chainStyle)樣式.
根據樣式有三種參數值:
官方有一張介紹圖
雖然看着有五個,實際上屬性仍是那三個. 不過有加入權重和百分比偏移. Bias是偏移, weighted是權重.
和LinearLayout的wight屬性同樣. 不過只支持spread和spread_inside有效.
layout_constraintHorizontal_weight
複製代碼
一樣能夠編輯屬性也能夠鼠標修改
wrap_content
不受約束的限制 (這一問題在ConstraintLayout1.1被解決)
app:layout_constrainedWidth=」true|false」
app:layout_constrainedHeight=」true|false」
複製代碼
須要知道的是,當咱們使用 MATCH_CONSTRAINT 時,ConstraintLayout 將不得不對控件進行 2 次測量,而測量的操做是昂貴的。
而優化器(Optimizer)的做用就是對 ConstraintLayout 進行優化,對應設置給 ConstraintLauyout 的屬性是:
可設置的值有:
在設置值時,能夠設置多個,如:
app:layout_optimizationLevel="direct|barrier|dimensions" 複製代碼
修改ConstraintLayout官方不推薦使用ConstraintLayout.LayoutParams
而是推薦使用ConstraintSet
ConstraintSet
能夠直接經過代碼建立或改變約束/改變Margin等操做, 而且都提供方法而非成員變量.
若是你想修改ConstraintLayout中任意一個控件的屬性都須要進行如下三個步驟.
步驟:
示例:
public class MainActivity extends AppCompatActivity { ConstraintSet mConstraintSet = new ConstraintSet(); // create a Constraint Set ConstraintLayout mConstraintLayout; // cache the ConstraintLayout @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.state1); Context context = this; mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main); mConstraintSet.clone(mConstraintLayout); // 克隆一個佈局到ConstraintSet } public void onClick(View view) { TransitionManager.beginDelayedTransition(mConstraintLayout); // 一行代碼添加動畫 mConstraintSet1.applyTo(mConstraintLayout); // 應用到新的佈局 } } 複製代碼
官方示例, 可是我發現我是無效.
複製一個ConstraintLayout佈局到ConstraintSet中. 後面能夠對ConstraintSet進行修改(即對複製的佈局修改).
void clone (ConstraintSet set) void clone (ConstraintLayout constraintLayout) void clone (Context context, int constraintLayoutId) 複製代碼
這僅僅指的是建立一條約束, 一個控件能夠存在n條約束. 最少兩條才能肯定位置.
須要注意的是START
和LEFT
自己是能夠並存的. 不要混用
void connect(int startID, int startSide, int endID, int endSide) void connect(int startID, int startSide, int endID, int endSide, int margin) 複製代碼
示例:
// 克隆佈局 mConstraintSet = new ConstraintSet(); mConstraintSet.clone(mBinding.root); // 用三條約束鏈接兩個控件 mConstraintSet.connect(R.id.btn_3, ConstraintSet.LEFT, R.id.btn, ConstraintSet.RIGHT, 100); mConstraintSet.connect(R.id.btn_3, ConstraintSet.TOP, R.id.btn, ConstraintSet.TOP); mConstraintSet.connect(R.id.btn_3, ConstraintSet.BOTTOM, R.id.btn, ConstraintSet.BOTTOM); // 應用佈局 mConstraintSet.applyTo(mBinding.root); 複製代碼
void centerVertically(int viewId, int toView) void centerVertically(int centerID, int topId, int topSide, int topMargin, int bottomId, int bottomSide, int bottomMargin, float bias) 複製代碼
示例: 相對父佈局垂直居中
mConstraintSet.centerVertically(R.id.btn_3, ConstraintSet.PARENT_ID);
複製代碼
相對其餘控件垂直居中
mConstraintSet.centerVertically(R.id.btn_3, R.id.btn);
複製代碼
錯誤示例: 若是你使用TOP或者BOTTOM之類的屬性, 只會貼靠頂部.. 並不會居中
mConstraintSet.centerVertically(R.id.btn_3, ConstraintSet.TOP);
複製代碼
注意若是你在第二種方法垂直居中使用了LEFT或RIGHT會致使程序中止
水平居中一樣不能使用TOP或者BOTTOM, 而且Rtl和不包含Rtl有使用上的區別
void centerHorizontally(int centerID, int leftId, int leftSide, int leftMargin, int rightId, int rightSide, int rightMargin, float bias) void centerHorizontally(int viewId, int toView) // 只能使用LEFT/RIGHT 否者Crash void centerHorizontallyRtl(int viewId, int toView) void centerHorizontallyRtl(int centerID, int startId, int startSide, int startMargin, int endId, int endSide, int endMargin, float bias) // 只能使用START/END 複製代碼
示例:
// 居中父佈局 mConstraintSet.centerHorizontallyRtl(R.id.btn_3, ConstraintSet.PARENT_ID); mConstraintSet.centerHorizontallyRtl(R.id.btn_3, R.id.btn, ConstraintSet.START, 0, R.id.btn_2, ConstraintSet.END, 0, 0.5f); 複製代碼
該方法不只支持水平居中還支持垂直居中.
void center (int centerID, int firstID, int firstSide, int firstMargin, int secondId, int secondSide, int secondMargin, float bias) 複製代碼
能夠是一個像素值尺寸或者 WRAP_CONTENT
或MATCH_CONSTRAINT
void constrainHeight (int viewId, int height) // 像素單位 void constrainWidth (int viewId, int width) 複製代碼
最大和最小寬高只在MATCH_CONSTRAINT
狀況下才有效果
void constrainMaxHeight (int viewId, int height) void constrainMinHeight (int viewId, int height) void constrainMaxWidth (int viewId, int width) void constrainMinWidth (int viewId, int width) 複製代碼
默認寬高: 即均布排列的時候寬度(例如weight模式下)
void constrainDefaultWidth (int viewId, int width) void constrainDefaultWidth (int viewId, int width) 複製代碼
建立Guideline
void create (int guidelineID, // 給建立的guideline指定id int orientation) // guidline方向 複製代碼
設置Guideline邊距
void setGuidelineEnd (int guidelineID, int margin) void setGuidelineBegin (int guidelineID, int margin) void setGuidelinePercent (int guidelineID, float ratio) 複製代碼
void createBarrier (int id, // id int direction, // 方向 int... referenced) // 組id 複製代碼
設置類型
void setBarrierType (int id, int type) 複製代碼
void clear (int viewId, int anchor) // 刪除該空間某一約束 void clear (int viewId) // 刪除該控件所有約束 複製代碼
示例: 刪除頂部約束
mConstraintSet.clear(R.id.btn, ConstraintSet.TOP);
複製代碼
void setAlpha (int viewId, float alpha) 複製代碼
旋轉中心是控件的中心
void setRotation (int viewId, float rotation) // 以控件的左上角爲中心旋轉 void setRotationX (int viewId, float rotationX) // 以控件的x軸翻轉 void setRotationY (int viewId, float rotationY) // 以控件的y軸翻轉 複製代碼
以控件爲中心, 百分比浮點數
void setScaleX (int viewId, float scaleX) // 倍數關係 void setScaleY (int viewId, float scaleY) 複製代碼
以控件中心偏移
void setTranslation (int viewId, float translationX, float translationY) void setTranslationX (int viewId, float translationX) void setTranslationY (int viewId, float translationY) void setTranslationZ (int viewId, float translationZ) // z軸偏移必須在大於21纔有效 複製代碼
void setMargin (int viewId, int anchor, int value) 複製代碼
示例:
mConstraintSet.setMargin(R.id.btn, ConstraintSet.TOP, 200); 複製代碼
若是想要百分比生效必須同時設置兩邊約束(例如左右或者上下)
void setHorizontalBias (int viewId, float bias) void setVerticalBias (int viewId, float bias) 複製代碼
將當前ConstraintSet實例中Clone的ConstraintLayout應用到一個ConstraintLayout佈局中. 因爲你是經過clone()
方法來建立的ConstraintSet因此若是不使用apply()
並不會改變clone的ConstraintLayout.
void applyTo (ConstraintLayout constraintLayout) 複製代碼
不用Clone直接加載一個XML佈局文件.
void load (Context context, int resourceId) 複製代碼
主要介紹一些多是Bug或者是我知識層面不夠的問題
若是你使用了infer Constraint會發現自動生成了不少以tools開頭的屬性, 這些屬性不用去管, 不對應用有任何影響.
tools:layout_constraintTop_creator="1" 複製代碼
主要是由於控件存在兩個左右邊距屬性(start和left或者right和end)
刪除start或者end便可. 我的認爲是bug, 已經提交給Google.(個人推薦是所有都是用START和END)
要想使用Chain兩個控件必須相互約束, 可是佈局編輯器中沒法相互約束
可是XML直接編輯或者如下方法仍是能夠相互約束的, 因此我的認爲是bug
若是出現控件不在編輯器內顯示, 請檢查編輯器屬性座標.
tools:layout_editor_absoluteX="137dp" tools:layout_editor_absoluteY="-118dp" 複製代碼