ConstraintLayout: programowa zmiana ograniczeń

110

Potrzebuję pomocy ConstraintSet. Moim celem jest zmiana ograniczeń widoku w kodzie, ale nie wiem, jak to zrobić dobrze.

Mam 4 TextViewsi jeden ImageView. Muszę ustawić ImageViewograniczenia na jeden z TextViewplików s.

check_answer4 = (TextView) findViewById(R.id.check_answer4);
check_answer1 = (TextView) findViewById(R.id.check_answer1);
check_answer2 = (TextView) findViewById(R.id.check_answer2);
check_answer3 = (TextView) findViewById(R.id.check_answer3);

correct_answer_icon = (ImageView) findViewById(R.id.correct_answer_icon);

Jeśli pierwsza odpowiedź jest poprawna, muszę ustawić ograniczenia ImageViewna

app:layout_constraintRight_toRightOf="@+id/check_answer1"
app:layout_constraintTop_toTopOf="@+id/check_answer1"

Jeśli druga odpowiedź jest poprawna, muszę ustawić ograniczenia ImageViewna

app:layout_constraintRight_toRightOf="@+id/check_answer2"
app:layout_constraintTop_toTopOf="@+id/check_answer2"

I tak dalej.

Duży trener
źródło
w tym celu musisz dynamicznie zmieniać ograniczenie.
Shweta Chauhan
4
@shweta Pytam dokładnie o to, jak to zrobić dynamicznie?
Big Coach
uzyskiwanie. zamieszczając swoją odpowiedź.
Shweta Chauhan

Odpowiedzi:

185
  1. Aby ustawić ograniczenia widoku obrazu na:

     app:layout_constraintRight_toRightOf="@+id/check_answer1"
     app:layout_constraintTop_toTopOf="@+id/check_answer1"

    posługiwać się:

     ConstraintLayout constraintLayout = findViewById(R.id.parent_layout);
     ConstraintSet constraintSet = new ConstraintSet();
     constraintSet.clone(constraintLayout);
     constraintSet.connect(R.id.imageView,ConstraintSet.RIGHT,R.id.check_answer1,ConstraintSet.RIGHT,0);
     constraintSet.connect(R.id.imageView,ConstraintSet.TOP,R.id.check_answer1,ConstraintSet.TOP,0);
     constraintSet.applyTo(constraintLayout);
  2. Aby ustawić ograniczenia widoku obrazu na:

     app:layout_constraintRight_toRightOf="@+id/check_answer2"
     app:layout_constraintTop_toTopOf="@+id/check_answer2"

    posługiwać się:

     ConstraintLayout constraintLayout = findViewById(R.id.parent_layout);
     ConstraintSet constraintSet = new ConstraintSet();
     constraintSet.clone(constraintLayout); 
     constraintSet.connect(R.id.imageView,ConstraintSet.RIGHT,R.id.check_answer2,ConstraintSet.RIGHT,0);      
     constraintSet.connect(R.id.imageView,ConstraintSet.TOP,R.id.check_answer2,ConstraintSet.TOP,0);
     constraintSet.applyTo(constraintLayout);
vishakha yeolekar
źródło
3
constraintSet.clone (constraintLayout); w tym wierszu jest constraintLayout układ nadrzędny?
Reejesh PK
5
@Pang .clone(constraintLayout)co to za zmienna i skąd ją biorę?
leonheess
8
@ReejeshPK @ MiXT4PE Tak, to jest układ nadrzędny, tj.ConstraintLayout constraintLayout = findViewById(R.id.parent_layout);
Muhammad Muzammil
1
@leonheess Myślę, że to powinna być zmienna odwołująca się do twojej grupy widoku układu ograniczeń
Felix Favor Chinemerem
81

Załóżmy, że chcemy zmienić ograniczenia w czasie wykonywania, dzięki czemu przycisk1 zostanie wyrównany z przyciskiem2 po kliknięciu:

wprowadź opis obrazu tutaj

Następnie mając ten układ:

<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"
    android:id="@+id/root"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1"
        app:layout_constraintTop_toTopOf="@+id/button3"
        app:layout_constraintBottom_toBottomOf="@+id/button3"
        app:layout_constraintStart_toEndOf="@+id/button3"
        android:layout_marginStart="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="0dp" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:text="Button 2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintVertical_bias="0.5" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:text="Button 3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginStart="8dp"
        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"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintVertical_bias="0.223" />
</android.support.constraint.ConstraintLayout>

Możemy wykonać następujące czynności:


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button1.setOnClickListener {
            val params = button1.layoutParams as ConstraintLayout.LayoutParams
            params.leftToRight = button2.id
            params.topToTop = button2.id
            params.bottomToBottom = button2.id
            button1.requestLayout()
        }
    }

azizbekian
źródło
Mój przyjacielu, nie rozumiem twojego kodu .. co to jest layoutParamsi val? Czy to w ogóle Java?
leonheess
42
Proszę pana, to język programowania kotlin. Odpowiednikiem Javy będzieConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) button1.getLayoutParams();
azizbekian
1
Chyba zapomniałeś wpisać button1.layoutParams = params
sumit sonawane
1
@sumitsonawane, nie jest to potrzebne, ponieważ mutujemy tę instancję, a button1.requestLayout()następnie wykonujemy, która następnie sprawdza instancję LayoutParams, którą zmutowaliśmy.
azizbekian
2
@azizbekian, tak, dla mnie ostatecznym rozwiązaniem jest zamiana requestLayout()połączenia na setLayoutParams()i wtedy działa. Samo zmutowanie layoutParamsi zażądanie układu wydaje się nie działać.
qwertyfinger
2

W Kotlinie możesz po prostu rozszerzyć ConstraintSetklasę i dodać kilka metod, aby skorzystać z dsl w Kotlinie i stworzyć bardziej czytelny kod. Lubię to

class KotlinConstraintSet : ConstraintSet() {

    companion object {
        inline fun buildConstraintSet(block:KotlinConstraintSet.()->Unit) =
            KotlinConstraintSet().apply(block)
    }
    //add this if you plan on using the margin param in ConstraintSet.connect
    var margin: Int? = null
        get() {
            val result = field
            margin = null //reset it to work with other constraints
            return result
        }

    inline infix fun Unit.and(other: Int) = other // just to join two functions

    inline infix fun Int.topToBottomOf(bottom: Int) =
        margin?.let {
            connect(this, TOP, bottom, BOTTOM, it)
        } ?: connect(this, TOP, bottom, BOTTOM)

    inline fun margin(margin: Int) {
        this.margin = margin
    }

    inline infix fun Int.bottomToBottomOf(bottom: Int) =
        margin?.let {
            connect(this, BOTTOM, bottom, BOTTOM, it)
        } ?: connect(this, BOTTOM, bottom, BOTTOM)

    inline infix fun Int.topToTopOf(top: Int) =
        margin?.let {
            connect(this, TOP, top, TOP, it)
        } ?: connect(this, TOP, top, TOP)

    inline infix fun Int.startToEndOf(end: Int) =
        margin?.let {
            connect(this, START, end, END, it)
        } ?: connect(this, START, end, END)

            ...
    //TODO generate other functions depending on your needs

    infix fun Int.clear(constraint: Constraints) =
        when (constraint) {
            Constraints.TOP -> clear(this, TOP)
            Constraints.BOTTOM -> clear(this, BOTTOM)
            Constraints.END -> clear(this, END)
            Constraints.START -> clear(this, START)
        }

    //inline infix fun clearTopCon
    inline infix fun appliesTo(constraintLayout: ConstraintLayout) =
        applyTo(constraintLayout)

    inline infix fun clones(constraintLayout: ConstraintLayout) =
        clone(constraintLayout)

    inline fun constraint(view: Int, block: Int.() -> Unit) =
        view.apply(block)
}

enum class Constraints {
    TOP, BOTTOM, START, END //you could add other values to use with the clear fun like LEFT
}

I używaj tego w ten sposób

        buildConstraintSet {
            this clones yourConstraintLayout
            constraint(R.id.view1) {
                margin(value:Int) and this topToBottomOf R.id.view2
                margin(30) and this bottomToBottomOf ConstraintSet.PARENT_ID
            }
            constraint(R.id.view2) {
                this clear Constraints.BOTTOM
                margin(0) and this topToTopOf R.id.topGuide
            }
            constraint(R.id.view4) {
                this topToTopOf R.id.view2
                this bottomToBottomOf R.id.view3
                this startToEndOf R.id.view2
            }
            //or you could simply do
            R.id.view1 startToEndOf R.view2
            R.id.view1 toptToBottomOf R.view3
            R.id.view3 bottomtToBottomOf R.view2
            R.id.view3 clear Constraints.END

            // and finally call applyTo()
            this appliesTo yourConstraintLayout
        }
Kofi
źródło
2

Wiem, że moja odpowiedź jest bardzo późna, ale jestem pewien, że bardzo pomogłaby innym, którzy tu wpadają. Ten artykuł nie jest mój, ale wprowadziłem kilka zmian, więc powinieneś postarać się sprawdzić cały artykuł tutaj

Zestawy wiązań

Kluczem do pracy z zestawami ograniczeń w kodzie Java jest klasa ConstraintSet. Ta klasa zawiera szereg metod, które umożliwiają wykonywanie takich zadań, jak tworzenie, konfigurowanie i stosowanie ograniczeń do instancji ConstraintLayout. Ponadto bieżące ograniczenia dla instancji ConstraintLayout można skopiować do obiektu ConstraintSet i użyć do zastosowania tych samych ograniczeń do innych układów (z modyfikacjami lub bez).

Instancja ConstraintSet jest tworzona tak jak każdy inny obiekt Java:

ConstraintSet set = new ConstraintSet();

Po utworzeniu zestawu ograniczeń można wywołać metody w instancji w celu wykonania szerokiego zakresu zadań. Poniższy kod konfiguruje zestaw ograniczeń, w których lewa strona widoku przycisku jest połączona z prawą stroną widoku EditText z marginesem 70 dp:

set.connect(button1.getId(), ConstraintSet.LEFT, 
        editText1.getId(), ConstraintSet.RIGHT, 70);

Stosowanie ograniczeń do układu Po skonfigurowaniu zestawu ograniczeń należy go zastosować do instancji ConstraintLayout, zanim zacznie obowiązywać. Zestaw ograniczeń jest stosowany przez wywołanie metody applyTo (), przechodząc przez odwołanie do obiektu układu, do którego mają zostać zastosowane ustawienia:

set.applyTo(myLayout);

Jest znacznie więcej rzeczy, które możesz zrobić z ConstraintSet API, ustawiania odchylenia poziomego i pionowego, środkowania w poziomie i w pionie, manipulowania łańcuchami i wiele więcej.

Naprawdę fajna lektura.

Znowu to tylko adaptacja.

Felix Favor Chinemerem
źródło
0

Oprócz odpowiedzi Azizbekiana chciałbym zwrócić uwagę na dwie rzeczy:

  1. Jeśli lewa / prawa nie działa, spróbuj rozpocząć / zakończyć w ten sposób:

params.startToEnd = button2.id

  1. Jeśli chcesz usunąć ograniczenie, użyj flagi UNSET w następujący sposób:

params.startToEnd = ConstraintLayout.LayoutParams.UNSET

Oleg Yablokov
źródło