Bagaimana saya bisa mengubah prioritas kendala dalam waktu berjalan


87

Saya memiliki tampilan yang memiliki ketinggian dinamis dan saya mencoba mengubah prioritas tinggi tampilan ini dalam waktu proses.

Ini bagian dari kode saya;

if (index == 0) {

    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.priority = 1000;

} else if (index == 1) {

    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.priority = 500;

}

Saya mengubah indeks dengan aksi tombol. Ketika saya menjalankan kode ini, saya mendapatkan kesalahan ini:

*** Assertion failure in -[NSLayoutConstraint setPriority:], /SourceCache/Foundation/Foundation-1141.1/Layout.subproj/NSLayoutConstraint.m:174

Apa kesalahan saya disini?

Jawaban:


174

Seperti yang dinyatakan dalam NSLayoutConstraintreferensi kelas :

Prioritas tidak boleh berubah dari tidak wajib menjadi wajib, atau dari wajib menjadi tidak wajib. Pengecualian akan diberikan jika prioritas NSLayoutPriorityRequireddi OS X atau UILayoutPriorityRequireddi iOS diubah ke prioritas yang lebih rendah, atau jika prioritas yang lebih rendah diubah ke prioritas yang diperlukan setelah batasan ditambahkan ke tampilan. Mengubah dari satu prioritas opsional ke prioritas opsional lainnya diperbolehkan bahkan setelah batasan diinstal pada tampilan.

Gunakan prioritas 999 alih-alih 1000. Ini tidak mutlak diperlukan secara teknis, tetapi ini akan menjadi prioritas yang lebih tinggi dari apa pun.


4
Terima kasih atas jawaban Anda yang bagus, tetapi jika saya menggunakan 999, bukan 1000, saya tidak dapat menyembunyikan pandangan saya dengan menetapkan 0 untuk batasan ketinggian.
Le'Kirdok

Itu masalah lain. Anda mungkin memiliki kendala lain yang saling bertentangan. Jika kode Anda tidak mogok lagi tetapi animasi tampilan Anda masih salah, tandai pertanyaan ini sebagai terselesaikan; lalu buka satu sama lain.
Cyrille

bagus, tidak masalah menggunakan nilai yang berbeda (999, 900, 500, dll.) :)
user924

7
Sungguh? Apakah ada yang berfungsi normal dalam pengembangan iOS? Begitu banyak hal yang harus dilakukan secara manual dan / atau harus mengimplementasikan berton-ton kode solusi yang menyebabkan bug sistem atau tidak didukung. Maaf atas komentar yang tidak membangun.
Luten

7
Sepertinya batasan ini telah dihapus di iOS 13. Saya mencoba mengubah batasan dari requiredmenjadi defaultLowdan berhasil. Kode yang sama digunakan untuk mogok di iOS 12.
Steven Vandeweghe

53

Saya ingin memberi sedikit tambahan pada jawaban Cyrille.

Jika Anda membuat batasan dalam kode, pastikan untuk menyetel prioritasnya sebelum membuatnya aktif. Misalnya:

surveyViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self
                                               attribute:NSLayoutAttributeHeight
                                               relatedBy:NSLayoutRelationEqual
                                                  toItem:self.superview
                                               attribute:NSLayoutAttributeHeight
                                              multiplier:1
                                                constant:0];
surveyViewHeightConstraint.active = YES;
surveyViewHeightConstraint.priority = 999;

Ini akan menghasilkan pengecualian waktu proses.

Mengubah prioritas dari wajib menjadi tidak pada batasan yang terpasang (atau sebaliknya) tidak didukung.

Urutan yang benar adalah:

surveyViewHeightConstraint.priority = 999;
surveyViewHeightConstraint.active = YES;

Untuk Swift versi 4+

constraintName.priority = UILayoutPriority(rawValue: 999)

13

Versi Swift:

myContraint.priority = UILayoutPriority(999.0)

8

Cara kami selalu menangani ini adalah dengan tidak mengubah konstanta kendala, cukup prioritasnya. Misalnya, dalam situasi Anda memiliki dua kendala ketinggian.

 heightConstraintOne (who's height is set in the storyboard at 150, and priority set at 750)
 heightConstraintTwo (who's height is set in the storyboard at 0, and priority set at 250)

jika Anda ingin menyembunyikan tampilan, Anda:

heightConstraintTwo.priority = 999;

Begitu pula jika Anda ingin memperlihatkan tampilan:

heightConstraintTwo.priority = 250;

5
Keren, mengerti: gunakan 999, bukan 1000. Terima kasih
brainray

3

Saya berharap skenario ini membantu seseorang: Saya memiliki dua kendala, bahwa mereka berlawanan satu sama lain, maksud saya mereka tidak dapat puas dalam waktu yang sama, dalam pembuat antarmuka salah satunya memiliki prioritas 1000 dan lainnya memiliki prioritas kurang dari 1000. ketika saya mengubahnya dalam kode, saya mengalami kesalahan ini:

Menghentikan aplikasi karena pengecualian yang tidak tertangkap 'NSInternalInconsistencyException', alasan: 'Mengubah prioritas dari wajib menjadi tidak pada batasan yang terpasang (atau sebaliknya) tidak didukung. Anda melewati prioritas 250 dan prioritas yang ada adalah 1000. '

kemudian saya hanya menginisialisasi mereka dalam fungsi viewDidLoad dengan nilai .defaultHigh dan .defaultLow dan ini memperbaiki masalah saya.


1

Menurut NSLayoutConstraints classdi dalam UIKit Module

Jika tingkat prioritas batasan kurang dari UILayoutPriorityRequired, maka itu opsional. Batasan prioritas yang lebih tinggi dipenuhi sebelum batasan prioritas yang lebih rendah. Kepuasan kendala tidak semuanya atau tidak sama sekali. Jika batasan 'a == b' bersifat opsional, itu berarti kami akan mencoba meminimalkan 'abs (ab)'. Properti ini hanya dapat diubah sebagai bagian dari penyiapan awal atau jika opsional. Setelah batasan ditambahkan ke tampilan, pengecualian akan ditampilkan jika prioritas diubah dari / ke NSLayoutPriorityRequired.

Contoh: - UIButtonkendala dengan berbagai prioritas -

 func setConstraints() {
        buttonMessage.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: -10).isActive = true

        let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 10)

        leading.isActive = true


        let widthConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100)

        let heightConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)


        let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)

        trailingToSuperView.priority = 999
        trailingToSuperView.isActive = true

        //leading.isActive = false//uncomment & check it will align to right of the View

        buttonMessage.addConstraints([widthConstraint,heightConstraint])

         }  

1
Tidak, Anda tidak boleh membuat batasan di viewDidLayoutSubviews. Metode itu bisa dipanggil beberapa kali, yang bisa membuat aplikasi Anda mogok jika Anda membuat batasan duplikat di sana.
mph

0

Saya menghadapi masalah yang sama. Karena beberapa jawaban yang disebutkan di atas di iOS 13 mengubah prioritas akan berfungsi dengan baik, Namun di iOS 12 itu akan menyebabkan crash.

Saya dapat memperbaiki masalah ini dengan membuat IBOutlet NSLayoutConstraint ke batasan khusus di Storyboard yang mempertahankan prioritasnya ke 1000, di bawah ini adalah kode untuk memperbaikinya.

if (Condition) {
    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.isActive = false;
} else if (index == 1) {
    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.isActive = True;
}

Semoga ini membantu!!! Bersulang


-2

Sekarang Anda bisa, cukup gunakan koneksi IBOutlet untuk batasan Anda, lalu gunakan kode ini.

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.