ConstraintLayout: modifier les contraintes par programme

110

J'ai besoin d'aide avec ConstraintSet. Mon objectif est de modifier les contraintes de la vue dans le code, mais je ne sais pas comment faire cela correctement.

J'ai 4 TextViews et un ImageView. J'ai besoin de fixer des ImageViewcontraintes à l'un des TextViews.

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);

Si la première réponse est correcte, je dois définir des contraintes de ImageViewà

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

Si la deuxième réponse est correcte, je dois définir des contraintes de ImageViewà

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

Etc.

Grand entraîneur
la source
pour cela, vous devez changer la contrainte de manière dynamique.
Shweta Chauhan
3
@shweta Je demande exactement à ce sujet, comment le faire de manière dynamique?
Big Coach
obtenir. poster votre réponse.
Shweta Chauhan

Réponses:

185
  1. Pour définir les contraintes de la vue d'image sur:

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

    utilisation:

     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. Pour définir les contraintes de la vue d'image sur:

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

    utilisation:

     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
la source
3
constraintSet.clone (constraintLayout); dans cette ligne, constraintLayout est-il la mise en page parent?
Reejesh PK
5
@Pang .clone(constraintLayout)quelle est cette variable et d'où puis-je l'obtenir?
leonheess
8
@ReejeshPK @ MiXT4PE Oui, c'est la mise en page parent, c'est à direConstraintLayout constraintLayout = findViewById(R.id.parent_layout);
Muhammad Muzammil
1
@leonheess Je pense que cela devrait être une variable référençant votre mise en page de contraintes ViewGroup
Felix Favor Chinemerem
81

Supposons que nous souhaitons modifier les contraintes pendant l'exécution, en alignant button1 sur button2 lorsque vous cliquez dessus:

entrez la description de l'image ici

Ensuite, ayant cette disposition:

<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>

Nous pouvons faire ce qui suit:


    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()
        }
    }

azizbek
la source
Mon ami, je ne reçois pas votre code .. qu'est-ce que layoutParamset val? Est-ce même Java?
leonheess
42
Monsieur, c'est le langage de programmation Kotlin. L'équivalent Java seraConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) button1.getLayoutParams();
azizbekian
1
Je pense que vous avez oublié d'écrire button1.layoutParams = params
sumit sonawane
1
@sumitsonawane, ce n'est pas nécessaire, car nous mutons cette instance et après cela, nous effectuons button1.requestLayout()ce qui inspectera l'instance de LayoutParamscelle que nous avons mutée.
azizbekian
2
@azizbekian, oui, pour moi, la solution finale consiste à remplacer l' requestLayout()appel par setLayoutParams(), puis cela fonctionne. Le simple fait de muter layoutParamset de demander la mise en page moi-même ne semble pas faire l'affaire.
qwertyfinger
2

Dans Kotlin, vous pouvez simplement étendre la ConstraintSetclasse et ajouter des méthodes pour tirer parti de dsl dans Kotlin et produire un code plus lisible. Comme ça

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
}

Et utilisez-le comme ça

        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
la source
2

Je sais que ma réponse est très tardive, mais je suis sûr que cela aiderait les autres qui s'arrêtent beaucoup ici. Cet article n'est pas le mien mais j'ai apporté quelques modifications, cela étant dit, vous devriez essayer de consulter l'article complet ici

Ensembles de contraintes

La clé pour travailler avec des jeux de contraintes dans le code Java est la classe ConstraintSet. Cette classe contient une gamme de méthodes qui permettent des tâches telles que la création, la configuration et l'application de contraintes à une instance de ConstraintLayout. De plus, les contraintes actuelles d'une occurrence de ConstraintLayout peuvent être copiées dans un objet ConstraintSet et utilisées pour appliquer les mêmes contraintes à d'autres présentations (avec ou sans modifications).

Une instance de ConstraintSet est créée comme tout autre objet Java:

ConstraintSet set = new ConstraintSet();

Une fois qu'un jeu de contraintes a été créé, des méthodes peuvent être appelées sur l'instance pour effectuer un large éventail de tâches. Le code suivant configure un jeu de contraintes dans lequel le côté gauche d'une vue Button est connecté au côté droit d'une vue EditText avec une marge de 70dp:

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

Application de contraintes à une présentation Une fois le jeu de contraintes configuré, il doit être appliqué à une instance de ConstraintLayout avant qu'il ne prenne effet. Un jeu de contraintes est appliqué via un appel à la méthode applyTo (), en passant par une référence à l'objet de mise en page auquel les paramètres doivent être appliqués:

set.applyTo(myLayout);

Il y a beaucoup plus de choses que vous pouvez faire avec le ConstraintSet API, définir un biais horizontal et vertical, centrer horizontalement et verticalement, manipuler des chaînes et bien plus encore.

Très bonne lecture.

Encore une fois, ce n'est qu'une adaptation.

Felix Favor Chinemerem
la source
0

En plus de la réponse d' Azizbekian , permettez-moi de souligner deux choses:

  1. Si gauche / droite ne fonctionnait pas, essayez de démarrer / terminer comme ceci:

params.startToEnd = button2.id

  1. Si vous souhaitez supprimer une contrainte, utilisez l'indicateur UNSET comme ceci:

params.startToEnd = ConstraintLayout.LayoutParams.UNSET

Oleg Yablokov
la source