ConstraintLayout: ubah batasan secara terprogram

110

Saya butuh bantuan ConstraintSet. Tujuan saya adalah mengubah batasan tampilan dalam kode, tetapi saya tidak tahu cara melakukannya dengan benar.

Saya memiliki 4 TextViews dan satu ImageView. Saya perlu menetapkan ImageViewbatasan ke salah satu 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);

Jika jawaban pertama benar, saya perlu menyetel batasan ImageViewmenjadi

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

Jika jawaban kedua benar, saya perlu menetapkan batasan ImageViewmenjadi

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

Dan seterusnya.

Pelatih Besar
sumber
untuk ini, Anda harus mengubah batasan secara dinamis.
Shweta Chauhan
3
@shweta Saya bertanya persis tentang ini, bagaimana melakukannya secara dinamis?
Pelatih Besar
mendapatkan. memposting jawaban Anda.
Shweta Chauhan

Jawaban:

185
  1. Untuk menyetel batasan tampilan gambar ke:

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

    menggunakan:

     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. Untuk menyetel batasan tampilan gambar ke:

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

    menggunakan:

     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
sumber
3
constraintSet.clone (constraintLayout); di baris ini, apakah constraintLayout adalah tata letak induk?
Reejesh PK
5
@Pang .clone(constraintLayout)apa variabel ini dan dari mana saya mendapatkannya?
leonheess
8
@ReejeshPK @ MiXT4PE Ya itu ADALAH tata letak induk, yaituConstraintLayout constraintLayout = findViewById(R.id.parent_layout);
Muhammad Muzammil
1
@leonheess Saya pikir itu harus menjadi variabel yang mereferensikan Constraint Layout ViewGroup Anda
Felix Favor Chinemerem
81

Asumsikan kita ingin mengubah batasan selama runtime, membuat tombol1 menjadi sejajar dengan tombol2 saat diklik:

masukkan deskripsi gambar di sini

Kemudian, memiliki tata letak ini:

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

Kami dapat melakukan berikut ini:


    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
sumber
Teman saya, saya tidak mendapatkan kode Anda .. apa layoutParamsdan val? Apakah ini Java?
leonheess
42
Pak, itu bahasa pemrograman kotlin. Setara dengan Jawa akanConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) button1.getLayoutParams();
azizbekian
1
Saya pikir Anda lupa menulis button1.layoutParams = params
sumit sonawane
1
@sumitsonawane, tidak perlu, karena kita mutasi instance itu dan setelah itu kita lakukan button1.requestLayout()yang kemudian akan memeriksa instance LayoutParamsyang sudah kita mutasi.
azizbekian
2
@azizbekian, ya, bagi saya solusi terakhir adalah mengganti requestLayout()panggilan dengan setLayoutParams()dan kemudian berhasil. Cukup bermutasi layoutParamsdan meminta tata letak sendiri sepertinya tidak berhasil.
qwertyfinger
2

Di Kotlin, Anda cukup memperluas ConstraintSetkelas dan menambahkan beberapa metode untuk memanfaatkan dsl di Kotlin dan menghasilkan kode yang lebih mudah dibaca. Seperti ini

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
}

Dan gunakan seperti ini

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

Saya tahu jawaban saya sangat terlambat, namun saya yakin itu akan membantu orang lain yang sering mampir di sini. Artikel ini bukan milik saya tetapi saya membuat beberapa perubahan, karena itu, Anda harus berusaha untuk melihat artikel lengkap di sini

Set Batasan

Kunci untuk bekerja dengan kumpulan batasan dalam kode Java adalah kelas ConstraintSet. Kelas ini berisi berbagai metode yang memungkinkan tugas-tugas seperti membuat, mengonfigurasi, dan menerapkan batasan ke instance ConstraintLayout. Selain itu, batasan saat ini untuk instance ConstraintLayout dapat disalin ke dalam objek ConstraintSet dan digunakan untuk menerapkan batasan yang sama ke tata letak lain (dengan atau tanpa modifikasi).

Instance ConstraintSet dibuat seperti objek Java lainnya:

ConstraintSet set = new ConstraintSet();

Setelah kumpulan batasan dibuat, metode dapat dipanggil pada instance untuk melakukan berbagai tugas. Kode berikut mengonfigurasi kumpulan batasan di mana sisi kiri tampilan Tombol terhubung ke sisi kanan tampilan EditText dengan margin 70dp:

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

Menerapkan Batasan ke Layout Setelah set pembatas dikonfigurasi, itu harus diterapkan ke instance ConstraintLayout sebelum diterapkan. Satu set batasan diterapkan melalui panggilan ke metode applyTo (), meneruskan referensi ke objek layout yang setelannya akan diterapkan:

set.applyTo(myLayout);

Ada lebih banyak hal yang dapat Anda lakukan dengan file ConstraintSet API, Menyetel bias horizontal dan vertikal, memusatkan secara horizontal dan vertikal, memanipulasi Rantai, dan banyak lagi.

Bacaan yang sangat bagus.

Sekali lagi, ini hanyalah adaptasi.

Felix Mendukung Chinemerem
sumber
0

Selain jawaban azizbekian , izinkan saya menunjukkan dua hal:

  1. Jika kiri / kanan tidak berfungsi, coba mulai / akhiri seperti ini:

params.startToEnd = button2.id

  1. Jika Anda ingin menghilangkan batasan, gunakan flag UNSET seperti ini:

params.startToEnd = ConstraintLayout.LayoutParams.UNSET

Oleg Yablokov
sumber