Saya mencoba membuat ukuran sendiri UICollectionViewCells
bekerja dengan Tata Letak Otomatis, tetapi sepertinya saya tidak bisa membuat sel untuk mengukur sendiri untuk konten. Saya mengalami kesulitan memahami bagaimana ukuran sel diperbarui dari konten yang ada di dalam contentView sel.
Berikut pengaturan yang saya coba:
- Ubahsuaikan
UICollectionViewCell
denganUITextView
di isinyaView. - Menggulir untuk yang
UITextView
dinonaktifkan. - Batasan horizontal contentView adalah: "H: | [_textView (320)]", yaitu
UITextView
disematkan di sebelah kiri sel dengan lebar eksplisit 320. - Batasan vertikal contentView adalah: "V: | -0 - [_ textView]", yaitu yang
UITextView
disematkan di bagian atas sel. - The
UITextView
memiliki kendala tinggi diatur ke sebuah konstanta yangUITextView
laporan akan cocok teks.
Begini tampilannya dengan latar belakang sel yang disetel menjadi merah, dan UITextView
latar diatur ke Biru:
Saya meletakkan proyek yang telah saya mainkan di GitHub di sini .
Jawaban:
Diperbarui untuk Swift 5
preferredLayoutAttributesFittingAttributes
diubah namanya menjadipreferredLayoutAttributesFitting
dan menggunakan ukuran otomatisDiperbarui untuk Swift 4
systemLayoutSizeFittingSize
diganti namanya menjadisystemLayoutSizeFitting
Diperbarui untuk iOS 9
Setelah melihat solusi GitHub saya istirahat di iOS 9 saya akhirnya punya waktu untuk menyelidiki masalah ini sepenuhnya. Saya sekarang telah memperbarui repo untuk memasukkan beberapa contoh konfigurasi yang berbeda untuk sel-sel ukuran sendiri. Kesimpulan saya adalah bahwa sel-sel ukuran diri besar dalam teori tetapi berantakan dalam praktiknya. Sebuah kata peringatan ketika melanjutkan dengan sel sizing diri.
TL; DR
Lihat proyek GitHub saya
Sel ukuran sendiri hanya didukung dengan tata letak aliran jadi pastikan itulah yang Anda gunakan.
Ada dua hal yang Anda butuhkan untuk mengatur agar sel-sel ukuran sendiri berfungsi.
1. Set
estimatedItemSize
diUICollectionViewFlowLayout
Tata letak aliran akan menjadi dinamis setelah Anda mengatur
estimatedItemSize
properti.2. Tambahkan dukungan untuk ukuran pada subkelas sel Anda
Ini hadir dalam 2 rasa; Tata Letak Otomatis atau penggantian kustom
preferredLayoutAttributesFittingAttributes
.Buat dan konfigurasikan sel dengan Tata Letak Otomatis
Saya tidak akan masuk ke detail tentang ini karena ada posting SO brilian tentang mengkonfigurasi kendala untuk sel. Hanya berhati-hatilah bahwa Xcode 6 memecahkan banyak hal dengan iOS 7 jadi, jika Anda mendukung iOS 7, Anda harus melakukan hal-hal seperti memastikan autoresizingMask diatur pada konten sel. sel dimuat (yaitu
awakeFromNib
).Hal yang perlu Anda ketahui adalah bahwa sel Anda harus dibatasi lebih serius daripada Table View Cell. Misalnya, jika Anda ingin lebar Anda menjadi dinamis maka sel Anda membutuhkan batasan ketinggian. Demikian juga, jika Anda ingin ketinggian menjadi dinamis maka Anda akan memerlukan batasan lebar untuk sel Anda.
Terapkan
preferredLayoutAttributesFittingAttributes
di sel khusus AndaKetika fungsi ini disebut, tampilan Anda telah dikonfigurasikan dengan konten (yaitu
cellForItem
telah dipanggil). Dengan asumsi kendala Anda telah diatur dengan tepat, Anda dapat memiliki implementasi seperti ini:CATATAN Pada iOS 9 perilaku berubah sedikit yang dapat menyebabkan crash pada implementasi Anda jika Anda tidak hati-hati (Lihat lebih lanjut di sini ). Saat Anda menerapkan,
preferredLayoutAttributesFittingAttributes
Anda perlu memastikan bahwa Anda hanya mengubah bingkai atribut tata letak Anda satu kali. Jika Anda tidak melakukan ini, tata letak akan memanggil implementasi Anda tanpa batas dan akhirnya macet. Salah satu solusinya adalah men-cache ukuran yang dihitung dalam sel Anda dan membatalkan ini kapan saja Anda menggunakan kembali sel atau mengubah kontennya seperti yang telah saya lakukan denganisHeightCalculated
properti.Rasakan tata letak Anda
Pada titik ini Anda harus memiliki sel dinamis 'berfungsi' di collectionView Anda. Saya belum menemukan solusi out-of-the-box yang cukup selama pengujian saya jadi jangan ragu untuk berkomentar jika Anda punya Rasanya masih seperti
UITableView
memenangkan pertempuran untuk IMHO ukuran dinamis.Peringatan
Perhatikan bahwa jika Anda menggunakan sel prototipe untuk menghitung estimasiItemSize - ini akan pecah jika XIB Anda menggunakan kelas ukuran . Alasannya adalah ketika Anda memuat sel Anda dari XIB, kelas ukurannya akan dikonfigurasikan
Undefined
. Ini hanya akan rusak di iOS 8 dan lebih tinggi karena di iOS 7 kelas ukuran akan dimuat berdasarkan perangkat (iPad = Reguler-Any, iPhone = Compact-Any). Anda bisa mengatur Estimasi item tanpa memuat XIB, atau Anda dapat memuat sel dari XIB, menambahkannya ke collectionView (ini akan mengatur traitCollection), melakukan tata letak, dan kemudian menghapusnya dari superview. Atau Anda juga bisa membuat sel Anda menimpatraitCollection
pengambil dan mengembalikan sifat yang sesuai. Terserah kamu.Beri tahu saya jika saya melewatkan sesuatu, semoga saya membantu dan semoga berhasil coding
sumber
estimatedItemSize
mengarah ke macet - sepertinya ada beberapa bug besar dalam cara tata letak otomatis mencoba memproses UICollectionViewCell.Di iOS10 ada konstanta baru yang disebut
UICollectionViewFlowLayout.automaticSize
(sebelumnyaUICollectionViewFlowLayoutAutomaticSize
), jadi alih-alih:Anda bisa menggunakan ini:
Ini memiliki kinerja yang lebih baik terutama ketika sel dalam tampilan koleksi Anda memiliki wid konstan
Mengakses Tata Letak Alur:
Swift 5 Diperbarui:
sumber
collectionViewLayout
dan cukup periksa apakah itu bertipeUICollectionViewFlowLayout
Beberapa perubahan kunci pada jawaban Daniel Galasko memperbaiki semua masalah saya. Sayangnya, saya tidak memiliki reputasi yang cukup untuk berkomentar secara langsung (belum).
Pada langkah 1, saat menggunakan Tata Letak Otomatis, cukup tambahkan satu induk UIView ke dalam sel. SEGALA SESUATU di dalam sel harus menjadi subview dari induknya. Itu menjawab semua masalah saya. Sementara Xcode menambahkan ini untuk UITableViewCells secara otomatis, itu tidak (tetapi seharusnya) untuk UICollectionViewCells. Menurut dokumen :
Kemudian lewati langkah 3 sepenuhnya. Itu tidak diperlukan.
sumber
contentView
, Xcode mengeluh konflik dengan properti yang ada. Sudah mencoba menambahkan subview keself.contentView
dan menetapkan batasan untuk itu, lalu aplikasi mogok.Di iOS 10+ ini adalah proses 2 langkah yang sangat sederhana.
Pastikan bahwa semua konten sel Anda ditempatkan dalam UIView tunggal (atau di dalam turunan UIView seperti UIStackView yang menyederhanakan banyak pembayaran otomatis). Seperti halnya UITableViewCells yang mengubah ukuran secara dinamis, hierarki tampilan keseluruhan harus memiliki kendala yang dikonfigurasikan, dari wadah terluar ke tampilan terdalam. Itu termasuk kendala antara UICollectionViewCell dan childview langsung
Instruksikan flowlayout UICollectionView Anda untuk mengukur secara otomatis
sumber
UICollectionViewFlowLayout.automaticSize
telah diubah namanya menjadiUICollectionViewFlowLayoutAutomaticSize
.Tambahkan flowLayout di viewDidLoad ()
Juga, tetapkan UIView sebagai mainContainer untuk sel Anda dan tambahkan semua tampilan yang diperlukan di dalamnya.
Lihat tutorial yang mengagumkan dan mengejutkan ini untuk referensi lebih lanjut: UICollectionView dengan sel autosisasi menggunakan autolayout di iOS 9 & 10
sumber
EDIT 11/19/19: Untuk iOS 13, cukup gunakan UICollectionViewCompositionalLayout dengan perkiraan ketinggian. Jangan buang waktu Anda berurusan dengan API yang rusak ini.
Setelah berjuang dengan ini selama beberapa waktu, saya perhatikan bahwa pengubahan ukuran tidak berfungsi untuk UITextViews jika Anda tidak menonaktifkan pengguliran:
sumber
contentView misteri jangkar:
Dalam satu kasus aneh ini
tidak akan bekerja Menambahkan empat jangkar eksplisit ke contentView dan berhasil.
dan seperti biasa
di
YourLayout: UICollectionViewFlowLayout
Siapa tahu? Bisa membantu seseorang.
Kredit
https://www.vadimbulavin.com/collection-view-cells-self-sizing/
tersandung ke ujung sana - tidak pernah melihatnya di tempat lain di semua artikel 1000-an tentang ini.
sumber
Saya melakukan tampilan koleksi tinggi sel yang dinamis. Inilah repo hub git .
Dan, gali mengapa preferLayoutAttributesFittingAttributes disebut lebih dari sekali. Sebenarnya, itu akan dipanggil minimal 3 kali.
Gambar log konsol:
PreferredLayoutAttributesFittingAttributes :
LayoutAttributes.frame.size.height adalah status saat ini 57.5 .
2nd preferLayoutAttributesFittingAttributes :
Tinggi bingkai sel berubah menjadi 534,5 seperti yang kami harapkan. Tapi, tampilan koleksi masih nol tinggi.
3rdLayoutAttributesFittingAttributes lebih disukai :
Anda dapat melihat tinggi tampilan koleksi berubah dari 0 menjadi 477 .
Perilaku ini mirip dengan menangani gulir:
Pada awalnya, saya pikir metode ini hanya memanggil satu kali. Jadi saya kode sebagai berikut:
Garis ini:
akan menyebabkan system call infinite loop dan App crash.
Setiap ukuran diubah, itu akan memvalidasi semua sel preferLayoutAttributesFittingAttributes lagi dan lagi sampai setiap posisi sel (yaitu frame) tidak ada lagi perubahan.
sumber
Selain jawaban di atas,
Pastikan Anda menyetel properti estimasiItemSize dari UICollectionViewFlowLayout ke beberapa ukuran dan jangan mengimplementasikan sizeForItem: di metode delegate atIndexPath .
Itu dia.
sumber
Jika Anda menerapkan metode UICollectionViewDelegateFlowLayout:
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath
Saat Anda menelepon
collectionview performBatchUpdates:completion:
, tinggi ukuran akan digunakansizeForItemAtIndexPath
alih-alihpreferredLayoutAttributesFittingAttributes
.Proses rendering
performBatchUpdates:completion
akan melalui metodepreferredLayoutAttributesFittingAttributes
tetapi mengabaikan perubahan Anda.sumber
Bagi siapa pun itu mungkin membantu,
Saya mengalami kecelakaan yang tidak menyenangkan itu jika
estimatedItemSize
ditetapkan. Bahkan jika saya mengembalikan 0 innumberOfItemsInSection
. Oleh karena itu, sel-sel itu sendiri dan tata-letak otomatisnya bukanlah penyebab kerusakan ... CollectionView hanya mogok, bahkan ketika kosong, hanya karenaestimatedItemSize
diatur untuk mengatur sendiri.Dalam kasus saya, saya mengatur ulang proyek saya, dari pengontrol yang berisi collectionView ke collectionViewController, dan itu berhasil.
Sosok pergi.
sumber
collectionView.collectionViewLayout.invalidateLayout()
setelahcollectionView.reloadData()
.Bagi siapa saja yang mencoba segalanya tanpa keberuntungan, ini adalah satu-satunya yang membuatnya bekerja untuk saya. Untuk label multiline di dalam sel, coba tambahkan garis ajaib ini:
Info lebih lanjut: di sini
Bersulang!
sumber
Metode contoh di atas tidak dikompilasi. Ini adalah versi yang sudah dikoreksi (tetapi belum diuji apakah berfungsi atau tidak.)
sumber
Perbarui informasi lebih lanjut:
Jika Anda menggunakan
flowLayout.estimatedItemSize
, sarankan gunakan versi iOS8.3 nanti. Sebelum iOS8.3, itu akan crash[super layoutAttributesForElementsInRect:rect];
. Pesan kesalahannya adalah*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Kedua, dalam versi iOS8.x,
flowLayout.estimatedItemSize
akan menyebabkan pengaturan bagian inset yang berbeda tidak berfungsi. fungsi yaitu:(UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:
.sumber
Solusinya terdiri dari 4 langkah penting:
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
contentView
ke tepi sel karenacontentView
mencegah swa-ukuran, mengingat tata letak otomatis tidak diaktifkan.collectionView(:cellForItemAt:)
untuk membatasi lebar contentView ke lebar collectionView.Itu terjadi sebagai berikut; kami akan mengatur sel
maxWidth
variabel dengan lebar CollectionView ini dicollectionView(:cellForItemAt:)
dan dimaxWidth
'sdidSet
metode kami akan menetapkan widthAnchor.constant ke MaxWidth.Karena Anda ingin mengaktifkan UITextView dengan ukuran sendiri, ini memiliki langkah tambahan untuk;
4. Hitung dan atur ketinggianAnchor.constant dari UITextView.
Jadi, setiap kali lebar contentView diatur kami akan menyesuaikan ketinggian UITextView bersama di
didSet
darimaxWidth
.Di dalam UICollectionViewCell:
Langkah-langkah ini akan memberi Anda hasil yang diinginkan. Inilah intisari runnable yang lengkap
Terima kasih kepada Vadim Bulavin untuk posting blognya yang jelas dan mencerahkan - Collection View Cells Self-Sizing: Tutorial Langkah demi Langkah
sumber
Saya mencoba menggunakan
estimatedItemSize
tetapi ada banyak bug ketika memasukkan dan menghapus sel jikaestimatedItemSize
tidak persis sama dengan tinggi sel. saya berhenti mengaturestimatedItemSize
dan mengimplementasikan sel dinamis dengan menggunakan sel prototipe. begini caranya:buat protokol ini:
mengimplementasikan protokol ini di kebiasaan Anda
UICollectionViewCell
:sekarang buat pengontrol Anda sesuai
UICollectionViewDelegateFlowLayout
, dan di dalamnya, dapatkan bidang ini:itu akan digunakan sebagai sel prototipe untuk mengikat data dan kemudian menentukan bagaimana data itu mempengaruhi dimensi yang Anda inginkan menjadi dinamis
akhirnya,
UICollectionViewDelegateFlowLayout's
collectionView(:layout:sizeForItemAt:)
harus diimplementasikan:dan hanya itu. Mengembalikan ukuran sel dengan
collectionView(:layout:sizeForItemAt:)
cara ini mencegah saya dari keharusan menggunakanestimatedItemSize
, dan menyisipkan dan menghapus sel berfungsi dengan baik.sumber