Saya telah menyiapkan beberapa rangkaian batasan di IB, dan saya ingin beralih di antara keduanya secara terprogram tergantung pada beberapa status. Ada constraintsA
koleksi outlet yang semuanya ditandai terinstal dari IB, dan constraintsB
koleksi outlet yang semuanya dihapus di IB.
Saya secara terprogram dapat beralih di antara dua set seperti ini:
NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)
Tapi ... Saya tidak tahu kapan harus melakukan itu. Sepertinya saya harus bisa melakukannya sekali viewDidLoad
, tapi saya tidak bisa membuatnya bekerja. Saya sudah mencoba menelepon view.updateConstraints()
dan view.layoutSubviews()
setelah mengatur batasan, tetapi tidak berhasil.
Saya menemukan bahwa jika saya menetapkan batasan dalam viewDidLayoutSubviews
segala hal bekerja seperti yang diharapkan. Saya rasa saya ingin mengetahui dua hal ...
- Mengapa saya mendapatkan perilaku ini?
- Apakah mungkin untuk mengaktifkan / menonaktifkan batasan dari viewDidLoad?
sumber
Jawaban:
Saya mengaktifkan dan menonaktifkan
NSLayoutConstraints
diviewDidLoad
, dan saya tidak memiliki masalah dengan itu. Jadi itu berhasil. Harus ada perbedaan dalam penyiapan antara aplikasi Anda dan aplikasi saya :-)Saya hanya akan menjelaskan penyiapan saya - mungkin itu bisa memberi Anda petunjuk:
@IBOutlets
semua kendala yang perlu saya aktifkan / nonaktifkan.ViewController
, saya menyimpan batasan ke dalam properti kelas yang tidak lemah. Alasannya adalah karena saya menemukan bahwa setelah menonaktifkan kendala, saya tidak dapat mengaktifkannya kembali - nol. Jadi, sepertinya akan dihapus saat dinonaktifkan.NSLayoutConstraint.deactivate/activate
seperti yang Anda lakukan, saya menggunakanconstraint.active = YES
/NO
sebagai gantinya.view.layoutIfNeeded()
.sumber
.active = false
mengharapkan mereka akan diabaikan sampai saya mengaturnya ke aktif.Mungkin Anda bisa memeriksa
@properties
, gantiweak
denganstrong
.Terkadang karena
active = NO
disetelself.yourConstraint = nil
, sehingga Anda tidak bisa menggunakanself.yourConstraint
lagi.sumber
weak
dan itu akan melakukannya.sumber
Saya yakin masalah yang Anda alami adalah karena kendala tidak ditambahkan ke pandangan mereka sampai SETELAH
viewDidLoad()
dipanggil. Anda memiliki sejumlah opsi:A) Anda dapat menghubungkan batasan tata letak Anda ke IBOutlet dan mengaksesnya dalam kode Anda dengan referensi ini. Karena outlet terhubung sebelum
viewDidLoad()
dimulai, batasan harus dapat diakses dan Anda dapat terus mengaktifkan dan menonaktifkannya di sana.B) Jika Anda ingin menggunakan
constraints()
fungsi UIView untuk mengakses berbagai batasan, Anda harus menunggu untukviewDidLayoutSubviews()
memulai dan melakukannya di sana, karena itu adalah poin pertama setelah membuat pengontrol tampilan dari ujung yang akan memiliki batasan yang terpasang. Jangan lupa meneleponlayoutIfNeeded()
setelah selesai. Ini memang memiliki kerugian bahwa pass tata letak akan dilakukan dua kali jika ada perubahan yang akan diterapkan dan Anda harus memastikan bahwa tidak ada kemungkinan loop tak terbatas akan dipicu.Sebuah kata peringatan singkat: batasan yang dinonaktifkan TIDAK dikembalikan oleh
constraints()
metode! Ini berarti jika Anda LAKUKAN menonaktifkan pembatas dengan maksud untuk mengaktifkannya kembali nanti, Anda perlu menyimpan referensi ke sana.C) Anda bisa melupakan pendekatan storyboard dan menambahkan batasan Anda secara manual. Karena Anda melakukan ini di,
viewDidLoad()
saya berasumsi bahwa tujuannya adalah hanya melakukannya sekali seumur hidup objek daripada mengubah tata letak dengan cepat, jadi ini harus menjadi metode yang dapat diterima.sumber
Anda juga dapat menyesuaikan
priority
properti untuk "mengaktifkan" dan "menonaktifkan" mereka (nilai 750 untuk diaktifkan dan 250 untuk menonaktifkan misalnya). Untuk beberapa alasan, mengubahactive
BOOL tidak berpengaruh pada UI saya. Tidak perlulayoutIfNeeded
dan dapat disetel dan diubah di viewDidLoad atau kapan saja setelah itu.sumber
viewWillTransition(to:, with:)
atauviewWillLayoutSubviews()
dan Anda dapat menyimpan semua batasan alternatif sebagai "terpasang" di papan cerita. Prioritas batasan tidak boleh berubah dari tidak wajib menjadi wajib, jadi gunakan nilai di bawah ini1000
. Di sisi lain, mengaktifkan (menambahkan) dan menonaktifkan (menghapus) batasan hanya berfungsiviewDidLayoutSubviews()
dan membutuhkanstrong
@IBOutlet
referensi keNSLayoutConstraint
-s.Waktu yang tepat untuk menonaktifkan kendala yang tidak digunakan:
Perlu diingat bahwa
viewWillLayoutSubviews
bisa dipanggil berkali-kali, jadi tidak ada perhitungan berat di sini, oke?Catatan: jika Anda ingin mengaktifkan kembali beberapa batasan nanti, maka selalu simpan
strong
referensi ke sana.sumber
viewDidLayoutSubviews()
. Menyesuaikan batasanviewWillLayoutSubviews()
tidak berfungsi dalam kasus saya.Saat tampilan sedang dibuat, metode siklus hidup berikut dipanggil secara berurutan:
Sekarang untuk pertanyaan Anda.
Jawaban: Karena ketika Anda mencoba untuk mengatur batasan pada tampilan dalam
viewDidLoad
tampilan tidak memiliki batasan, maka batasan tidak dapat diatur. Hanya setelahviewDidLayoutSubviews
itu batas tampilan diselesaikan.Jawaban: Tidak. Alasan dijelaskan di atas.
sumber
Saya telah menemukan selama Anda mengatur batasan per normal dalam menimpa
- (void)updateConstraints
(objektif c), denganstrong
referensi untuk inisialitas yang digunakan batasan aktif dan tidak aktif. Dan di tempat lain dalam siklus tampilan menonaktifkan dan / atau mengaktifkan apa yang Anda butuhkan, kemudian memanggillayoutIfNeeded
, Anda seharusnya tidak memiliki masalah.Hal utama adalah jangan terus-menerus menggunakan kembali penggantian
updateConstraints
dan untuk memisahkan aktivasi batasan, selama Anda memanggilnyaupdateConstraint
setelah inisialisasi dan tata letak pertama Anda. Tampaknya penting setelah itu di mana dalam siklus tampilan.sumber