Saya merasa ini adalah paradigma yang cukup umum untuk ditunjukkan / sembunyikan UIViews
, paling sering UILabels
, tergantung pada logika bisnis. Pertanyaan saya adalah, apa cara terbaik menggunakan AutoLayout untuk menanggapi tampilan tersembunyi seolah-olah bingkai mereka 0x0. Berikut adalah contoh daftar dinamis 1-3 fitur.
Saat ini saya memiliki ruang atas 10px dari tombol ke label terakhir, yang jelas tidak akan geser ke atas ketika label disembunyikan. Sampai sekarang saya membuat outlet untuk batasan ini dan memodifikasi konstanta tergantung pada berapa banyak label yang saya tampilkan. Ini jelas agak membingungkan karena saya menggunakan nilai konstan negatif untuk menekan tombol di atas frame tersembunyi. Ini juga buruk karena tidak dibatasi oleh elemen tata letak yang sebenarnya, hanya perhitungan statis yang licik berdasarkan ketinggian / padding elemen lainnya yang diketahui, dan jelas berjuang melawan untuk apa AutoLayout dibuat.
Saya jelas bisa saja membuat batasan baru tergantung pada label dinamis saya, tapi itu banyak manajemen mikro dan banyak kata-kata untuk mencoba hanya menghancurkan beberapa spasi putih. Apakah ada pendekatan yang lebih baik? Mengubah ukuran bingkai 0,0 dan membiarkan AutoLayout melakukan tugasnya tanpa manipulasi kendala? Menghapus tampilan sepenuhnya?
Jujur saja, hanya mengubah konstanta dari konteks tampilan tersembunyi memerlukan satu baris kode dengan perhitungan sederhana. Menciptakan kendala baru dengan constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:
tampaknya begitu berat.
Sunting Feb 2018 : Lihat jawaban Ben dengan UIStackView
s
sumber
Jawaban:
UIStackView
mungkin cara untuk iOS 9+. Tidak hanya menangani tampilan tersembunyi, itu juga akan menghapus spasi dan margin tambahan jika diatur dengan benar.sumber
Preferensi pribadi saya untuk menampilkan / menyembunyikan tampilan adalah membuat IBOutlet dengan lebar atau batas ketinggian yang sesuai.
Saya kemudian memperbarui
constant
nilai untuk0
disembunyikan, atau nilai apa pun yang harus ditampilkan.Keuntungan besar dari teknik ini adalah bahwa kendala relatif akan dipertahankan. Misalnya, Anda memiliki tampilan A dan tampilan B dengan celah horizontal x . Ketika tampilan A lebar
constant
diatur ke0.f
kemudian tampilan B akan bergerak ke kiri untuk mengisi ruang itu.Tidak perlu menambah atau menghilangkan kendala, yang merupakan operasi kelas berat. Cukup memperbarui kendala
constant
akan melakukan trik.sumber
Solusi menggunakan konstanta
0
ketika disembunyikan dan konstanta lain jika Anda menampilkannya lagi fungsional, tetapi tidak memuaskan jika konten Anda memiliki ukuran yang fleksibel. Anda perlu mengukur konten fleksibel Anda dan menetapkan kembali konstan. Ini terasa salah, dan memiliki masalah jika konten berubah ukuran karena kejadian server atau UI.Saya punya solusi yang lebih baik.
Idenya adalah untuk menetapkan aturan ketinggian 0 untuk memiliki prioritas tinggi ketika kita menyembunyikan elemen sehingga tidak memakan ruang autolayout.
Begini cara Anda melakukannya:
1. mengatur lebar (atau tinggi) dari 0 di pembangun antarmuka dengan prioritas rendah.
Pembuat Antarmuka tidak akan berteriak tentang konflik karena prioritasnya rendah. Uji perilaku ketinggian dengan menetapkan prioritas ke 999 sementara (1000 dilarang untuk bermutasi secara program, jadi kami tidak akan menggunakannya). Pembuat antarmuka mungkin sekarang akan berteriak tentang kendala yang saling bertentangan. Anda dapat memperbaikinya dengan menetapkan prioritas pada objek terkait hingga 900 atau lebih.
2. Tambahkan outlet sehingga Anda dapat mengubah prioritas batasan lebar dalam kode:
3. Sesuaikan prioritas ketika Anda menyembunyikan elemen Anda:
sumber
Dalam hal ini, saya memetakan ketinggian label Penulis ke IBOutlet yang sesuai:
dan ketika saya mengatur ketinggian kendala menjadi 0,0f, kami mempertahankan "padding", karena ketinggian tombol Play memungkinkan untuk itu.
sumber
Ada banyak solusi di sini tetapi pendekatan saya yang biasa berbeda lagi :)
Siapkan dua set kendala yang mirip dengan jawaban Jorge Arimany dan TMin:
Ketiga batasan yang ditandai memiliki nilai yang sama untuk Constant. Batasan yang ditandai A1 dan A2 memiliki Prioritasnya diatur ke 500, sedangkan kendala yang ditandai B menjadikan Prioritasnya diatur ke 250 (atau
UILayoutProperty.defaultLow
dalam kode).Hubungkan kendala B ke IBOutlet. Kemudian, ketika Anda menyembunyikan elemen, Anda hanya perlu mengatur prioritas kendala ke tinggi (750):
constraintB.priority = .defaultHigh
Tetapi ketika elemen terlihat, atur prioritas kembali ke rendah (250):
constraintB.priority = .defaultLow
Keuntungan (diakui minor) untuk pendekatan ini dari hanya mengubah
isActive
untuk kendala B adalah bahwa Anda masih memiliki kendala kerja jika elemen transien dihapus dari tampilan dengan cara lain.sumber
Subkelas tampilan dan timpa
func intrinsicContentSize() -> CGSize
. Kembali sajaCGSizeZero
jika tampilan disembunyikan.sumber
invalidateIntrinsicContentSize
. Anda dapat melakukannya secara overridesetHidden
.Saya baru tahu bahwa untuk mendapatkan UILabel agar tidak memakan tempat, Anda harus menyembunyikannya DAN mengatur teksnya ke string kosong. (iOS 9)
Mengetahui fakta / bug ini dapat membantu beberapa orang menyederhanakan layout mereka, bahkan mungkin dari pertanyaan awal, jadi saya pikir saya akan mempostingnya.
sumber
Saya terkejut bahwa tidak ada pendekatan yang lebih elegan yang disediakan oleh
UIKit
untuk perilaku yang diinginkan ini. Sepertinya hal yang sangat umum untuk dapat dilakukan.Karena menghubungkan kendala ke
IBOutlets
dan menyetel konstanta mereka menjadi0
yucky (dan menyebabkanNSLayoutConstraint
peringatan ketika tampilan Anda memiliki subview), saya memutuskan untuk membuat ekstensi yang memberikan pendekatan sederhana, stateful untuk menyembunyikan / menampilkan suatuUIView
yang memiliki kendala Tata Letak OtomatisItu hanya menyembunyikan pandangan dan menghilangkan kendala eksterior. Ketika Anda menunjukkan tampilan lagi, itu menambah kendala kembali. Satu-satunya peringatan adalah bahwa Anda harus menentukan batasan failover fleksibel untuk tampilan sekitarnya.
Sunting Jawaban ini ditargetkan untuk iOS 8.4 dan di bawahnya. Di iOS 9, gunakan saja
UIStackView
pendekatannya.sumber
Praktik terbaik adalah, setelah semuanya memiliki batasan tata letak yang benar, tambahkan ketinggian atau dengan kendala, tergantung bagaimana Anda ingin tampilan di sekitarnya bergerak dan menghubungkan kendala ke
IBOutlet
properti.Pastikan bahwa properti Anda
strong
dalam kode kamu hanya perlu mengatur konstanta ke 0 dan mengaktifkannya , untuk menyembunyikan konten, atau menonaktifkannya untuk menampilkan konten. Ini lebih baik daripada mengacaukan nilai konstan tabungan-memulihkannya. Jangan lupa menelepon
layoutIfNeeded
sesudahnya.Jika konten yang akan disembunyikan dikelompokkan, praktik terbaik adalah menempatkan semua ke tampilan dan menambahkan kendala ke tampilan itu
Setelah Anda mengatur Anda, Anda dapat mengujinya di IntefaceBuilder dengan menetapkan batasan Anda ke 0 dan kemudian kembali ke nilai aslinya. Jangan lupa untuk memeriksa prioritas kendala lainnya sehingga ketika disembunyikan tidak ada konflik sama sekali. Cara lain untuk mengujinya adalah dengan meletakkannya ke 0 dan mengatur prioritas ke 0, tetapi, jangan lupa untuk mengembalikannya ke prioritas tertinggi lagi.
sumber
Saya membangun kategori untuk memperbarui kendala dengan mudah:
Jawab di sini: Sembunyikan autolayout UIView: Cara mendapatkan NSLayoutConstraint yang ada untuk memperbarui yang ini
sumber
Metode pilihan saya sangat mirip dengan yang disarankan oleh Jorge Arimany.
Saya lebih suka membuat banyak kendala. Pertama buat batasan Anda ketika label kedua terlihat. Buat outlet untuk batasan antara tombol dan label ke-2 (jika Anda menggunakan objc pastikan kuatnya). Batasan ini menentukan ketinggian antara tombol dan label kedua saat terlihat.
Kemudian buat batasan lain yang menentukan ketinggian antara tombol dan label atas ketika tombol kedua disembunyikan. Buat outlet ke batasan kedua dan pastikan outlet ini memiliki pointer yang kuat. Kemudian hapus centang pada
installed
centang pada kotak centang di pembangun antarmuka, dan pastikan prioritas kendala pertama lebih rendah dari prioritas kendala kedua ini.Akhirnya ketika Anda menyembunyikan label kedua, beralih
.isActive
properti dari kendala dan panggilan inisetNeedsDisplay()
Dan itu saja, tidak ada angka Ajaib, tidak ada matematika, jika Anda memiliki beberapa kendala untuk menghidupkan dan mematikan Anda bahkan dapat menggunakan koleksi outlet untuk menjaga mereka diatur oleh negara. (AKA menyimpan semua kendala tersembunyi di satu OutletCollection dan yang tidak tersembunyi di yang lain dan hanya mengulangi setiap koleksi untuk mengubah status .isActive mereka).
Saya tahu Ryan Romanchuk mengatakan dia tidak ingin menggunakan banyak kendala, tapi saya merasa ini bukan manajemen mikro-y, dan lebih sederhana yang secara dinamis menciptakan pandangan dan kendala secara terprogram (yang menurut saya ingin dia hindari jika saya sedang membaca pertanyaan dengan benar).
Saya telah membuat contoh sederhana, semoga bermanfaat ...
sumber
Saya akan memberikan solusi saya juga, untuk menawarkan variasi.) Saya pikir membuat outlet untuk lebar / tinggi masing-masing item plus untuk jarak hanya konyol dan meledakkan kode, kemungkinan kesalahan dan jumlah komplikasi.
Metode saya menghapus semua tampilan (dalam kasus saya, contoh UIImageView), memilih mana yang perlu ditambahkan kembali, dan dalam satu lingkaran, itu menambahkan kembali masing-masing dan menciptakan kendala baru. Ini sebenarnya sangat sederhana, harap tindak lanjuti. Ini kode cepat dan kotor saya untuk melakukannya:
Saya mendapatkan tata letak dan spasi yang bersih dan konsisten. Kode saya menggunakan Masonry, saya sangat merekomendasikannya: https://github.com/SnapKit/Masonry
sumber
Coba BoxView , itu membuat tata letak dinamis ringkas dan mudah dibaca.
Dalam kasus Anda itu adalah:
sumber