Bagaimana Anda menggunakan Tata Letak Otomatis dalam UITableViewCell
tampilan tabel untuk membiarkan konten dan subview setiap sel menentukan tinggi baris (sendiri / otomatis), sambil mempertahankan kinerja pengguliran yang mulus?
ios
uitableview
autolayout
nsautolayout
row-height
smileyborg
sumber
sumber
contentSize
danpreferredMaxLayoutWidth
bekerja. Lihat di sini . Yang sedang berkata jika Anda mengatur kendala Anda dengan benar maka Anda tidak perlupreferredMaxLayoutWidth
dan pada kenyataannya dapat menciptakan hasil yang tidak terduga.Jawaban:
TL; DR: Tidak suka membaca? Langsung langsung ke proyek sampel di GitHub:
Deskripsi Konseptual
2 langkah pertama di bawah ini berlaku untuk apa pun versi iOS yang Anda kembangkan.
1. Mengatur & Menambahkan Kendala
Dalam Anda
UITableViewCell
subclass, menambahkan kendala sehingga subviews dari sel memiliki tepi mereka disematkan ke tepi sel contentView (yang paling penting ke atas dan tepi bawah). CATATAN: jangan sematkan subview ke sel itu sendiri; hanya ke selcontentView
! Biarkan ukuran konten intrinsik dari subview ini mendorong ketinggian tampilan konten sel tampilan tabel dengan memastikan hambatan kompresi konten dan kendala memeluk konten dalam dimensi vertikal untuk setiap subview tidak ditimpa oleh kendala prioritas lebih tinggi yang telah Anda tambahkan. ( Hah? Klik di sini. )Ingat, idenya adalah untuk membuat subview sel terhubung secara vertikal ke tampilan konten sel sehingga mereka dapat "menekan" dan membuat tampilan konten diperluas agar sesuai dengan mereka. Menggunakan contoh sel dengan beberapa subview, berikut ini adalah ilustrasi visual tentang apa yang beberapa (tidak semua!) Dari kendala Anda perlu terlihat seperti:
Anda dapat membayangkan bahwa karena lebih banyak teks ditambahkan ke label tubuh multi-garis pada contoh sel di atas, maka teks tersebut akan perlu tumbuh secara vertikal agar sesuai dengan teks, yang secara efektif akan memaksa sel untuk tumbuh tinggi. (Tentu saja, Anda perlu memperbaiki kendala agar ini berfungsi dengan benar!)
Memperbaiki kendala dengan tepat merupakan bagian tersulit dan paling penting untuk mendapatkan ketinggian sel dinamis yang bekerja dengan Tata Letak Otomatis. Jika Anda membuat kesalahan di sini, itu bisa mencegah semuanya bekerja - jadi luangkan waktu Anda! Saya sarankan mengatur batasan Anda dalam kode karena Anda tahu persis kendala mana yang ditambahkan di mana, dan itu jauh lebih mudah untuk debug ketika ada masalah. Menambahkan kendala dalam kode bisa semudah dan secara signifikan lebih kuat daripada Interface Builder menggunakan tata letak jangkar, atau salah satu API open source fantastis yang tersedia di GitHub.
updateConstraints
metode subkelas UITableViewCell Anda. Catatan yangupdateConstraints
dapat dipanggil lebih dari sekali, jadi untuk menghindari menambahkan kendala yang sama lebih dari sekali, pastikan untuk memasukkan kode penambahan kendala Anda dalamupdateConstraints
cek untuk properti boolean sepertididSetupConstraints
(yang Anda setel ke YA setelah Anda menjalankan kendala Anda -menambahkan kode sekali). Di sisi lain, jika Anda memiliki kode yang memperbarui kendala yang ada (seperti menyesuaikanconstant
properti pada beberapa kendala), letakkan ini diupdateConstraints
luar pemeriksaandidSetupConstraints
agar dapat dijalankan setiap kali metode dipanggil.2. Tentukan Unik Table View Cell Reuse Identifiers
Untuk setiap rangkaian kendala unik dalam sel, gunakan pengidentifikasi penggunaan kembali sel yang unik. Dengan kata lain, jika sel Anda memiliki lebih dari satu tata letak yang unik, masing-masing tata letak yang unik harus menerima pengenal penggunaan kembali sendiri. (Petunjuk bagus bahwa Anda perlu menggunakan pengenal penggunaan kembali yang baru adalah ketika varian sel Anda memiliki jumlah subview yang berbeda, atau subview tersebut diatur dengan cara yang berbeda.)
Misalnya, jika Anda menampilkan pesan email di setiap sel, Anda mungkin memiliki 4 tata letak yang unik: pesan hanya dengan subjek, pesan dengan subjek dan badan, pesan dengan subjek dan lampiran foto, dan pesan dengan subjek, tubuh, dan lampiran foto. Setiap tata letak memiliki batasan yang sangat berbeda yang diperlukan untuk mencapainya, jadi setelah sel diinisialisasi dan kendala ditambahkan untuk salah satu dari jenis sel ini, sel harus mendapatkan pengidentifikasi penggunaan ulang yang unik khusus untuk jenis sel itu. Ini berarti ketika Anda membuat sel untuk digunakan kembali, batasannya telah ditambahkan dan siap digunakan untuk jenis sel itu.
Perhatikan bahwa karena perbedaan dalam ukuran konten intrinsik, sel dengan batasan (tipe) yang sama mungkin masih memiliki ketinggian yang berbeda-beda! Jangan bingung tata letak yang berbeda secara fundamental (kendala yang berbeda) dengan bingkai tampilan terhitung yang berbeda (diselesaikan dari kendala yang sama) karena ukuran konten yang berbeda.
Untuk iOS 8 - Sel Self-Sizing
3. Aktifkan Estimasi Tinggi Baris
Dengan iOS 8, Apple telah menginternalisasi banyak pekerjaan yang sebelumnya harus diimplementasikan oleh Anda sebelum iOS 8. Untuk memungkinkan mekanisme sel sizing bekerja, Anda harus terlebih dahulu mengatur
rowHeight
properti pada tampilan tabel ke konstantaUITableViewAutomaticDimension
. Kemudian, Anda hanya perlu mengaktifkan estimasi tinggi baris dengan menyetelestimatedRowHeight
properti tampilan tabel ke nilai bukan nol, misalnya:Apa yang dilakukan adalah menyediakan tampilan tabel dengan estimasi sementara / placeholder untuk ketinggian baris sel yang belum tampil di layar. Kemudian, ketika sel-sel ini akan bergulir di layar, tinggi baris sebenarnya akan dihitung. Untuk menentukan ketinggian aktual untuk setiap baris, tampilan tabel secara otomatis menanyakan setiap sel berapa tinggi yang
contentView
dibutuhkan berdasarkan pada lebar tetap dari tampilan konten (yang didasarkan pada lebar tampilan tabel, dikurangi hal-hal tambahan seperti indeks bagian) atau tampilan aksesori) dan batasan tata letak otomatis yang telah Anda tambahkan ke tampilan dan subview konten sel. Setelah tinggi sel aktual ini telah ditentukan, tinggi estimasi lama untuk baris diperbarui dengan tinggi aktual baru (dan setiap penyesuaian pada konten tampilan tabelSize / contentOffset dibuat sesuai kebutuhan untuk Anda).Secara umum, perkiraan yang Anda berikan tidak harus sangat akurat - itu hanya digunakan untuk mengukur dengan benar indikator gulir dalam tampilan tabel, dan tampilan tabel melakukan pekerjaan yang baik untuk menyesuaikan indikator gulir untuk perkiraan yang salah saat Anda gulirkan sel di layar. Anda harus mengatur
estimatedRowHeight
properti pada tampilan tabel (dalamviewDidLoad
atau serupa) dengan nilai konstan yaitu tinggi baris "rata-rata". Hanya jika ketinggian baris Anda memiliki variabilitas ekstrem (mis. Berbeda berdasarkan urutan besarnya) dan Anda melihat indikator gulir "melompat" ketika Anda menggulir, Anda harus bersusah payah menerapkantableView:estimatedHeightForRowAtIndexPath:
untuk melakukan perhitungan minimal yang diperlukan untuk mengembalikan perkiraan yang lebih akurat untuk setiap baris.Untuk dukungan iOS 7 (menerapkan ukuran sel otomatis sendiri)
3. Lakukan Layout Pass & Dapatkan Tinggi Sel
Pertama, instantiate instance layar tampilan sel tampilan tabel, satu instance untuk setiap pengidentifikasi ulang , yang digunakan secara ketat untuk perhitungan ketinggian. (Offscreen artinya referensi sel disimpan dalam properti / ivar pada pengontrol tampilan dan tidak pernah kembali dari
tableView:cellForRowAtIndexPath:
tampilan tabel untuk benar-benar membuat layar). Selanjutnya, sel harus dikonfigurasi dengan konten yang tepat (misalnya teks, gambar, dll) bahwa itu akan berlaku jika itu akan ditampilkan dalam tampilan tabel.Kemudian, paksa sel untuk segera menata subview, dan kemudian gunakan
systemLayoutSizeFittingSize:
metode padaUITableViewCell
'scontentView
untuk mengetahui berapa tinggi sel yang diperlukan. GunakanUILayoutFittingCompressedSize
untuk mendapatkan ukuran terkecil yang diperlukan agar sesuai dengan semua isi sel. Ketinggian kemudian dapat dikembalikan daritableView:heightForRowAtIndexPath:
metode delegasi.4. Gunakan Estimated Row Heights
Jika tampilan tabel Anda memiliki lebih dari beberapa lusin baris di dalamnya, Anda akan menemukan bahwa melakukan penyelesaian kendala Tata Letak Otomatis dapat dengan cepat memotong utas saat pertama memuat tampilan tabel, seperti
tableView:heightForRowAtIndexPath:
yang dipanggil pada setiap baris pada beban pertama ( untuk menghitung ukuran indikator gulir).Pada iOS 7, Anda dapat (dan benar-benar harus) menggunakan
estimatedRowHeight
properti pada tampilan tabel. Apa yang dilakukan adalah menyediakan tampilan tabel dengan estimasi sementara / placeholder untuk ketinggian baris sel yang belum tampil di layar. Kemudian, ketika sel-sel ini akan bergulir di layar, tinggi baris aktual akan dihitung (dengan menelepontableView:heightForRowAtIndexPath:
), dan estimasi tinggi diperbarui dengan yang sebenarnya.Secara umum, perkiraan yang Anda berikan tidak harus sangat akurat - itu hanya digunakan untuk mengukur dengan benar indikator gulir dalam tampilan tabel, dan tampilan tabel melakukan pekerjaan yang baik untuk menyesuaikan indikator gulir untuk perkiraan yang salah saat Anda gulirkan sel di layar. Anda harus mengatur
estimatedRowHeight
properti pada tampilan tabel (dalamviewDidLoad
atau serupa) dengan nilai konstan yaitu tinggi baris "rata-rata". Hanya jika ketinggian baris Anda memiliki variabilitas ekstrem (mis. Berbeda berdasarkan urutan besarnya) dan Anda melihat indikator gulir "melompat" ketika Anda menggulir, Anda harus bersusah payah menerapkantableView:estimatedHeightForRowAtIndexPath:
untuk melakukan perhitungan minimal yang diperlukan untuk mengembalikan perkiraan yang lebih akurat untuk setiap baris.5. (Jika Diperlukan) Tambahkan Caching Ketinggian Baris
Jika Anda telah melakukan semua hal di atas dan masih menemukan bahwa kinerja sangat lambat saat melakukan penyelesaian kendala
tableView:heightForRowAtIndexPath:
, sayangnya Anda harus menerapkan beberapa caching untuk ketinggian sel. (Ini adalah pendekatan yang disarankan oleh para insinyur Apple.) Gagasan umum adalah membiarkan mesin Autolayout memecahkan kendala pertama kali, lalu menyimpan cache yang dihitung tinggi untuk sel itu dan menggunakan nilai cache untuk semua permintaan di masa depan untuk tinggi sel itu. Triknya tentu saja adalah memastikan Anda menghapus ketinggian cache untuk sebuah sel ketika terjadi sesuatu yang dapat menyebabkan tinggi sel berubah - terutama, ini akan terjadi ketika konten sel itu berubah atau ketika peristiwa penting lainnya terjadi (seperti pengguna menyesuaikan panel geser ukuran teks Tipe Dinamis).Kode Sampel Generik iOS 7 (dengan banyak komentar menarik)
Proyek Sampel
Proyek-proyek ini adalah contoh-contoh tampilan tabel yang berfungsi penuh dengan ketinggian baris variabel karena sel-sel tampilan tabel yang berisi konten dinamis dalam UILabel.
Xamarin (C # /. NET)
Jika Anda menggunakan Xamarin, periksa proyek sampel ini disatukan oleh @KentBoogaart .
sumber
heightForRowAtIndexPath
, menyimpan sel dan mengembalikannya pada waktu berikutnyacellForRowAtIndexPath
disebut.iOS8
implementasinya masih direkomendasikan untukiOS9
daniOS10
, atau adakah pendekatan baru sejak jawaban ini dipublikasikan?Untuk iOS 8 di atas sangat sederhana:
atau
Tetapi untuk iOS 7, kuncinya adalah menghitung ketinggian setelah autolayout:
Penting
Jika banyak baris label, jangan lupa atur
numberOfLines
ke0
.Jangan lupa
label.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)
Kode contoh lengkap ada di sini .
sumber
Contoh cepat dari ketinggian variabel UITableViewCell
Diperbarui untuk Swift 3
Jawaban William Hu dari Swift itu bagus, tetapi itu membantu saya untuk memiliki beberapa langkah sederhana namun terperinci ketika belajar melakukan sesuatu untuk pertama kalinya. Contoh di bawah ini adalah proyek pengujian saya sambil belajar membuat
UITableView
ketinggian sel variabel. Saya mendasarkannya pada contoh UITableView dasar ini untuk Swift .Proyek yang sudah selesai akan terlihat seperti ini:
Buat proyek baru
Ini bisa menjadi Aplikasi Tampilan Tunggal.
Tambahkan kodenya
Tambahkan file Swift baru ke proyek Anda. Beri nama MyCustomCell. Kelas ini akan menampung outlet untuk tampilan yang Anda tambahkan ke sel Anda di storyboard. Dalam contoh dasar ini, kami hanya akan memiliki satu label di setiap sel.
Kami akan menghubungkan outlet ini nanti.
Buka ViewController.swift dan pastikan Anda memiliki konten berikut:
Catatan penting:
Ini adalah dua baris kode berikut (bersama dengan tata letak otomatis) yang memungkinkan tinggi sel variabel:
Siapkan storyboard
Tambahkan Tampilan Tabel ke pengontrol tampilan Anda dan gunakan tata letak otomatis untuk menyematkannya ke empat sisi. Lalu seret Table View Cell ke Table View. Dan ke sel Prototipe, seret Label. Gunakan tata letak otomatis untuk menyematkan label pada keempat tepi tampilan konten dari Table View Cell.
Catatan penting:
Pengaturan IB lainnya
Nama kelas khusus dan Identifier
Pilih Table View Cell dan atur kelas kustom menjadi
MyCustomCell
(nama kelas dalam file Swift yang kami tambahkan). Juga atur Identifier menjadicell
(string yang sama dengan yang kita gunakancellReuseIdentifier
pada kode di atas.Nol Garis untuk Label
Setel jumlah baris ke
0
dalam Label Anda. Ini berarti multi-line dan memungkinkan label untuk mengubah ukuran sendiri berdasarkan kontennya.Menghubungkan Outlet
tableView
variabel dalamViewController
kode.myCellLabel
variabel diMyCustomCell
kelas.Jadi
Anda harus dapat menjalankan proyek Anda sekarang dan mendapatkan sel dengan ketinggian variabel.
Catatan
Jika Anda tidak menyematkan tepi depan dan belakang (kiri dan kanan), Anda mungkin juga perlu mengatur label
preferredMaxLayoutWidth
sehingga tahu kapan harus membungkus garis. Misalnya, jika Anda telah menambahkan batasan secara horizontal ke label pada proyek di atas daripada menyematkan tepi depan dan belakang, maka Anda perlu menambahkan baris ini ketableView:cellForRowAtIndexPath
metode:Lihat juga
sumber
preferredMaxLayoutWidth
melawan selcontentSize
? Dengan begitu jika Anda memiliki accessoryView atau digesek untuk diedit maka masih akan dipertimbangkan?Saya membungkus solusi iOS7 @ smileyborg dalam sebuah kategori
Saya memutuskan untuk membungkus solusi pintar ini dengan @smileyborg ke dalam
UICollectionViewCell+AutoLayoutDynamicHeightCalculation
kategori.Kategori ini juga memperbaiki masalah yang dijabarkan dalam jawaban @ wildmonkey (memuat sel dari nib dan
systemLayoutSizeFittingSize:
kembaliCGRectZero
)Itu tidak memperhitungkan caching tetapi sesuai dengan kebutuhan saya sekarang. Jangan ragu untuk menyalin, menempel, dan meretasnya.
UICollectionViewCell + AutoLayoutDynamicHeightCalculation.h
UICollectionViewCell + AutoLayoutDynamicHeightCalculation.m
Contoh penggunaan:
Syukurlah kita tidak harus melakukan jazz ini di iOS8, tapi itu untuk sekarang!
sumber
[YourCell new]
dan menggunakannya sebagai boneka. Selama kode pembangun kode kendala diaktifkan dalam instance Anda, dan Anda memicu pass layout secara programatik, Anda harus baik-baik saja.UICollectionViews
baik.Inilah solusi saya:
Anda perlu memberitahu
TableView
paraestimatedHeight
sebelum beban pandangan. Kalau tidak, ia tidak akan bisa berperilaku seperti yang diharapkan.Objektif-C
Perbarui ke Swift 4.2
sumber
estimatedRowHeight
bervariasi baris demi baris? haruskah saya melebihi atau di bawah perkiraan? gunakan ketinggian minimum atau maksimum yang saya gunakantableView
?estimatedRowHeight
, sebagian besar mempengaruhi ukuran bilah gulir, tidak pernah tinggi sel yang sebenarnya. Berani dalam ketinggian yang Anda pilih: ini akan memengaruhi animasi penyisipan / penghapusan.Solusi yang diajukan oleh @smileyborg hampir sempurna. Jika Anda memiliki sel khusus dan Anda ingin satu atau lebih
UILabel
dengan ketinggian dinamis maka metode systemLayoutSizeFittingSize yang dikombinasikan dengan AutoLayout diaktifkan mengembalikan aCGSizeZero
kecuali jika Anda memindahkan semua kendala sel Anda dari sel ke kontennya. Lihat (seperti yang disarankan oleh @TomSwift di sini. Cara mengubah ukuran superview ke cocokkan semua subview dengan autolayout? ).Untuk melakukannya, Anda harus memasukkan kode berikut dalam implementasi UITableViewCell kustom Anda (terima kasih kepada @Adrian).
Mencampur jawaban @smileyborg dengan ini seharusnya bekerja.
sumber
systemLayoutSizeFittingSize
perlu dipanggil pada contentView, bukan cellSebuah gotcha yang cukup penting, saya hanya berlari ke posting sebagai jawaban.
Jawaban @ smileyborg sebagian besar benar. Namun, jika Anda memiliki kode apa pun dalam
layoutSubviews
metode kelas sel khusus Anda, misalnya mengaturpreferredMaxLayoutWidth
, maka tidak akan dijalankan dengan kode ini:Itu membingungkan saya untuk sementara waktu. Kemudian saya menyadari itu karena itu hanya memicu layoutSubviews pada
contentView
, bukan sel itu sendiri.Kode kerja saya terlihat seperti ini:
Perhatikan bahwa jika Anda membuat sel baru, saya cukup yakin Anda tidak perlu menelepon
setNeedsLayout
karena sudah diatur. Dalam kasus di mana Anda menyimpan referensi ke sel, Anda mungkin harus menyebutnya. Apa pun itu seharusnya tidak menyakiti apa pun.Tip lain jika Anda menggunakan subclass sel tempat Anda mengatur hal-hal seperti
preferredMaxLayoutWidth
. Seperti @smileyborg menyebutkan, "sel tampilan tabel Anda belum memiliki lebarnya tetap pada lebar tampilan tabel". Ini benar, dan masalah jika Anda melakukan pekerjaan Anda di subkelas dan bukan di pengontrol tampilan. Namun Anda dapat dengan mudah mengatur bingkai sel pada titik ini menggunakan lebar tabel:Misalnya dalam perhitungan untuk tinggi:
(Saya kebetulan menyimpan sel khusus ini untuk digunakan kembali, tapi itu tidak relevan).
sumber
Dalam kasus orang masih mengalami masalah dengan ini. Saya menulis posting blog cepat tentang menggunakan Autolayout dengan UITableViews Memanfaatkan Autolayout Untuk Dynamic Cell Heights serta komponen open source untuk membantu menjadikan ini lebih abstrak dan lebih mudah diimplementasikan. https://github.com/Raizlabs/RZCellSizeManager
sumber
Selama tata letak Anda di sel Anda bagus.
Pembaruan: Anda harus menggunakan pengubahan ukuran dinamis yang diperkenalkan di iOS 8.
sumber
tableView:cellForRowAtIndexPath:
ditableView:heightForRowAtIndexPath:
sekarang?systemLayoutSizeFittingSize:
ditableView:cellForRowAtIndexPath:
dan cache hasilnya kemudian dan kemudian menggunakannya dalamtableView:heightForRowAtIndexPath:
bekerja dengan baik selama kendala setup dengan benar tentu saja!(untuk Xcode 8.x / Xcode 9.x baca di bagian bawah)
Waspadai masalah berikut di dalam Xcode 7.x, yang mungkin menjadi sumber kebingungan:
Interface Builder tidak menangani pengaturan sel ukuran otomatis dengan benar. Bahkan jika kendala Anda benar-benar valid, IB akan tetap mengeluh dan memberi Anda saran dan kesalahan yang membingungkan. Alasannya adalah bahwa IB tidak mau mengubah ketinggian baris karena kendala Anda menentukan (sehingga sel cocok dengan konten Anda). Sebagai gantinya, itu menjaga ketinggian baris tetap dan mulai menyarankan Anda mengubah batasan Anda, yang harus Anda abaikan .
Misalnya, bayangkan Anda telah mengatur semuanya dengan baik, tidak ada peringatan, tidak ada kesalahan, semua berfungsi.
Sekarang jika Anda mengubah ukuran font (dalam contoh ini saya mengubah ukuran font label deskripsi dari 17.0 ke 18.0).
Karena ukuran font meningkat, label sekarang ingin menempati 3 baris (sebelum itu menempati 2 baris).
Jika Interface Builder berfungsi seperti yang diharapkan, itu akan mengubah ukuran tinggi sel untuk mengakomodasi tinggi label baru. Namun apa yang sebenarnya terjadi adalah bahwa IB menampilkan ikon kesalahan tata letak merah otomatis dan menyarankan Anda memodifikasi prioritas pelukan / kompresi.
Anda harus mengabaikan peringatan ini. Yang bisa Anda * lakukan adalah mengubah ketinggian baris secara manual (pilih Cell> Size Inspector> Row Height).
Saya mengubah ketinggian ini satu per satu (menggunakan stepper atas / bawah) sampai kesalahan panah merah hilang! (Anda benar-benar akan mendapatkan peringatan berwarna kuning, pada titik mana lanjutkan dan lakukan 'perbarui frame', semuanya akan berfungsi).
* Perhatikan bahwa Anda tidak benar-benar harus menyelesaikan kesalahan merah atau peringatan kuning ini di Interface Builder - saat runtime, semuanya akan berfungsi dengan benar (bahkan jika IB menunjukkan kesalahan / peringatan). Pastikan saja saat runtime di log konsol Anda tidak mendapatkan kesalahan AutoLayout.
Sebenarnya berusaha untuk selalu memperbarui tinggi baris di IB sangat menjengkelkan dan kadang-kadang hampir tidak mungkin (karena nilai fraksional).
Untuk mencegah peringatan / kesalahan IB yang mengganggu, Anda dapat memilih tampilan yang terlibat dan
Size Inspector
untuk propertiAmbiguity
pilihVerify Position Only
Xcode 8.x / Xcode 9.x tampaknya (kadang-kadang) melakukan sesuatu yang berbeda dari Xcode 7.x, tetapi masih salah. Sebagai contoh bahkan ketika
compression resistance priority
/hugging priority
diatur ke diperlukan (1000), Interface Builder dapat meregangkan atau klip label agar sesuai dengan sel (alih-alih mengubah ukuran tinggi sel agar sesuai dengan label). Dan dalam kasus seperti itu bahkan mungkin tidak menampilkan peringatan atau kesalahan AutoLayout. Atau kadang-kadang ia melakukan apa yang dilakukan Xcode 7.x, dijelaskan di atas.sumber
Untuk mengatur dimensi otomatis untuk tinggi baris & perkiraan tinggi baris, pastikan langkah-langkah berikut untuk membuat, dimensi otomatis efektif untuk tata letak tinggi sel / baris.
UITableViewAutomaticDimension
ke rowHeight & estimasiRowHeightheightForRowAt
dan mengembalikan nilaiUITableViewAutomaticDimension
ke sana)-
Sasaran C:
Cepat:
Untuk contoh label di UITableviewCell
Catatan : Jika Anda memiliki lebih dari satu label (UIElements) dengan panjang dinamis, yang harus disesuaikan sesuai dengan ukuran kontennya: Sesuaikan 'Prioritas Pelukan Konten dan Ketahanan Kompresi` untuk label yang ingin Anda ekspansi / kompres dengan prioritas lebih tinggi.
sumber
tableView: heightForRow
sumber data.tableView: heightForRow
. (untuk iOS 10-tableView: heightForRow
diperlukan)tableView: heightForRow
..if (indexPath.row == 0) { return 100} else { return UITableView.automaticDimension }
Seperti @ Bob-Spryn saya bertemu dengan gotcha yang cukup penting sehingga saya memposting ini sebagai jawaban.
Saya berjuang dengan jawaban @ smileyborg untuk sementara waktu. Gotcha yang saya temui adalah jika Anda telah mendefinisikan sel prototipe Anda di IB dengan elemen tambahan (
UILabels
,,UIButtons
dll.) Di IB ketika Anda membuat instance sel dengan [[YourTableViewCellClass alloc] init]
itu tidak akan instantiate semua elemen lain dalam sel itu kecuali Anda sudah kode tertulis untuk melakukan itu. (Saya memiliki pengalaman serupa denganinitWithStyle
.)Untuk membuat storyboard instantiate semua elemen tambahan dapatkan sel Anda dengan
[tableView dequeueReusableCellWithIdentifier:@"DoseNeeded"]
(Bukan[tableView dequeueReusableCellWithIdentifier:forIndexPath:]
karena ini akan menyebabkan masalah yang menarik.) Ketika Anda melakukan ini semua elemen yang Anda tetapkan dalam IB akan instantiated.sumber
Tampilan Tabel Dinamis, Tinggi Sel, dan Tata Letak Otomatis
Cara yang baik untuk menyelesaikan masalah dengan Tata Letak Otomatis storyboard:
sumber
sumber
"Solusi" lain: lewati semua frustrasi ini dan gunakan UIScrollView sebagai gantinya untuk mendapatkan hasil yang terlihat dan terasa identik dengan UITableView.
Itu adalah "solusi" yang menyakitkan bagi saya, setelah memasukkan total 20 + jam sangat frustasi mencoba membangun sesuatu seperti apa yang disarankan smileyborg dan gagal selama berbulan-bulan dan tiga versi rilis App Store.
Menurut saya, jika Anda benar-benar membutuhkan dukungan iOS 7 (bagi kami, itu penting) maka teknologinya terlalu rapuh dan Anda akan mencabut rambut Anda saat mencoba. Dan bahwa UITableView benar-benar berlebihan secara umum kecuali jika Anda menggunakan beberapa fitur pengeditan baris lanjutan dan / atau benar-benar perlu mendukung 1000 + "baris" (di aplikasi kami, secara realistis tidak pernah lebih dari 20 baris).
Bonus tambahan adalah bahwa kode menjadi sangat sederhana dibandingkan semua omong kosong delegasi dan bolak-balik yang datang dengan UITableView. Hanya satu loop kode di viewOnLoad yang terlihat elegan dan mudah dikelola.
Berikut ini beberapa kiat tentang cara melakukannya:
Menggunakan Storyboard atau file nib, buat ViewController dan tampilan root terkait.
Seret UIScrollView ke tampilan root Anda.
Tambahkan kendala atas, bawah, kiri dan kanan ke tampilan tingkat atas sehingga UIScrollView mengisi seluruh tampilan root.
Tambahkan UIView di dalam UIScrollView dan sebut "wadah". Tambahkan batasan atas, bawah, kiri dan kanan ke UIScrollView (induknya). TRIK KUNCI: Tambahkan juga batasan "Equal widths" untuk menautkan UIScrollView dan UIView.
CATATAN: Anda akan mendapatkan kesalahan "tampilan gulir memiliki tinggi konten yang dapat digulir ambigu" dan bahwa wadah Anda UIView harus memiliki tinggi 0 piksel. Tampaknya tidak ada kesalahan yang berarti ketika aplikasi sedang berjalan.
Buat file nib dan pengontrol untuk masing-masing "sel" Anda. Gunakan UIView bukan UITableViewCell.
Di root ViewController Anda, pada dasarnya Anda menambahkan semua "baris" ke wadah UIView dan secara terprogram menambahkan batasan yang menghubungkan tepi kiri dan kanan ke tampilan wadah, tepi atas mereka ke atas tampilan wadah (untuk item pertama) atau sebelumnya sel. Kemudian hubungkan sel terakhir ke dasar wadah.
Bagi kami, setiap "baris" ada di file nib. Jadi kodenya terlihat seperti ini:
Dan inilah kode untuk UITools.addViewToTop:
Satu-satunya "gotcha" yang saya temukan dengan pendekatan ini sejauh ini adalah bahwa UITableView memiliki fitur bagus header bagian "mengambang" di bagian atas tampilan saat Anda menggulir. Solusi di atas tidak akan melakukan itu kecuali Anda menambahkan lebih banyak pemrograman tetapi untuk kasus khusus kami fitur ini tidak 100% penting dan tidak ada yang memperhatikan ketika itu pergi.
Jika Anda ingin pembagi di antara sel-sel Anda, tambahkan saja UIView setinggi 1 piksel di bagian bawah "sel" khusus Anda yang terlihat seperti pembagi.
Pastikan untuk mengaktifkan "bouncing" dan "bouncing secara vertikal" agar kontrol refresh berfungsi dan sepertinya lebih seperti tampilan tabel.
TableView menunjukkan beberapa baris dan pembagi kosong di bawah konten Anda, jika tidak mengisi layar penuh sedangkan solusi ini tidak. Tetapi secara pribadi, saya lebih suka jika baris-baris kosong itu tidak ada di sana - dengan tinggi sel variabel selalu terlihat "bermasalah" bagi saya untuk memiliki baris kosong di sana.
Berikut ini berharap beberapa programmer lain membaca posting saya SEBELUM menghabiskan 20+ jam untuk mencari tahu dengan Table View di aplikasi mereka sendiri. :)
sumber
Saya harus menggunakan tampilan dinamis (pengaturan tampilan dan batasan oleh kode) dan ketika saya ingin mengatur lebar label preferMaxLayoutWidth adalah 0. Jadi saya salah tinggi sel.
Lalu saya menambahkan
sebelum dieksekusi
Setelah itu lebar label seperti yang diharapkan dan tinggi dinamis menghitung dengan benar.
sumber
Katakanlah Anda memiliki sel dengan subview, dan Anda ingin tinggi sel cukup tinggi untuk mencakup subview + padding.
1) Setel batasan bawah subview sama dengan cell.contentView minus padding yang Anda inginkan. Jangan menetapkan batasan pada sel atau cell.contentView itu sendiri.
2) Setel
rowHeight
properti tableView atautableView:heightForRowAtIndexPath:
keUITableViewAutomaticDimension
.3) Tetapkan
estimatedRowHeight
properti tableView atautableView:estimatedHeightForRowAtIndexPath:
tebakan ketinggian yang terbaik.Itu dia.
sumber
Jika Anda melakukan tata letak secara pemrograman, berikut adalah apa yang harus dipertimbangkan untuk iOS 10 menggunakan jangkar di Swift.
Ada tiga aturan / langkah
NOMOR 1: atur dua properti tampilan tabel ini pada viewDidLoad, yang pertama memberitahu tampilan tabel yang seharusnya mengharapkan ukuran dinamis pada sel mereka, yang kedua hanya untuk membiarkan aplikasi menghitung ukuran indikator scrollbar, sehingga membantu untuk kinerja.
NOMOR 2: Ini penting Anda perlu menambahkan subview ke kontenMelihat sel untuk tidak melihat, dan juga menggunakan layoutsmarginguide untuk melabuhkan subview ke atas dan bawah, ini adalah contoh kerja bagaimana melakukannya.
Buat metode yang akan menambahkan subview dan melakukan tata letak, sebut saja dengan metode init.
NOMOR 3: JANGAN HUBUNGI METODE:
Jika Anda melakukannya, Anda akan menimpa implementasi Anda.
Ikuti 3 aturan ini untuk sel dinamis dalam tampilan tabel.
di sini adalah implementasi kerja https://github.com/jamesrochabrun/MinimalViewController
sumber
Jika Anda memiliki string yang panjang . mis. yang tidak memiliki line break. Maka Anda mungkin akan mengalami beberapa masalah.
Perbaikan "yang diduga" disebutkan oleh jawaban yang diterima dan beberapa jawaban lainnya. Anda hanya perlu menambahkan
Saya menemukan jawaban Suragh paling lengkap dan ringkas , karenanya tidak membingungkan.
Padahal tidak dijelaskan mengapa perubahan ini diperlukan. Ayo lakukan itu.
Masukkan kode berikut ke proyek.
Perhatikan bahwa saya belum menambahkan batasan ukuran . Saya hanya menambahkan centerX, batasan centerY. Tapi tetap saja labelnya akan berukuran benar Kenapa?
Karena
contentSize
.Untuk memproses ini dengan lebih baik, pertahankan langkah0 terlebih dahulu, kemudian beri komentar pada langkah 1-6. Biarkan
setupLayout()
tinggal. Amati perilakunya.Kemudian batalkan komentar step1, dan amati.
Kemudian batalkan komentar step2 dan amati.
Lakukan ini sampai Anda telah menghapus semua 6 langkah dan mengamati perilaku mereka.
Apa yang bisa disimpulkan dari semua ini? Faktor apa yang bisa mengubah
contenSize
?\n
maka lebar intrinsicContentSize akan menjadi lebar maksimum semua garis. Jika satu baris memiliki 25 karakter, yang lain memiliki 2 karakter dan yang lain memiliki 21 karakter maka lebar Anda akan dihitung berdasarkan 25 karakternumberOfLines
agar0
jika tidak, Anda tidak akan memiliki banyak baris. AndanumberOfLines
akan menyesuaikan tinggi intrinsicContentSize AndaMembuat penyesuaian: Bayangkan bahwa berdasarkan pada teks Anda, lebar intrinsicContentSize Anda adalah
200
tinggi100
, tetapi Anda ingin membatasi lebar pada wadah label apa yang akan Anda lakukan? Solusinya adalah mengaturnya ke lebar yang diinginkan. Anda melakukannya dengan mengaturpreferredMaxLayoutWidth
agar130
intrinsicContentSize baru Anda akan memiliki lebar kira-kira130
. Tingginya jelas akan lebih daripada100
karena Anda akan membutuhkan lebih banyak garis. Itu dikatakan jika kendala Anda diatur dengan benar maka Anda tidak perlu menggunakan ini sama sekali! Untuk lebih lanjut tentang itu lihat jawaban ini dan komentarnya. Anda hanya perlu menggunakanpreferredMaxLayoutWidth
jika Anda tidak memiliki kendala membatasi lebar / tinggi seperti dalam satu kata "jangan membungkus teks kecuali melebihipreferredMaxLayoutWidth
". Tetapi dengan kepastian 100% jika Anda mengatur yang terdepan / membuntuti dannumberOfLines
untuk0
kemudian Anda baik-baik saja! Singkatnya, sebagian besar jawaban di sini yang merekomendasikan penggunaannya SALAH! Anda tidak membutuhkannya. Membutuhkannya adalah tanda bahwa kendala Anda tidak diatur dengan benar atau Anda hanya tidak memiliki kendalaUkuran Font: Juga perhatikan bahwa jika Anda meningkatkan fontSize Anda maka tinggi intrinsicContentSize akan meningkat. Saya tidak menunjukkan itu dalam kode saya. Anda dapat mencobanya sendiri.
Jadi kembali ke contoh tableViewCell Anda:
Yang perlu Anda lakukan adalah:
numberOfLines
ke0
preferredMaxLayoutWidth
.sumber
Dalam kasus saya, saya harus membuat sel khusus dengan gambar yang berasal dari server dan dapat dari lebar dan tinggi. Dan dua UILabel dengan ukuran dinamis (baik lebar & tinggi)
saya telah mencapai hal yang sama di sini dalam jawaban saya dengan autolayout dan secara terprogram:
Pada dasarnya jawaban @smileyBorg di atas membantu tetapi systemLayoutSizeFittingSize tidak pernah bekerja untuk saya, Dalam pendekatan saya:
1. Tidak menggunakan properti perhitungan tinggi baris otomatis. 2.Tidak menggunakan perkiraan ketinggian. 3.Tidak perlu pembaruan Batasan yang tidak perlu. 4.Tidak menggunakan Lebar Tata Letak Max Pilihan Otomatis. 5. Tidak menggunakan systemLayoutSizeFittingSize (seharusnya menggunakan tetapi tidak bekerja untuk saya, saya tidak tahu apa yang dilakukannya secara internal), tetapi metode saya - (float) getViewHeight bekerja dan saya tahu apa yang dilakukannya secara internal.
Apakah mungkin untuk memiliki ketinggian yang berbeda dalam Sel UITableView ketika saya menggunakan beberapa cara berbeda untuk menampilkan sel?
sumber
Dalam kasus saya, padding itu karena ketinggian sectionHeader dan sectionFooter, di mana storyboard memungkinkan saya untuk mengubahnya ke minimum 1. Jadi dalam metode viewDidLoad:
sumber
Saya baru saja melakukan beberapa percobaan bodoh dengan nilai 2
rowHeight
danestimatedRowHeight
dan hanya berpikir itu mungkin memberikan beberapa wawasan debug:Jika Anda mengatur keduanya ATAU hanya mengatur,
estimatedRowHeight
Anda akan mendapatkan perilaku yang diinginkan:Disarankan agar Anda melakukan yang terbaik untuk mendapatkan perkiraan yang benar, tetapi hasil akhirnya tidak berbeda. Itu hanya akan mempengaruhi kinerja Anda.
Jika Anda hanya mengatur rowHeight yaitu hanya lakukan:
hasil akhir Anda tidak akan seperti yang diinginkan:
Jika Anda mengatur
estimatedRowHeight
ke 1 atau lebih kecil maka Anda akan macet terlepas darirowHeight
.Saya gagal dengan pesan kesalahan berikut:
sumber
Berkenaan dengan jawaban yang diterima oleh @smileyborg, saya telah menemukan
menjadi tidak dapat diandalkan dalam beberapa kasus di mana kendala bersifat ambigu. Lebih baik untuk memaksa mesin tata letak untuk menghitung ketinggian dalam satu arah, dengan menggunakan kategori pembantu pada UIView di bawah ini:
Di mana w: adalah lebar tampilan tabel
sumber
Cukup tambahkan dua fungsi ini di viewcontroller Anda, itu akan menyelesaikan masalah Anda. Di sini, daftar adalah array string yang berisi string Anda dari setiap baris.
sumber
sumber
Jika tinggi sel dinamis oleh konten, Anda harus menghitungnya dengan tepat dan kemudian mengembalikan nilai tinggi sebelum sel dirender. Cara mudah adalah menentukan metode penghitungan dalam kode sel tampilan tabel untuk pengontrol memanggil di metode delegasi tinggi sel tabel. Jangan lupa untuk menghitung lebar bingkai sel nyata (standarnya adalah 320) jika tingginya bergantung pada lebar tabel atau layar. Yaitu, dalam metode pendelegasian tinggi sel tabel, gunakan cell.frame untuk mengoreksi lebar sel terlebih dahulu, kemudian memanggil metode penghitungan tinggi yang ditentukan dalam sel untuk mendapatkan nilai yang sesuai dan mengembalikannya .
PS. Kode untuk menghasilkan objek sel dapat didefinisikan dalam metode lain untuk memanggil metode delegasi sel tampilan tabel yang berbeda.
sumber
UITableView.automaticDimension
dapat diatur melalui Interface Builder:Xcode> Storyboard> Pemeriksa Ukuran
Tampilan Tabel Sel> Tinggi Baris> Otomatis
sumber
solusi iOs7 + iOs8 di Swift
sumber
cellForRowAtIndexPath
, sel belum ditata pada saat ini.