Menggunakan Tata Letak Otomatis di UITableView untuk tata letak sel dinamis & ketinggian baris variabel


1501

Bagaimana Anda menggunakan Tata Letak Otomatis dalam UITableViewCelltampilan tabel untuk membiarkan konten dan subview setiap sel menentukan tinggi baris (sendiri / otomatis), sambil mempertahankan kinerja pengguliran yang mulus?


Berikut kode contoh di swift 2.3 github.com/dpakthakur/DynamicCellHeight
Deepak Thakur

Untuk memahami sebagian besar jawaban terkait memiliki UILabel multiline, Anda memerlukan pemahaman penuh tentang bagaimana contentSizedan preferredMaxLayoutWidthbekerja. Lihat di sini . Yang sedang berkata jika Anda mengatur kendala Anda dengan benar maka Anda tidak perlu preferredMaxLayoutWidthdan pada kenyataannya dapat menciptakan hasil yang tidak terduga.
Sayang

Jawaban:


2389

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 UITableViewCellsubclass, 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 sel contentView! 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:

Contoh ilustrasi kendala pada sel tampilan tabel.

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.

  • Jika Anda menambahkan batasan dalam kode, Anda harus melakukannya sekali dari dalam updateConstraintsmetode subkelas UITableViewCell Anda. Catatan yang updateConstraintsdapat dipanggil lebih dari sekali, jadi untuk menghindari menambahkan kendala yang sama lebih dari sekali, pastikan untuk memasukkan kode penambahan kendala Anda dalam updateConstraintscek untuk properti boolean seperti didSetupConstraints(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 menyesuaikan constantproperti pada beberapa kendala), letakkan ini di updateConstraintsluar pemeriksaan didSetupConstraintsagar 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.

  • Jangan menambahkan sel dengan set kendala yang sangat berbeda ke kumpulan reuse yang sama (yaitu menggunakan pengidentifikasi reuse yang sama) dan kemudian mencoba untuk menghapus kendala lama dan mengatur batasan baru dari awal setelah setiap dequeue. Mesin Tata Letak Otomatis internal tidak dirancang untuk menangani perubahan skala besar pada kendala, dan Anda akan melihat masalah kinerja yang sangat besar.

Untuk iOS 8 - Sel Self-Sizing

3. Aktifkan Estimasi Tinggi Baris

Untuk mengaktifkan sel tampilan tabel ukuran sendiri, Anda harus mengatur properti rowHeight tampilan tabel ke UITableViewAutomaticDimension. Anda juga harus menetapkan nilai ke properti taksiranRowHeight. Segera setelah kedua properti ini diatur, sistem menggunakan Tata Letak Otomatis untuk menghitung ketinggian aktual baris

Apple: Bekerja dengan Sel Tampilan Tabel Self-Sizing

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 rowHeightproperti pada tampilan tabel ke konstanta UITableViewAutomaticDimension. Kemudian, Anda hanya perlu mengaktifkan estimasi tinggi baris dengan menyetel estimatedRowHeightproperti tampilan tabel ke nilai bukan nol, misalnya:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0; // set to whatever your "average" cell height is

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 contentViewdibutuhkan 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 estimatedRowHeightproperti pada tampilan tabel (dalam viewDidLoadatau 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 menerapkan tableView: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 pada UITableViewCell's contentViewuntuk mengetahui berapa tinggi sel yang diperlukan. Gunakan UILayoutFittingCompressedSizeuntuk mendapatkan ukuran terkecil yang diperlukan agar sesuai dengan semua isi sel. Ketinggian kemudian dapat dikembalikan dari tableView: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 estimatedRowHeightproperti 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 menelepon tableView: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 estimatedRowHeightproperti pada tampilan tabel (dalam viewDidLoadatau 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 menerapkan tableView: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)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Determine which reuse identifier should be used for the cell at this 
    // index path, depending on the particular layout required (you may have
    // just one, or may have many).
    NSString *reuseIdentifier = ...;

    // Dequeue a cell for the reuse identifier.
    // Note that this method will init and return a new cell if there isn't
    // one available in the reuse pool, so either way after this line of 
    // code you will have a cell with the correct constraints ready to go.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

    // Configure the cell with content for the given indexPath, for example:
    // cell.textLabel.text = someTextForThisCell;
    // ...

    // Make sure the constraints have been set up for this cell, since it 
    // may have just been created from scratch. Use the following lines, 
    // assuming you are setting up constraints from within the cell's 
    // updateConstraints method:
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    // If you are using multi-line UILabels, don't forget that the 
    // preferredMaxLayoutWidth needs to be set correctly. Do it at this 
    // point if you are NOT doing it within the UITableViewCell subclass 
    // -[layoutSubviews] method. For example: 
    // cell.multiLineLabel.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds);

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Determine which reuse identifier should be used for the cell at this 
    // index path.
    NSString *reuseIdentifier = ...;

    // Use a dictionary of offscreen cells to get a cell for the reuse 
    // identifier, creating a cell and storing it in the dictionary if one 
    // hasn't already been added for the reuse identifier. WARNING: Don't 
    // call the table view's dequeueReusableCellWithIdentifier: method here 
    // because this will result in a memory leak as the cell is created but 
    // never returned from the tableView:cellForRowAtIndexPath: method!
    UITableViewCell *cell = [self.offscreenCells objectForKey:reuseIdentifier];
    if (!cell) {
        cell = [[YourTableViewCellClass alloc] init];
        [self.offscreenCells setObject:cell forKey:reuseIdentifier];
    }

    // Configure the cell with content for the given indexPath, for example:
    // cell.textLabel.text = someTextForThisCell;
    // ...

    // Make sure the constraints have been set up for this cell, since it 
    // may have just been created from scratch. Use the following lines, 
    // assuming you are setting up constraints from within the cell's 
    // updateConstraints method:
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    // Set the width of the cell to match the width of the table view. This
    // is important so that we'll get the correct cell height for different
    // table view widths if the cell's height depends on its width (due to 
    // multi-line UILabels word wrapping, etc). We don't need to do this 
    // above in -[tableView:cellForRowAtIndexPath] because it happens 
    // automatically when the cell is used in the table view. Also note, 
    // the final width of the cell may not be the width of the table view in
    // some cases, for example when a section index is displayed along 
    // the right side of the table view. You must account for the reduced 
    // cell width.
    cell.bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));

    // Do the layout pass on the cell, which will calculate the frames for 
    // all the views based on the constraints. (Note that you must set the 
    // preferredMaxLayoutWidth on multiline UILabels inside the 
    // -[layoutSubviews] method of the UITableViewCell subclass, or do it 
    // manually at this point before the below 2 lines!)
    [cell setNeedsLayout];
    [cell layoutIfNeeded];

    // Get the actual height required for the cell's contentView
    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    // Add an extra point to the height to account for the cell separator, 
    // which is added between the bottom of the cell's contentView and the 
    // bottom of the table view cell.
    height += 1.0;

    return height;
}

// NOTE: Set the table view's estimatedRowHeight property instead of 
// implementing the below method, UNLESS you have extreme variability in 
// your row heights and you notice the scroll indicator "jumping" 
// as you scroll.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Do the minimal calculations required to be able to return an 
    // estimated row height that's within an order of magnitude of the 
    // actual height. For example:
    if ([self isTallCellAtIndexPath:indexPath]) {
        return 350.0;
    } else {
        return 40.0;
    }
}

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 .


1
Meskipun ini bekerja dengan baik, saya menemukan di bawah perkiraan ukuran yang diperlukan sedikit (mungkin karena berbagai masalah pembulatan) dan saya harus menambahkan beberapa poin ke ketinggian akhir agar semua teks saya masuk ke dalam label
DBD

5
@ Alex311 Sangat menarik, terima kasih telah memberikan contoh ini. Saya melakukan sedikit pengujian pada akhir saya dan menulis beberapa komentar di sini: github.com/Alex311/TableCellWithAutoLayout/commit/…
smileyborg

3
Saya SANGAT merekomendasikan caching sel untuk setiap jenis pengenal penggunaan kembali sel. Setiap kali Anda menentukan ketinggian, Anda mengambil sel dari antrian yang tidak ditambahkan kembali. Caching dapat secara signifikan menurunkan berapa kali inisialisasi untuk sel tabel Anda disebut. Untuk beberapa alasan, ketika saya tidak melakukan caching, jumlah memori yang digunakan terus bertambah seperti yang saya gulir.
Alex311

1
Papan cerita, sebenarnya. Saya tidak berpikir itu berfungsi untuk sel prototipe (setidaknya tanpa instantiating seluruh VC). Dimungkinkan untuk menghindari kebocoran sama sekali dengan membuang di dalam heightForRowAtIndexPath, menyimpan sel dan mengembalikannya pada waktu berikutnya cellForRowAtIndexPathdisebut.
nschum

2
Apakah iOS8implementasinya masih direkomendasikan untuk iOS9dan iOS10, atau adakah pendekatan baru sejak jawaban ini dipublikasikan?
koen

175

Untuk iOS 8 di atas sangat sederhana:

override func viewDidLoad() {  
    super.viewDidLoad()

    self.tableView.estimatedRowHeight = 80
    self.tableView.rowHeight = UITableView.automaticDimension
}

atau

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

Tetapi untuk iOS 7, kuncinya adalah menghitung ketinggian setelah autolayout:

func calculateHeightForConfiguredSizingCell(cell: GSTableViewCell) -> CGFloat {
    cell.setNeedsLayout()
    cell.layoutIfNeeded()
    let height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingExpandedSize).height + 1.0
    return height
}

Penting

  • Jika banyak baris label, jangan lupa atur numberOfLineske 0.

  • Jangan lupa label.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)

Kode contoh lengkap ada di sini .


7
Saya pikir kita tidak perlu mengimplementasikan fungsi heightForRowAtIndexPath dalam kasus
OS8

Sebagai @eddwinpaz mencatat pada jawaban lain, penting bahwa kendala yang digunakan untuk mengunci ketinggian baris TIDAK termasuk margin.
Richard

1
+1 untuk "Jika beberapa baris label, jangan lupa atur numberOfLines ke 0" ini menyebabkan sel saya tidak dinamis dalam ukuran.
Ian-Fogelman

Sebut saya orang yang suka mengontrol, tetapi bahkan di zaman iOS 11 saya masih tidak suka menggunakan UITableViewAutomaticDimension. Memiliki beberapa pengalaman buruk dengannya di masa lalu. Karena itu, saya biasanya menggunakan solusi iOS7 yang tercantum di sini. Catatan William untuk tidak melupakan label.preferredMaxLayoutWidth di sini menyelamatkan saya.
Brian Sachetta

Ketika kami menggulir, label mulai muncul dalam beberapa baris dan ketinggian baris juga tidak bertambah
Karanveer Singh

94

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 UITableViewketinggian sel variabel. Saya mendasarkannya pada contoh UITableView dasar ini untuk Swift .

Proyek yang sudah selesai akan terlihat seperti ini:

masukkan deskripsi gambar di sini

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.

import UIKit
class MyCustomCell: UITableViewCell {
    @IBOutlet weak var myCellLabel: UILabel!
}

Kami akan menghubungkan outlet ini nanti.

Buka ViewController.swift dan pastikan Anda memiliki konten berikut:

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    // These strings will be the data for the table view cells
    let animals: [String] = [
        "Ten horses:  horse horse horse horse horse horse horse horse horse horse ",
        "Three cows:  cow, cow, cow",
        "One camel:  camel",
        "Ninety-nine sheep:  sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep baaaa sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep",
        "Thirty goats:  goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat "]

    // Don't forget to enter this in IB also
    let cellReuseIdentifier = "cell"

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // delegate and data source
        tableView.delegate = self
        tableView.dataSource = self

        // Along with auto layout, these are the keys for enabling variable cell height
        tableView.estimatedRowHeight = 44.0
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    // number of rows in table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.animals.count
    }

    // create a cell for each table view row
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell
        cell.myCellLabel.text = self.animals[indexPath.row]
        return cell
    }

    // method to run when table view cell is tapped
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }
}

Catatan penting:

  • Ini adalah dua baris kode berikut (bersama dengan tata letak otomatis) yang memungkinkan tinggi sel variabel:

    tableView.estimatedRowHeight = 44.0
    tableView.rowHeight = UITableViewAutomaticDimension

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.

masukkan deskripsi gambar di sini

Catatan penting:

  • Tata letak otomatis berfungsi bersama dengan dua baris kode yang penting yang saya sebutkan di atas. Jika Anda tidak menggunakan tata letak otomatis, itu tidak akan berfungsi.

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 menjadi cell(string yang sama dengan yang kita gunakan cellReuseIdentifierpada kode di atas.

masukkan deskripsi gambar di sini

Nol Garis untuk Label

Setel jumlah baris ke 0dalam Label Anda. Ini berarti multi-line dan memungkinkan label untuk mengubah ukuran sendiri berdasarkan kontennya.

masukkan deskripsi gambar di sini

Menghubungkan Outlet

  • Kendalikan kontrol dari Tampilan Tabel di storyboard ke tableViewvariabel dalam ViewControllerkode.
  • Lakukan hal yang sama untuk Label dalam sel Prototipe Anda ke myCellLabelvariabel di MyCustomCellkelas.

Jadi

Anda harus dapat menjalankan proyek Anda sekarang dan mendapatkan sel dengan ketinggian variabel.

Catatan

  • Contoh ini hanya berfungsi untuk iOS 8 dan setelahnya. Jika Anda masih perlu mendukung iOS 7 maka ini tidak akan berfungsi untuk Anda.
  • Sel khusus Anda sendiri di proyek mendatang Anda mungkin akan memiliki lebih dari satu label. Pastikan Anda menyematkan semuanya dengan benar sehingga tata letak otomatis dapat menentukan ketinggian yang tepat untuk digunakan. Anda mungkin juga harus menggunakan resistensi kompresi vertikal dan memeluk. Lihat artikel ini untuk lebih lanjut tentang itu.
  • Jika Anda tidak menyematkan tepi depan dan belakang (kiri dan kanan), Anda mungkin juga perlu mengatur label preferredMaxLayoutWidthsehingga 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 ke tableView:cellForRowAtIndexPathmetode:

     cell.myCellLabel.preferredMaxLayoutWidth = tableView.bounds.width

Lihat juga


Bukankah lebih baik untuk mengatur preferredMaxLayoutWidthmelawan sel contentSize? Dengan begitu jika Anda memiliki accessoryView atau digesek untuk diedit maka masih akan dipertimbangkan?
Sayang

@ Sayang, Anda mungkin benar. Saya belum mengikuti iOS selama sekitar satu tahun sekarang dan saya terlalu berkarat untuk menjawab Anda dengan baik sekarang.
Suragch

65

Saya membungkus solusi iOS7 @ smileyborg dalam sebuah kategori

Saya memutuskan untuk membungkus solusi pintar ini dengan @smileyborg ke dalam UICollectionViewCell+AutoLayoutDynamicHeightCalculationkategori.

Kategori ini juga memperbaiki masalah yang dijabarkan dalam jawaban @ wildmonkey (memuat sel dari nib dan systemLayoutSizeFittingSize:kembali CGRectZero)

Itu tidak memperhitungkan caching tetapi sesuai dengan kebutuhan saya sekarang. Jangan ragu untuk menyalin, menempel, dan meretasnya.

UICollectionViewCell + AutoLayoutDynamicHeightCalculation.h

#import <UIKit/UIKit.h>

typedef void (^UICollectionViewCellAutoLayoutRenderBlock)(void);

/**
 *  A category on UICollectionViewCell to aid calculating dynamic heights based on AutoLayout contraints.
 *
 *  Many thanks to @smileyborg and @wildmonkey
 *
 *  @see stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights
 */
@interface UICollectionViewCell (AutoLayoutDynamicHeightCalculation)

/**
 *  Grab an instance of the receiving type to use in order to calculate AutoLayout contraint driven dynamic height. The method pulls the cell from a nib file and moves any Interface Builder defined contrainsts to the content view.
 *
 *  @param name Name of the nib file.
 *
 *  @return collection view cell for using to calculate content based height
 */
+ (instancetype)heightCalculationCellFromNibWithName:(NSString *)name;

/**
 *  Returns the height of the receiver after rendering with your model data and applying an AutoLayout pass
 *
 *  @param block Render the model data to your UI elements in this block
 *
 *  @return Calculated constraint derived height
 */
- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block collectionViewWidth:(CGFloat)width;

/**
 *  Directly calls `heightAfterAutoLayoutPassAndRenderingWithBlock:collectionViewWidth` assuming a collection view width spanning the [UIScreen mainScreen] bounds
 */
- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block;

@end

UICollectionViewCell + AutoLayoutDynamicHeightCalculation.m

#import "UICollectionViewCell+AutoLayout.h"

@implementation UICollectionViewCell (AutoLayout)

#pragma mark Dummy Cell Generator

+ (instancetype)heightCalculationCellFromNibWithName:(NSString *)name
{
    UICollectionViewCell *heightCalculationCell = [[[NSBundle mainBundle] loadNibNamed:name owner:self options:nil] lastObject];
    [heightCalculationCell moveInterfaceBuilderLayoutConstraintsToContentView];
    return heightCalculationCell;
}

#pragma mark Moving Constraints

- (void)moveInterfaceBuilderLayoutConstraintsToContentView
{
    [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
        [self removeConstraint:constraint];
        id firstItem = constraint.firstItem == self ? self.contentView : constraint.firstItem;
        id secondItem = constraint.secondItem == self ? self.contentView : constraint.secondItem;
        [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:firstItem
                                                                     attribute:constraint.firstAttribute
                                                                     relatedBy:constraint.relation
                                                                        toItem:secondItem
                                                                     attribute:constraint.secondAttribute
                                                                    multiplier:constraint.multiplier
                                                                      constant:constraint.constant]];
    }];
}

#pragma mark Height

- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block
{
    return [self heightAfterAutoLayoutPassAndRenderingWithBlock:block
                                            collectionViewWidth:CGRectGetWidth([[UIScreen mainScreen] bounds])];
}

- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block collectionViewWidth:(CGFloat)width
{
    NSParameterAssert(block);

    block();

    [self setNeedsUpdateConstraints];
    [self updateConstraintsIfNeeded];

    self.bounds = CGRectMake(0.0f, 0.0f, width, CGRectGetHeight(self.bounds));

    [self setNeedsLayout];
    [self layoutIfNeeded];

    CGSize calculatedSize = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

    return calculatedSize.height;

}

@end

Contoh penggunaan:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MYSweetCell *cell = [MYSweetCell heightCalculationCellFromNibWithName:NSStringFromClass([MYSweetCell class])];
    CGFloat height = [cell heightAfterAutoLayoutPassAndRenderingWithBlock:^{
        [(id<MYSweetCellRenderProtocol>)cell renderWithModel:someModel];
    }];
    return CGSizeMake(CGRectGetWidth(self.collectionView.bounds), height);
}

Syukurlah kita tidak harus melakukan jazz ini di iOS8, tapi itu untuk sekarang!


2
Anda hanya bisa menggunakan: [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.
Adam Waite

1
Terima kasih! Ini bekerja. Kategori Anda sangat bagus. Inilah yang membuat saya sadar bahwa teknik ini juga bekerja dengan UICollectionViewsbaik.
Ricardo Sanchez-Saez

2
Bagaimana Anda melakukan ini menggunakan sel prototipe yang didefinisikan dalam storyboard?
David Potter

57

Inilah solusi saya:

Anda perlu memberitahu TableViewpara estimatedHeightsebelum beban pandangan. Kalau tidak, ia tidak akan bisa berperilaku seperti yang diharapkan.

Objektif-C

- (void)viewWillAppear:(BOOL)animated {
    _messageField.delegate = self;
    _tableView.estimatedRowHeight = 65.0;
    _tableView.rowHeight = UITableViewAutomaticDimension;
}

Perbarui ke Swift 4.2

override func viewWillAppear(_ animated: Bool) {
    tableView.rowHeight = UITableView.automaticDimension
    tableView.estimatedRowHeight = 65.0
}

2
Menyiapkan autolayout dengan benar, bersama dengan kode ini ditambahkan di viewDidLoad melakukan trik.
Bruce

1
tetapi bagaimana jika estimatedRowHeightbervariasi baris demi baris? haruskah saya melebihi atau di bawah perkiraan? gunakan ketinggian minimum atau maksimum yang saya gunakan tableView?
János

1
@ János ini adalah point of rowHeight. Untuk melakukan ini berperilaku seperti yang diharapkan, Anda perlu menggunakan konstrain tanpa margin dan sejajarkan dengan TableViewCell objek. dan saya berasumsi Anda menggunakan UITextView jadi Anda masih perlu menghapus autoscroll = false jika tidak maka ia akan mempertahankan tinggi dan Tinggi relatif tidak akan bertindak seperti yang diharapkan.
Eddwin Paz

1
Itu adalah solusi yang paling kuat. Khawatir bukan tentang 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.
SwiftArchitect

Berikut kode contoh di swift 2.3 github.com/dpakthakur/DynamicCellHeight
Deepak Thakur

47

Solusi yang diajukan oleh @smileyborg hampir sempurna. Jika Anda memiliki sel khusus dan Anda ingin satu atau lebih UILabeldengan ketinggian dinamis maka metode systemLayoutSizeFittingSize yang dikombinasikan dengan AutoLayout diaktifkan mengembalikan a CGSizeZerokecuali 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).

- (void)awakeFromNib{
    [super awakeFromNib];
    for (NSLayoutConstraint *cellConstraint in self.constraints) {
        [self removeConstraint:cellConstraint];
        id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
        id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;
        NSLayoutConstraint *contentViewConstraint =
        [NSLayoutConstraint constraintWithItem:firstItem
                                 attribute:cellConstraint.firstAttribute
                                 relatedBy:cellConstraint.relation
                                    toItem:seccondItem
                                 attribute:cellConstraint.secondAttribute
                                multiplier:cellConstraint.multiplier
                                  constant:cellConstraint.constant];
        [self.contentView addConstraint:contentViewConstraint];
    }
}

Mencampur jawaban @smileyborg dengan ini seharusnya bekerja.


systemLayoutSizeFittingSizeperlu dipanggil pada contentView, bukan cell
onmyway133

25

Sebuah gotcha yang cukup penting, saya hanya berlari ke posting sebagai jawaban.

Jawaban @ smileyborg sebagian besar benar. Namun, jika Anda memiliki kode apa pun dalam layoutSubviewsmetode kelas sel khusus Anda, misalnya mengatur preferredMaxLayoutWidth, maka tidak akan dijalankan dengan kode ini:

[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];

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:

TCAnswerDetailAppSummaryCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailAppSummaryCell"];
[cell configureWithThirdPartyObject:self.app];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;

Perhatikan bahwa jika Anda membuat sel baru, saya cukup yakin Anda tidak perlu menelepon setNeedsLayoutkarena 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:

self.summaryCell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailDefaultSummaryCell"];
CGRect oldFrame = self.summaryCell.frame;
self.summaryCell.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, self.tableView.frame.size.width, oldFrame.size.height);

(Saya kebetulan menyimpan sel khusus ini untuk digunakan kembali, tapi itu tidak relevan).



19

Selama tata letak Anda di sel Anda bagus.

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];

    return [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
}

Pembaruan: Anda harus menggunakan pengubahan ukuran dinamis yang diperkenalkan di iOS 8.


Ini bekerja untuk saya pada iOS7, adalah sekarang OK untuk menelepon tableView:cellForRowAtIndexPath:di tableView:heightForRowAtIndexPath:sekarang?
Semut

Ok jadi ini tidak bekerja, tapi ketika saya sebut systemLayoutSizeFittingSize:di tableView:cellForRowAtIndexPath:dan cache hasilnya kemudian dan kemudian menggunakannya dalam tableView:heightForRowAtIndexPath:bekerja dengan baik selama kendala setup dengan benar tentu saja!
Semut

Ini hanya berfungsi jika Anda menggunakan dequeueReusableCellWithIdentifier: alih-alih dequeueReusableCellWithIdentifier: forIndexPath:
Antoine

1
Saya benar-benar tidak berpikir memanggil tableView: cellForRowAtIndexPath: langsung adalah cara yang baik.
Itachi

19

(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.

masukkan deskripsi gambar di sini

Sekarang jika Anda mengubah ukuran font (dalam contoh ini saya mengubah ukuran font label deskripsi dari 17.0 ke 18.0).

masukkan deskripsi gambar di sini

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.

masukkan deskripsi gambar di sini

Anda harus mengabaikan peringatan ini. Yang bisa Anda * lakukan adalah mengubah ketinggian baris secara manual (pilih Cell> Size Inspector> Row Height).

masukkan deskripsi gambar di sini

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 Inspectoruntuk properti AmbiguitypilihVerify Position Only

masukkan deskripsi gambar di sini


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 prioritydiatur 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.


hai apakah mungkin untuk memberikan tinggi dinamis untuk sel, yang memiliki tampilan tabel dengan sel dengan konten sel dinamis.?
Jignesh B

18

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.

  • Tetapkan dan laksanakan tableview sumber Data dan delegasikan
  • Tetapkan UITableViewAutomaticDimensionke rowHeight & estimasiRowHeight
  • Menerapkan metode delegasi / sumber data (yaitu heightForRowAtdan mengembalikan nilai UITableViewAutomaticDimensionke sana)

-

Sasaran C:

// in ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

  @property IBOutlet UITableView * table;

@end

// in ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.table.dataSource = self;
    self.table.delegate = self;

    self.table.rowHeight = UITableViewAutomaticDimension;
    self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return UITableViewAutomaticDimension;
}

Cepat:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

Untuk contoh label di UITableviewCell

  • Tetapkan jumlah baris = 0 (& mode break baris = truncate tail)
  • Atur semua kendala (atas, bawah, kiri kanan) sehubungan dengan wadah superview / selnya.
  • Opsional : Tetapkan tinggi minimum untuk label, jika Anda ingin area vertikal minimum yang dicakup oleh label, bahkan jika tidak ada data.

masukkan deskripsi gambar di sini

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.


1
Terima kasih sepertinya solusi yang jelas dan sederhana tapi saya punya masalah. Saya tidak menggunakan label tetapi tampilan teks jadi saya perlu tinggi baris untuk meningkat ketika data ditambahkan. Masalah saya kemudian adalah meneruskan info ke heightForRowAt. Saya dapat mengukur ketinggian tampilan teks saya yang berubah, tetapi sekarang perlu mengubah tinggi baris. Harap menghargai bantuan
Jeremy Andrews

@JeremyAndrews Sure akan membantu Anda. Naikkan pertanyaan Anda dengan kode sumber yang telah Anda coba dan detail tentang masalah.
Krunal

Ini bekerja untuk saya tanpa menerapkan tableView: heightForRowsumber data.
Hemang

@Hemang - Karena iOS 11+ berfungsi tanpa tableView: heightForRow. (untuk iOS 10- tableView: heightForRowdiperlukan)
Krunal

1
@Hemang - Solusi tergantung pada definisi permintaan yang tepat. Di sini saya sudah solusi umum umum untuk permintaan Anda. Letakkan kondisi di dalam tableView: heightForRow..if (indexPath.row == 0) { return 100} else { return UITableView.automaticDimension }
Krunal

16

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,, UIButtonsdll.) 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 dengan initWithStyle.)

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.


15

Tampilan Tabel Dinamis, Tinggi Sel, dan Tata Letak Otomatis

Cara yang baik untuk menyelesaikan masalah dengan Tata Letak Otomatis storyboard:

- (CGFloat)heightForImageCellAtIndexPath:(NSIndexPath *)indexPath {
  static RWImageCell *sizingCell = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    sizingCell = [self.tableView dequeueReusableCellWithIdentifier:RWImageCellIdentifier];
  });

  [sizingCell setNeedsLayout];
  [sizingCell layoutIfNeeded];

  CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
  return size.height;
}

1
Ini sudah dibahas secara luas dalam jawaban yang diterima untuk pertanyaan ini.
smileyborg

2
Ya, saya tahu ... tetapi saya tidak ingin menggunakan PureLayout dan 'trik' dispatch_once banyak membantu saya, untuk menyelesaikannya hanya menggunakan Storyboard.
Mohnasm

13
tableView.estimatedRowHeight = 343.0
tableView.rowHeight = UITableViewAutomaticDimension

masukkan deskripsi gambar di sini


13

"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:

  1. Menggunakan Storyboard atau file nib, buat ViewController dan tampilan root terkait.

  2. Seret UIScrollView ke tampilan root Anda.

  3. Tambahkan kendala atas, bawah, kiri dan kanan ke tampilan tingkat atas sehingga UIScrollView mengisi seluruh tampilan root.

  4. 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.

  5. Buat file nib dan pengontrol untuk masing-masing "sel" Anda. Gunakan UIView bukan UITableViewCell.

  6. 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:

class YourRootViewController {

    @IBOutlet var container: UIView! //container mentioned in step 4

    override func viewDidLoad() {

        super.viewDidLoad()

        var lastView: UIView?
        for data in yourDataSource {

            var cell = YourCellController(nibName: "YourCellNibName", bundle: nil)
            UITools.addViewToTop(container, child: cell.view, sibling: lastView)
            lastView = cell.view
            //Insert code here to populate your cell
        }

        if(lastView != nil) {
            container.addConstraint(NSLayoutConstraint(
                item: lastView!,
                attribute: NSLayoutAttribute.Bottom,
                relatedBy: NSLayoutRelation.Equal,
                toItem: container,
                attribute: NSLayoutAttribute.Bottom,
                multiplier: 1,
                constant: 0))
        }

        ///Add a refresh control, if you want - it seems to work fine in our app:
        var refreshControl = UIRefreshControl()
        container.addSubview(refreshControl!)
    }
}

Dan inilah kode untuk UITools.addViewToTop:

class UITools {
    ///Add child to container, full width of the container and directly under sibling (or container if sibling nil):
    class func addViewToTop(container: UIView, child: UIView, sibling: UIView? = nil)
    {
        child.setTranslatesAutoresizingMaskIntoConstraints(false)
        container.addSubview(child)

        //Set left and right constraints so fills full horz width:

        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Leading,
            relatedBy: NSLayoutRelation.Equal,
            toItem: container,
            attribute: NSLayoutAttribute.Left,
            multiplier: 1,
            constant: 0))

        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Trailing,
            relatedBy: NSLayoutRelation.Equal,
            toItem: container,
            attribute: NSLayoutAttribute.Right,
            multiplier: 1,
            constant: 0))

        //Set vertical position from last item (or for first, from the superview):
        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Top,
            relatedBy: NSLayoutRelation.Equal,
            toItem: sibling == nil ? container : sibling,
            attribute: sibling == nil ? NSLayoutAttribute.Top : NSLayoutAttribute.Bottom,
            multiplier: 1,
            constant: 0))
    }
}

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. :)


11

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

[cell layoutSubviews];

sebelum dieksekusi

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

Setelah itu lebar label seperti yang diharapkan dan tinggi dinamis menghitung dengan benar.


9

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 rowHeightproperti tableView atau tableView:heightForRowAtIndexPath:ke UITableViewAutomaticDimension.

3) Tetapkan estimatedRowHeightproperti tableView atau tableView:estimatedHeightForRowAtIndexPath:tebakan ketinggian yang terbaik.

Itu dia.


7

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.

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 100

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.

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    setUpViews()
}

private func setUpViews() {

    contentView.addSubview(movieImageView)
    contentView.addSubview(descriptionLabel)
    let marginGuide = contentView.layoutMarginsGuide

    NSLayoutConstraint.activate([
        movieImageView.heightAnchor.constraint(equalToConstant: 80),
        movieImageView.widthAnchor.constraint(equalToConstant: 80),
        movieImageView.leftAnchor.constraint(equalTo: marginGuide.leftAnchor),
        movieImageView.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 20),

        descriptionLabel.leftAnchor.constraint(equalTo: movieImageView.rightAnchor, constant: 15),
        descriptionLabel.rightAnchor.constraint(equalTo: marginGuide.rightAnchor),
        descriptionLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: -15),
        descriptionLabel.topAnchor.constraint(equalTo: movieImageView.topAnchor)

        ])
}

Buat metode yang akan menambahkan subview dan melakukan tata letak, sebut saja dengan metode init.

NOMOR 3: JANGAN HUBUNGI METODE:

  override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    }

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


di Swift 5 UITableViewAutomaticDimension diubah namanya menjadi UITableView.automaticDimension
James Rochabrun

4

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

cell.myCellLabel.preferredMaxLayoutWidth = tableView.bounds.width

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.

import UIKit

class ViewController: UIViewController {

    lazy var label : UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.backgroundColor = .red
        lbl.textColor = .black
        return lbl
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // step0: (0.0, 0.0)
        print("empty Text intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step1: (29.0, 20.5)
        label.text = "hiiiii"
        print("hiiiii intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step2: (328.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints"
        print("1 translate intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step3: (992.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints translatesAutoresizingMaskIntoConstraints translatesAutoresizingMaskIntoConstraints"
        print("3 translate intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step4: (328.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints\ntranslatesAutoresizingMaskIntoConstraints\ntranslatesAutoresizingMaskIntoConstraints"
        print("3 translate w/ line breaks (but the line breaks get ignored, because numberOfLines is defaulted to `1` and it will force it all to fit into one line! intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step5: (328.0, 61.0)
        label.numberOfLines = 0
        print("3 translate w/ line breaks and '0' numberOfLines intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step6: (98.5, 243.5)
        label.preferredMaxLayoutWidth = 100
        print("3 translate w/ line breaks | '0' numberOfLines | preferredMaxLayoutWidth: 100 intrinsicContentSize: \(label.intrinsicContentSize)")

        setupLayout()
    }
    func setupLayout(){
        view.addSubview(label)
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }
}

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?

  1. Panjang Teks: Jika Anda memiliki teks yang lebih panjang maka lebar intrinsicContentSize Anda akan meningkat
  2. Jeda baris: Jika Anda menambahkan \nmaka 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 karakter
  3. Jumlah baris yang diizinkan: Anda harus mengatur numberOfLinesagar 0jika tidak, Anda tidak akan memiliki banyak baris. Anda numberOfLinesakan menyesuaikan tinggi intrinsicContentSize Anda
  4. Membuat penyesuaian: Bayangkan bahwa berdasarkan pada teks Anda, lebar intrinsicContentSize Anda adalah 200tinggi 100, tetapi Anda ingin membatasi lebar pada wadah label apa yang akan Anda lakukan? Solusinya adalah mengaturnya ke lebar yang diinginkan. Anda melakukannya dengan mengatur preferredMaxLayoutWidthagar 130intrinsicContentSize baru Anda akan memiliki lebar kira-kira 130. Tingginya jelas akan lebih daripada 100karena 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 menggunakan preferredMaxLayoutWidthjika 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 dan numberOfLinesuntuk 0kemudian 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 kendala

  5. Ukuran 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:

  • atur numberOfLineske0
  • membatasi label dengan benar ke margin / tepi
  • Tidak perlu diatur preferredMaxLayoutWidth.

1

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?


1

Dalam kasus saya, padding itu karena ketinggian sectionHeader dan sectionFooter, di mana storyboard memungkinkan saya untuk mengubahnya ke minimum 1. Jadi dalam metode viewDidLoad:

tableView.sectionHeaderHeight = 0
tableView.sectionFooterHeight = 0

1

Saya baru saja melakukan beberapa percobaan bodoh dengan nilai 2 rowHeightdan estimatedRowHeightdan hanya berpikir itu mungkin memberikan beberapa wawasan debug:

Jika Anda mengatur keduanya ATAU hanya mengatur, estimatedRowHeightAnda akan mendapatkan perilaku yang diinginkan:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 1.00001 // MUST be greater than 1

Disarankan agar Anda melakukan yang terbaik untuk mendapatkan perkiraan yang benar, tetapi hasil akhirnya tidak berbeda. Itu hanya akan mempengaruhi kinerja Anda.

masukkan deskripsi gambar di sini


Jika Anda hanya mengatur rowHeight yaitu hanya lakukan:

tableView.rowHeight = UITableViewAutomaticDimension

hasil akhir Anda tidak akan seperti yang diinginkan:

masukkan deskripsi gambar di sini


Jika Anda mengatur estimatedRowHeightke 1 atau lebih kecil maka Anda akan macet terlepas dari rowHeight.

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 1 

Saya gagal dengan pesan kesalahan berikut:

Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'table view row height
must not be negative - provided height for index path (<NSIndexPath:
0xc000000000000016> {length = 2, path = 0 - 0}) is -1.000000'
    ...some other lines...

libc++abi.dylib: terminating with uncaught exception of type
NSException

1

Berkenaan dengan jawaban yang diterima oleh @smileyborg, saya telah menemukan

[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]

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:

-(CGFloat)systemLayoutHeightForWidth:(CGFloat)w{
    [self setNeedsLayout];
    [self layoutIfNeeded];
    CGSize size = [self systemLayoutSizeFittingSize:CGSizeMake(w, 1) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
    CGFloat h = size.height;
    return h;
}

Di mana w: adalah lebar tampilan tabel


0

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.

 func tableView(_ tableView: UITableView, 
   estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        tableView.rowHeight = self.calculateHeight(inString: list[indexPath.row])

    return (tableView.rowHeight) 
}

func calculateHeight(inString:String) -> CGFloat
{
    let messageString = input.text
    let attributes : [NSAttributedStringKey : Any] = [NSAttributedStringKey(rawValue: NSAttributedStringKey.font.rawValue) : UIFont.systemFont(ofSize: 15.0)]

    let attributedString : NSAttributedString = NSAttributedString(string: messageString!, attributes: attributes)

    let rect : CGRect = attributedString.boundingRect(with: CGSize(width: 222.0, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)

    let requredSize:CGRect = rect
    return requredSize.height
}

-1
swift 4

    @IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!
    @IBOutlet weak var tableView: UITableView!
    private var context = 1
 override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.addObserver(self, forKeyPath: "contentSize", options: [.new,.prior], context: &context)
    }
  // Added observer to adjust tableview height based on the content

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if context == &self.context{
            if let size = change?[NSKeyValueChangeKey.newKey] as? CGSize{
                print("-----")
                print(size.height)
                tableViewHeightConstraint.constant = size.height + 50
            }
        }
    }

//Remove observer
 deinit {

        NotificationCenter.default.removeObserver(self)

    }

-1

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.


-3

UITableView.automaticDimension dapat diatur melalui Interface Builder:

Xcode> Storyboard> Pemeriksa Ukuran

Tampilan Tabel Sel> Tinggi Baris> Otomatis

Inspektur ukuran


-4

solusi iOs7 + iOs8 di Swift

var cell2height:CGFloat=44

override func viewDidLoad() {
    super.viewDidLoad()
    theTable.rowHeight = UITableViewAutomaticDimension
    theTable.estimatedRowHeight = 44.0;
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell =  tableView.dequeueReusableCellWithIdentifier("myTableViewCell", forIndexPath: indexPath) as! myTableViewCell
    cell2height=cell.contentView.height
    return cell
}

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if #available(iOS 8.0, *) {
        return UITableViewAutomaticDimension
    } else {
        return cell2height
    }
}

note: systemLayoutSizeFittingSize tidak berfungsi dalam kasus saya
djdance

tinggi sel tidak benar cellForRowAtIndexPath, sel belum ditata pada saat ini.
Andrii Chernenko

di iOs7 itu adalah nilai tetap, yaitu berfungsi. Anda dapat mengatur di luar cellForRowAtIndexPath jika Anda mau
djdance
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.