Android ConstraintLayout - ConstraintSet 動態修改約束


ConstraintLayout熟悉的差不多了,你可以使用各種約束定位出你的框架大小位置,裡面也有很多很好用的工具,包含Guideline、bias、ratio、chain 等等 . . . ,不過今天要講的是如何動態修改約束。


作者將基於上面的APP 來進行這篇文章的論述。我有一個constraint layout ,這裡面總共有五個按鈕。

應用和重置按鈕除了應用和重置我們的動畫之外不做其他事情。另外三個按鈕被用來進行我們的動畫。我們通過應用不同的動畫來使這三個按鈕共同協作。最重要的一點,我們在開始之前應該知道這三個按鈕的constraint。
<?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <Button
            android:id="@+id/applyButton"
            android:text="Apply"
            ...
            />

        <Button
            android:id="@+id/resetButton"
            android:text="Reset"
            ...
            />

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent"
            android:text="Button 1"
            android:layout_marginLeft="52dp"
            app:layout_constraintLeft_toLeftOf="parent"
            android:layout_marginStart="52dp"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="69dp" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimaryDark"
            android:text="Button 2"
            app:layout_constraintLeft_toRightOf="@+id/button1"
            android:layout_marginLeft="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginRight="8dp"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintHorizontal_bias="0.571"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="136dp" />

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_red_dark"
            android:text="Button 3"
            android:layout_marginTop="102dp"
            app:layout_constraintTop_toBottomOf="@+id/button1"
            android:layout_marginLeft="88dp"
            app:layout_constraintLeft_toLeftOf="parent"
            android:layout_marginStart="88dp" />

    </android.support.constraint.ConstraintLayout>

在你檢查這段代碼之後你可以輕鬆地了解這三個按鈕之間的關係,下面這張圖會給你一個更直觀的認識。


public class MainActivity extends AppCompatActivity {

    private ConstraintLayout constraintLayout;
    private ConstraintSet applyConstraintSet = new ConstraintSet();
    private ConstraintSet resetConstraintSet = new ConstraintSet();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        constraintLayout = (ConstraintLayout) findViewById(R.id.main);
        resetConstraintSet.clone(constraintLayout);
        applyConstraintSet.clone(constraintLayout);
    }

    public void onApplyClick(View view) {

    }

    public void onResetClick(View view) {

    }
留意粗體字,這些代碼很簡單。ConstraintSet就是我們要在這個教程中經常用到的一個工具。簡單來說,你可以這樣理解,這個工具將記住我們在XML文件裡實現的所有的constraints。怎樣使用呢?就像你看到的,在上面的代碼裡我擁有了一個constarintLayout引用,在那之後,我將把它的constraints複製到我們的兩個變量resetConstraintSetapplyConstraintSet中。非常的簡單。

新需求:

我想要在constraint layout 裡使用Java 代碼讓按鈕1 在用戶點擊啟動按鈕的時候與父控件的左邊對齊。

解決方案:

public void onApplyClick(View view) {
    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.START,8);
    applyConstraintSet.applyTo(constraintLayout);
}

public void onResetClick(View view) {
    resetConstraintSet.applyTo(constraintLayout);
}

SetMargin() 方法將使用三個參數(viewId, anchor, margin)。
按鈕1 有52dp 的左邊距,但是當用戶點擊之後我會把間距改變到8px。是時候看下這個過程了
除了猛地一跳,沒有按鈕移動的軌跡,這看起來並不像動畫。所以我們需要重新檢查下我們的代碼。在檢查之後我發現需要在applyButton() 方法裡再加點東西。在增加了之後,得到動畫效果如下圖所示。

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);
    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.START,8);
    applyConstraintSet.applyTo(constraintLayout);
}
這裡我需要添加TransitionManager。從一個support library 裡面能夠獲取到TransistionManager
你可以添加gradle 依賴。
compile 'com.android.support:transition:25.1.0'

新需求:

當用戶點擊應用按鈕的時候,我想要讓所有的按鈕動起來並在父容器里水平居中。

解決方案:

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);
    applyConstraintSet.centerHorizontally(R.id.button1, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button2, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button3, R.id.main);
    applyConstraintSet.applyTo(constraintLayout);
}
這裡我使用centerHorizo​​ntally() 方法。這個方法需要兩個參數:

第一個:我想要進行水平居中操作的View。
第二個:父容器View。
我們給這些按鈕設置了不同的外邊距,這導致了我們點擊應用按鈕時他們將移動到中心,但是由於外邊距的設定,它們最終的位置出現了偏移。是時候解決這個問題了。
public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);

    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.START,0);
    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.END,0);
    applyConstraintSet.setMargin(R.id.button2,ConstraintSet.START,0);
    applyConstraintSet.setMargin(R.id.button2,ConstraintSet.END,0);
    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.START,0);
    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.END,0);


    applyConstraintSet.centerHorizontally(R.id.button1, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button2, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button3, R.id.main);
    applyConstraintSet.applyTo(constraintLayout);
}
這裡我把所有按鈕的左右外邊距都設置為0。

剩下的還有很多功能,很多function,等需要用到時可以看看ConstraintSet

留言

這個網誌中的熱門文章

Android - 使用 adb 安装apk

Android TextView autosizing 自動調整大小

Kotlin - 實現Android中的Parcelable