Saya telah mendesain Sel khusus saya di IB, mensubklasifikasikan dan menghubungkan outlet saya ke kelas khusus saya. Saya memiliki tiga subview dalam konten sel yaitu: UIView (cdView) dan dua label (titleLabel dan emailLabel). Bergantung pada data yang tersedia untuk setiap baris, kadang-kadang saya ingin UIView dan dua label ditampilkan di sel saya dan kadang-kadang hanya dua label. Apa yang saya coba lakukan adalah menetapkan batasan seperti itu jika saya mengatur properti UIView menjadi tersembunyi atau saya akan menghapusnya dari superview dua label akan pindah ke kiri. Saya mencoba mengatur batasan utama UIView menjadi Superview (konten sel) untuk 10px dan batasan utama UILabel untuk 10 px ke tampilan berikutnya (UIView). Kemudian dalam kode saya
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(IndexPath *)indexPath {
...
Record *record = [self.records objectAtIndex:indexPath.row];
if ([record.imageURL is equalToString:@""]) {
cell.cdView.hidden = YES;
}
Saya menyembunyikan cell.cdView saya dan saya ingin label untuk pindah ke kiri namun mereka tetap berada di posisi yang sama di Cell. Saya mencoba menghapus cell.cdView dari superview tetapi tidak berhasil juga. Saya telah melampirkan gambar untuk menjelaskan tentang saya.
Saya tahu bagaimana melakukan ini secara terprogram dan saya tidak mencari solusi itu. Yang saya inginkan adalah menetapkan batasan dalam IB dan saya berharap bahwa subview saya akan bergerak secara dinamis jika tampilan lain dihapus atau disembunyikan. Apakah mungkin untuk melakukan ini di IB dengan tata letak otomatis?
.....
Jawaban:
Itu mungkin, tetapi Anda harus melakukan sedikit pekerjaan ekstra. Ada beberapa hal konseptual untuk keluar dari jalan pertama:
Dalam kasus Anda, ini kemungkinan berarti:
Yang perlu Anda lakukan adalah membatasi label Anda dengan bijaksana . Biarkan kendala Anda saat ini (ruang 10pts ke tampilan lain), tetapi tambahkan kendala lain: jadikan tepi kiri label Anda 10pts dari tepi kiri superview mereka dengan prioritas yang tidak diperlukan (prioritas tinggi default mungkin akan bekerja dengan baik).
Kemudian, ketika Anda ingin mereka bergerak ke kiri, hapus tampilan kiri sama sekali. Batasan 10pt wajib untuk tampilan kiri akan menghilang bersama dengan tampilan yang terkait dengannya, dan Anda akan dibiarkan hanya dengan kendala prioritas tinggi yang labelnya berjarak 10 poin dari superview mereka. Pada pass tata letak berikutnya, ini akan menyebabkan mereka melebar ke kiri sampai mereka memenuhi lebar superview tetapi untuk jarak Anda di sekitar tepi.
Satu peringatan penting: jika Anda ingin tampilan kiri Anda kembali dalam gambar, Anda tidak hanya harus menambahkannya kembali ke hierarki tampilan, tetapi Anda juga harus membangun kembali semua kendala pada saat yang sama. Ini berarti Anda memerlukan cara untuk mengembalikan batasan spasi 10pt antara tampilan dan labelnya setiap kali tampilan itu ditampilkan lagi.
sumber
|-(space)-[hidden(0)]-(space)-[visible]
efektif|-(2*space)-[visible]
. Kedua, tampilan itu mungkin mulai melempar pelanggaran batasan tergantung pada subtree dan kendala tampilan sendiri - Anda tidak dapat menjamin bahwa Anda dapat secara sewenang-wenang membatasi tampilan pada lebar 0 dan membuatnya tetap berfungsi.|-[otherViews]-[eitherThis][orThis]-|
, tetapi saya akhirnya akan mengalami masalah itu.Menambah atau menghapus kendala selama runtime adalah operasi kelas berat yang dapat memengaruhi kinerja. Namun, ada alternatif yang lebih sederhana.
Untuk tampilan yang ingin Anda sembunyikan, atur batasan lebar. Batasi tampilan lain dengan celah horizontal mengarah ke tampilan itu.
Untuk menyembunyikan, perbarui
.constant
batasan lebar ke 0.f. Tampilan lain akan secara otomatis bergerak ke kiri untuk mengambil posisi.Lihat jawaban saya yang lain di sini untuk perincian lebih lanjut:
Bagaimana cara mengubah batasan label selama runtime?
sumber
Bagi mereka yang hanya mendukung iOS 8+ , ada properti boolean baru yang aktif . Ini akan membantu untuk mengaktifkan hanya kendala yang diperlukan secara dinamis
Stopkontak PS Constraint harus kuat , tidak lemah.
Contoh:
Juga untuk memperbaiki kesalahan di storyboard Anda harus menghapus
Installed
centang pada kotak centang untuk salah satu kendala ini.UIStackView (iOS 9+)
Satu opsi lagi adalah membungkus pandangan Anda
UIStackView
. Setelah tampilan disembunyikanUIStackView
akan memperbarui tata letak secara otomatissumber
UIStackView
reposisi pandangannya secara otomatis ketikahidden
properti diubah pada salah satu dari subview-nya (iOS 9+)Lompat ke 11:48 dalam video WWDC ini untuk demo:
Misteri Tata Letak Otomatis, Bagian 1
sumber
Proyek saya menggunakan
@IBDesignable
subkelas khususUILabel
(untuk memastikan konsistensi dalam warna, font, inset, dll.) Dan saya telah menerapkan sesuatu seperti berikut:Ini memungkinkan subclass label untuk mengambil bagian dalam Tata Letak Otomatis, tetapi tidak mengambil ruang ketika disembunyikan.
sumber
Untuk Googler: membangun jawaban Max, untuk menyelesaikan masalah padding yang banyak orang perhatikan, saya hanya menambah tinggi label dan menggunakan tinggi itu sebagai pemisah alih-alih padding aktual. Gagasan ini dapat diperluas untuk skenario apa pun yang berisi tampilan.
Berikut ini contoh sederhana:
Dalam hal ini, saya memetakan ketinggian label Penulis ke yang sesuai
IBOutlet
:dan ketika saya mengatur ketinggian batasan untuk
0.0f
, kami mempertahankan "padding", karena ketinggian tombol Play memungkinkan untuk itu.sumber
NSLayoutConstraint
mengenal saya percaya bahwa Anda ingin memperbaruiconstant
properti AndaauthorLabelHeight
.hubungkan batasan antara uiview dan label sebagai IBOutlet dan atur anggota prioritas ke nilai yang lebih rendah saat disembunyikan = YES
sumber
Apa yang akhirnya saya lakukan adalah membuat 2 xibs. Satu dengan tampilan kiri dan satu tanpa itu. Saya mendaftarkan keduanya di controller dan kemudian memutuskan mana yang akan digunakan selama cellForRowAtIndexPath.
Mereka menggunakan kelas UITableViewCell yang sama. Kelemahannya adalah bahwa ada beberapa duplikasi konten antara xibs, tetapi sel-sel ini cukup mendasar. Sisi baiknya adalah saya tidak memiliki banyak kode untuk mengelola penghapusan tampilan secara manual, memperbarui kendala, dll.
Secara umum, ini mungkin solusi yang lebih baik karena tata letak mereka berbeda secara teknis dan karenanya harus memiliki xib yang berbeda.
sumber
Dalam hal ini, saya memetakan ketinggian label Penulis ke IBOutlet yang sesuai:
dan ketika saya mengatur ketinggian batasan menjadi 0,0f, kami mempertahankan "padding", karena ketinggian tombol Play memungkinkan untuk itu.
sumber
Gunakan dua UIStackView Horizontal dan Vertical, ketika beberapa tampilan subview dalam stack disembunyikan, subview stack lainnya akan dipindahkan, gunakan Distribution -> Fill Proportionally for Vertical stack dengan dua UILabels dan perlu tetapkan lebar dan tinggi konstan untuk UIView pertama
sumber
Coba ini, saya telah menerapkan kode di bawah ini,
Saya punya satu View di ViewController yang menambahkan tiga tampilan lainnya, Ketika ada tampilan yang disembunyikan dua tampilan lainnya akan bergerak, Ikuti langkah-langkah di bawah ini. ,
File 1.ViewController.h
2.ViewController.m
Semoga Jadi logika ini akan membantu seseorang.
sumber
Dalam kasus saya saya mengatur konstan dari ketinggian kendala untuk
0.0f
dan juga mengaturhidden
properti untukYES
.Untuk menunjukkan tampilan (dengan subview) lagi saya melakukan yang sebaliknya: Saya mengatur tinggi konstan ke nilai non-nol dan mengatur
hidden
propertiNO
.sumber
Saya akan menggunakan stackview horizontal. Itu dapat menghapus bingkai ketika subview disembunyikan.
Pada gambar di bawah, tampilan merah adalah wadah aktual untuk konten Anda dan memiliki ruang trailing 10pt ke superview oranye (ShowHideView), lalu sambungkan ShowHideView ke IBOutlet dan tampilkan / sembunyikan / hapus secara programatik.
sumber
Ini solusi saya yang lain menggunakan kendala prioritas. Idenya adalah mengatur lebar ke 0.
buat tampilan kontainer (oranye) dan atur lebar.
buat tampilan konten (merah) dan atur spasi 10pt ke superview (oranye). Perhatikan trailing space constraint, ada 2 trailing constraint dengan prioritas berbeda. Rendah (= 10) dan Tinggi (<= 10). Ini penting untuk menghindari ambiguitas.
Atur lebar tampilan oranye ke 0 untuk menyembunyikan tampilan.
sumber
Seperti yang disarankan no_scene, Anda pasti dapat melakukan ini dengan mengubah prioritas kendala saat runtime. Ini jauh lebih mudah bagi saya karena saya memiliki lebih dari satu pandangan yang menghalangi yang harus dihapus.
Berikut cuplikan menggunakan ReactiveCocoa:
sumber
Dalam hal ini membantu seseorang, saya membangun kelas pembantu untuk menggunakan format visual batasan . Saya menggunakannya di aplikasi saya saat ini.
AutolayoutHelper
Mungkin sedikit disesuaikan dengan kebutuhan saya, tetapi Anda mungkin menemukan itu berguna atau Anda mungkin ingin mengubahnya dan membuat pembantu Anda sendiri.
Saya harus berterima kasih kepada Tim atas jawabannya di atas , jawaban ini tentang UIScrollView dan juga tutorial ini .
sumber
Inilah cara saya akan menyelaraskan uiviews saya untuk mendapatkan solusi Anda:
Saya membuat aturan praktis saya sendiri. Setiap kali Anda harus menyembunyikan / menampilkan uiview apa pun yang batasannya mungkin terpengaruh, tambahkan semua subview yang terpengaruh / tergantung di dalam uiview dan perbarui konstanta kendala terkemuka / trailing / atas / bawah secara terprogram.
sumber
Ini adalah pertanyaan lama tapi tetap saya harap ini akan membantu. Datang dari Android, di platform ini Anda memiliki metode praktis
isVisible
untuk menyembunyikannya dari tampilan tetapi juga tidak memiliki bingkai yang dipertimbangkan saat autolayout menggambar tampilan.menggunakan ekstensi dan "extended" uiview Anda bisa melakukan fungsi serupa di ios (tidak yakin mengapa itu tidak ada di UIKit) di sini implementasi di swift 3:
sumber
cara yang tepat untuk melakukannya adalah menonaktifkan batasan dengan isActive = false. namun perhatikan bahwa menonaktifkan batasan menghilangkan dan melepaskannya, jadi Anda harus memiliki outlet yang kuat untuk itu.
sumber
Solusi termudah adalah dengan menggunakan UIStackView (horizontal). Tambahkan ke tumpukan tampilan: tampilan pertama dan tampilan kedua dengan label. Kemudian atur properti isHidden dari tampilan pertama ke false. Semua kendala akan dihitung dan diperbarui secara otomatis.
sumber
Saya pikir ini adalah jawaban yang paling sederhana. Harap verifikasi bahwa itu berfungsi:
periksa di sini https://www.youtube.com/watch?v=EBulMWMoFuw
sumber