ConstraintLayout基礎(chǔ) 及動(dòng)態(tài)控件(動(dòng)畫效果)

原創(chuàng)文章隅津,轉(zhuǎn)載請(qǐng)注明出處:http://www.reibang.com/p/7888cde8292f

ConstraintLayout靜態(tài)構(gòu)建方法

ConstraintLayout的靜態(tài)構(gòu)建的方法噪矛,也就是在布局界面上對(duì)其進(jìn)行處理该窗,網(wǎng)絡(luò)上已經(jīng)有很多文章臂容,也可參考

https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout.html

簡(jiǎn)單而言使用界面對(duì)ConstraintLayout內(nèi)的控件進(jìn)行修改,就是要將控件上下左右(文字)的四個(gè)約束給定義好,直接在布局界面中進(jìn)行拖拉,并調(diào)整好控件的位置即可蹄梢。

ConstraintLayout.LayoutParams

名字很熟悉,繼承自ViewGroup.MarginLayoutParams富俄,而ViewGroup.MarginLayoutParams繼承自ViewGroup.LayoutParams禁炒。這個(gè)就比較熟悉了,在其他的Layout布局也時(shí)常使用這個(gè)來(lái)布局霍比,layoutparams用于在父布局中布局子控件幕袱,子控件利用layoutparams告訴父布局它想如何被放置在父布局中,它包含的屬性類型會(huì)根據(jù)需要為視圖組的每個(gè)子視圖定義尺寸和位置悠瞬。
尺寸的定義可以使用具體值们豌,但常用的是:wrap_content和match_parent ,對(duì)于如何使用Constraintlayoutparams中的layoutparams浅妆,可以參照其他layout的使用方法玛痊,這里沒(méi)有太多特別的地方。

ConstraintSet 約束集合

官網(wǎng)的定義狂打,這個(gè)類允許我們已編程方式定義要與ConstraintLayout一起使用的一組約束,它允許我們創(chuàng)建和保存約束混弥,并將其應(yīng)用于現(xiàn)有的ConstraintLayout中趴乡,ConstraintSet可以通過(guò)各種方式創(chuàng)建:

1. 手動(dòng)創(chuàng)建:
c = new ConstraintSet(); c.connect(...);
2. from a R.layout.*object:
 c.clone(context,R.layout.layout1);
3. from a ConstraintLayout:
c.clone(clayout);

那么我們現(xiàn)在就來(lái)創(chuàng)建一個(gè)ConstraintSet 來(lái)嘗試一下(這里出現(xiàn)了問(wèn)題对省,后面有解釋):
首先是主布局xml的代碼:

<?xml version="1.0" encoding="utf-8"?>
<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.example.zjt.myapplicationfadsgwe.MainActivity"
    android:id="@+id/contentPanel">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="0dp"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="0dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="0dp"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintVertical_bias="0.0" />

</android.support.constraint.ConstraintLayout>

效果如圖:


1380880454.jpg

代碼的邏輯很簡(jiǎn)單,就是點(diǎn)擊Button生成新的Button并將新的Button添加到主視圖中晾捏,代碼如下(注意看注釋):

public class MainActivity extends AppCompatActivity {
    private Button add;
    private ConstraintLayout constraintLayout;
    private int num;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        add=findViewById(R.id.button);
        constraintLayout=findViewById(R.id.contentPanel);
        num=0;//代表按鈕點(diǎn)擊的次數(shù)
        add.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {//點(diǎn)擊事件
                if(num==0){
                    ConstraintSet constraintSet=new ConstraintSet();//新建一個(gè)ConstraintSet
                    num++;
                    Button new1=new Button(MainActivity.this);
                    //在其中添加第一個(gè)Button
                    new1.setText("第一個(gè)BUTTON");
                    constraintLayout.addView(new1);
                    constraintSet.clone(constraintLayout);
                    constraintSet.constrainWidth(new1.getId(), ConstraintLayout.LayoutParams.WRAP_CONTENT);
                    constraintSet.constrainHeight(new1.getId(),ConstraintLayout.LayoutParams.WRAP_CONTENT);
                    constraintSet.connect(new1.getId(),ConstraintSet.END, ConstraintSet.PARENT_ID,ConstraintSet.END);
                    constraintSet.connect(new1.getId(),ConstraintSet.START, ConstraintSet.PARENT_ID,ConstraintSet.START);
                    //這個(gè)按鈕距離頂部的margin值為1000
                    constraintSet.connect(new1.getId(),ConstraintSet.TOP, ConstraintSet.PARENT_ID,ConstraintSet.TOP,1000);
                    constraintSet.connect(new1.getId(),ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID,ConstraintSet.BOTTOM);
                    constraintSet.applyTo(constraintLayout);
                }else if(num==1){
                    ConstraintSet constraintSet=new ConstraintSet();
                    num++;
                    Button new2=new Button(MainActivity.this);
                    new2.setText("第二個(gè)");
                    constraintLayout.addView(new2);
                    constraintSet.clone(constraintLayout);
                    constraintSet.constrainWidth(new2.getId(), ConstraintLayout.LayoutParams.WRAP_CONTENT);
                    constraintSet.constrainHeight(new2.getId(),ConstraintLayout.LayoutParams.WRAP_CONTENT);
                    //這個(gè)按鈕什么都沒(méi)有蒿涎,添加了四個(gè)方向的約束后默認(rèn)居中
                    constraintSet.connect(new2.getId(),ConstraintSet.END,  ConstraintSet.PARENT_ID,ConstraintSet.END);
                    constraintSet.connect(new2.getId(),ConstraintSet.START, ConstraintSet.PARENT_ID,ConstraintSet.START);
                    constraintSet.connect(new2.getId(),ConstraintSet.TOP, ConstraintSet.PARENT_ID,ConstraintSet.TOP);
                    constraintSet.connect(new2.getId(),ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID,ConstraintSet.BOTTOM);
                    constraintSet.applyTo(constraintLayout);
                }else if(num==2){
                    ConstraintSet constraintSet=new ConstraintSet();
                    num++;
                    Button new3=new Button(MainActivity.this);
                    new3.setText("3");
                    constraintLayout.addView(new3);
                    constraintSet.clone(constraintLayout);
                    constraintSet.constrainWidth(new3.getId(), ConstraintLayout.LayoutParams.WRAP_CONTENT);
                    constraintSet.constrainHeight(new3.getId(),ConstraintLayout.LayoutParams.WRAP_CONTENT);
                    constraintSet.connect(new3.getId(),ConstraintSet.END,  ConstraintSet.PARENT_ID,ConstraintSet.END);
                    constraintSet.connect(new3.getId(),ConstraintSet.START, ConstraintSet.PARENT_ID,ConstraintSet.START);
                    constraintSet.connect(new3.getId(),ConstraintSet.TOP, ConstraintSet.PARENT_ID,ConstraintSet.TOP);
                    //這個(gè)按鈕距離底部的margin值為1000
                    constraintSet.connect(new3.getId(),ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID,ConstraintSet.BOTTOM,1000);
                    constraintSet.applyTo(constraintLayout);
                }
            }
        });
    }
}

動(dòng)態(tài)添加第一個(gè)Button,效果如圖:

第一個(gè)按鈕距離頂部1000

動(dòng)態(tài)添加第二個(gè)Button惦辛,效果如圖:
第二個(gè)按鈕居中

從圖上可以看到劳秋,第二個(gè)按鈕添加后,第一個(gè)按鈕的約束將不起作用胖齐?有些疑問(wèn)玻淑,那么再添加第三個(gè)按鈕嘗試,效果如圖:
約束也被修改了

這個(gè)意思很明顯了呀伙,在添加了新的按鈕以后补履,原來(lái)的約束將不起作用,都會(huì)修改為新的約束剿另。那也就是說(shuō)connect函數(shù)在Constraint的LEFT,RIGHT(START,END),TOP,BOTTOM等4個(gè)方向分別只能使用一次箫锤,舊的約束會(huì)被新的約束覆蓋。
PS:經(jīng)同學(xué)提醒雨女,將new的button的id打印出來(lái)發(fā)現(xiàn)是一樣的谚攒,如果先給Button使用setId方法設(shè)置了不同的Id,結(jié)果就沒(méi)有問(wèn)題了氛堕。
PS:只要傳入正確的id馏臭,即使是靜態(tài)的布局中的控件,也可以通過(guò)ConstraintSet調(diào)整約束
(附加一個(gè):如何優(yōu)雅的為Java代碼中新建的控件添加id:
首先在values文件夾中建立一個(gè)xml文件岔擂,我們把它命名為m_id.xml:

2017-07-21 08-47-08屏幕截圖.png

然后如圖添加:

2017-07-21 08-48-46屏幕截圖.png

在代碼中使用setId(R.id.命名的值)位喂,就可以使用這些id了。)

ConstraintSet動(dòng)畫

動(dòng)畫是最有趣的部分乱灵,這里做的很簡(jiǎn)單塑崖,但是也意味著動(dòng)畫的擴(kuò)展性很高,這個(gè)部分值得一學(xué):
首先是布局代碼:
主界面的代碼痛倚,activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<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.example.zjt.constraintsettransition.MainActivity"
    android:id="@+id/contentPanel">


    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="動(dòng)畫"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintHorizontal_bias="0.028"
        app:layout_constraintVertical_bias="0.0" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintEnd_toStartOf="@+id/button3"
        android:layout_marginEnd="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintHorizontal_bias="0.261"
        app:layout_constraintVertical_bias="0.498" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B"
        app:layout_constraintEnd_toStartOf="@+id/button4"
        android:layout_marginEnd="52dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintVertical_bias="0.498" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="C"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp" />
</android.support.constraint.ConstraintLayout>

用來(lái)替換的界面的代碼:activity2.xml规婆,要特別注意的就是這兩個(gè)布局的對(duì)應(yīng)的id要一致,否則是無(wú)法完成動(dòng)畫效果的

<?xml version="1.0" encoding="utf-8"?>
<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.example.zjt.constraintsettransition.MainActivity"
    android:id="@+id/contentPanel">


    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="動(dòng)畫"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintHorizontal_bias="0.028"
        app:layout_constraintVertical_bias="0.0" />

    <Button
        android:id="@+id/button2"
        android:layout_width="87dp"
        android:layout_height="wrap_content"
        android:text="A"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="80dp"
        app:layout_constraintHorizontal_bias="0.501" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        android:layout_marginTop="80dp"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="C"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintTop_toBottomOf="@+id/button3"
        app:layout_constraintVertical_bias="0.376" />
</android.support.constraint.ConstraintLayout>

主程序代碼:MainActivity.java

package com.example.zjt.constraintsettransition;

import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.ConstraintSet;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.transition.TransitionManager;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    private ConstraintSet first,second;
    private ConstraintLayout firstLayout;
    private Button start;
    boolean isFirst=true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        first=new ConstraintSet();
        second=new ConstraintSet();
        firstLayout=findViewById(R.id.contentPanel);
        start=findViewById(R.id.start);

        first.clone(firstLayout);
        second.clone(this,R.layout.activity2);
        start.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onClick(View view) {
                if(isFirst){
                    isFirst=false;
                    TransitionManager.beginDelayedTransition(firstLayout);// 動(dòng)畫效果
                    second.applyTo(firstLayout);
                }else {
                    isFirst=true;
                    TransitionManager.beginDelayedTransition(firstLayout);
                    first.applyTo(firstLayout);
                }
            }
        });
    }
}

效果如圖:


index.gif

在整個(gè)ConstraintLayout的使用過(guò)程中蝉稳,遇到了很多的問(wèn)題抒蚜,問(wèn)題不在與xml界面的調(diào)整,而在于代碼中ConstraintSet的使用耘戚,最無(wú)法理解的地方在上面的例子就有嗡髓,就是生成了新的Button后原來(lái)的Button也會(huì)受到影響,這個(gè)地方如果有什么想法歡迎與我聯(lián)系收津。動(dòng)畫的擴(kuò)展性就很強(qiáng)了饿这,這里只是做一個(gè)簡(jiǎn)單的動(dòng)畫演示浊伙,實(shí)際上可以完成更多的效果,這個(gè)就需要再研究下了长捧。另外嚣鄙,ConstraintLayout還有一些問(wèn)題,就是如果使某個(gè)控件的一部分處于屏幕內(nèi)串结,一部分處于屏幕外哑子,原先使用relativelayout就很好處理了,在代碼中的Layoutparams進(jìn)行位置的處理皆可以肌割,而使用ConstraintLayout這個(gè)地方就不好完成卧蜓,目前我沒(méi)有解決辦法。(解決辦法:在使用connect函數(shù)時(shí)設(shè)置好margin即可)總的來(lái)說(shuō)声功,ConstraintLayout使得我們布局更加靈活烦却,同時(shí)也存在一些問(wèn)題,有待解決先巴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末其爵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子伸蚯,更是在濱河造成了極大的恐慌摩渺,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剂邮,死亡現(xiàn)場(chǎng)離奇詭異摇幻,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)挥萌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門绰姻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人引瀑,你說(shuō)我怎么就攤上這事狂芋。” “怎么了憨栽?”我有些...
    開(kāi)封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵帜矾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我屑柔,道長(zhǎng)屡萤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任掸宛,我火速辦了婚禮死陆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唧瘾。我一直安慰自己措译,他們只是感情好迫像,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著瞳遍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菌羽。 梳的紋絲不亂的頭發(fā)上掠械,一...
    開(kāi)封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音注祖,去河邊找鬼猾蒂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛是晨,可吹牛的內(nèi)容都是我干的肚菠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼罩缴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蚊逢!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起箫章,我...
    開(kāi)封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤烙荷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后檬寂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體终抽,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年桶至,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昼伴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镣屹,死狀恐怖圃郊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情野瘦,我是刑警寧澤描沟,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站鞭光,受9級(jí)特大地震影響吏廉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惰许,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一席覆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汹买,春花似錦佩伤、人聲如沸聊倔。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)耙蔑。三九已至,卻和暖如春孤荣,著一層夾襖步出監(jiān)牢的瞬間甸陌,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工盐股, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钱豁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓疯汁,卻偏偏與公主長(zhǎng)得像牲尺,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子幌蚊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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