Pengaturan Tinggi Baris Sel Kustom di storyboard tidak merespons

213

Saya mencoba menyesuaikan ketinggian sel untuk salah satu sel pada tampilan tabel saya. Saya menyesuaikan ukuran dari pengaturan "tinggi baris" di dalam "inspektur ukuran" sel yang dimaksud. Ketika saya menjalankan aplikasi di iPhone saya, sel memiliki ukuran default yang ditetapkan dari "ukuran baris" pada tampilan tabel.

Jika saya mengubah "ukuran baris" dari tampilan tabel maka ukuran semua sel berubah. Saya tidak ingin melakukan itu karena saya ingin ukuran khusus hanya untuk satu sel. Saya telah melihat banyak posting yang memiliki solusi terprogram untuk masalah ini, tetapi saya lebih suka melakukannya melalui storyboard, jika itu mungkin.

zirinisp
sumber

Jawaban:

295

Pada sel dinamis , rowHeightatur pada UITableView selalu mengesampingkan rowHeight sel individual.

Tetapi pada sel-sel statis , rowHeightset pada sel-sel individual dapat mengesampingkan UITableView.

Tidak yakin apakah itu bug, Apple mungkin sengaja melakukan ini?

pixelfreak
sumber
36
Jawaban yang benar # 3, dan khususnya karena jawaban ini berlaku untuk Interface Builder / Storyboards. Jika Anda memilih sel di IB, maka Size Inspektur menunjukkan Tinggi Baris di atas (dengan "kebiasaan" kotak centang), tetapi jika Anda memilih seluruh tabel melihat para Ukuran Inspektur menunjukkan Tinggi Baris di atas sana juga (tidak ada "kustom " pada kasus ini). Seperti yang dikatakan pixelfreak, hanya pengaturan tampilan tabel yang digunakan untuk sel dinamis. (Tidak yakin apakah itu disengaja)
Rhubarb
8
jawaban ini menyiratkan bahwa solusinya adalah dengan mengubah UITableViewkonten dari Dynamic Prototypesmenjadi Static Cells, saya melakukan itu, dan seluruh proyek saya meledak .. hampir terbunuh sendiri.
abbood
4
Apakah ada cara untuk mengambil nomor ini? Apakah satu-satunya cara menggali dalamnya adalah dengan menyelam ke papan cerita dan menariknya keluar dari sana?
Biclops
Ini jelas BUKAN bug, karena meja Anda Dinamis, jadi bagaimana sistem bisa tahu ke mana Anda pergi menggunakan masing-masing sel? Dan berapa kali masing-masing prototipe akan digunakan.
Vincent Bernier
Tampaknya juga ada masalah jika Anda awalnya mengatur tampilan tabel sebagai "sel statis" dan kemudian mengubahnya menjadi "prototipe dinamis." Saya punya masalah di mana bahkan metode delegasi untuk rowHeight diabaikan. Saya pertama kali mengatasinya dengan langsung mengedit storyboard XML, kemudian akhirnya hanya membangun kembali adegan storyboard dari awal, menggunakan prototipe dinamis dari awal.
Eric Goldberg
84

Jika Anda menggunakan UITableViewController, terapkan metode ini:

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

Dalam fungsi baris, Anda dapat memilih Tinggi. Sebagai contoh,

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
       return 100;
    } 
    else {
       return 60;
    }
}

Dalam contoh ini, tinggi baris pertama adalah 100 piksel, dan yang lainnya adalah 60 piksel.

Saya harap yang ini dapat membantu Anda.

Beber
sumber
2
Beber, apakah satu SELALU harus melakukan keduanya (centang Kustom dan edit nilai Tinggi Baris di papan cerita && tentukan di heightForRowAtIndexPath)?
marciokoko
Bisakah Anda membantu saya mengenai hal ini? Saya perlu memiliki sel dinamis dengan tinggi dinamis, tetapi jika saya menggunakan metode ini, apa pun yang saya kembalikan, semua sel akan menghilang. Kecuali pada iPhone 5 perangkat , tempat kerjanya seperti yang diharapkan. Bisakah kamu mengerti mengapa?
Ostmeistro
34

Untuk sel dinamis, rowHeightatur UITableViewselalu menimpa sel individual rowHeight.

Perilaku ini, IMO, bug. Kapan pun Anda harus mengelola UI di dua tempat, ia cenderung mengalami kesalahan. Misalnya, jika Anda mengubah ukuran sel di storyboard, Anda harus ingat untuk mengubahnya heightForRowAtIndexPath:juga. Sampai Apple memperbaiki bug, solusi terbaik saat ini adalah untuk menimpanya heightForRowAtIndexPath:, tetapi gunakan sel prototipe yang sebenarnya dari storyboard untuk menentukan ketinggian daripada menggunakan angka ajaib . Ini sebuah contoh:

- (CGFloat)tableView:(UITableView *)tableView 
           heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* In this example, there is a different cell for
       the top, middle and bottom rows of the tableView.
       Each type of cell has a different height.
       self.model contains the data for the tableview 
    */
    static NSString *CellIdentifier;
    if (indexPath.row == 0) 
        CellIdentifier = @"CellTop";
    else if (indexPath.row + 1 == [self.model count] )
        CellIdentifier = @"CellBottom";
    else
        CellIdentifier = @"CellMiddle";

    UITableViewCell *cell = 
              [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    return cell.bounds.size.height;
}

Ini akan memastikan setiap perubahan ketinggian sel prototipe Anda akan secara otomatis diambil pada saat runtime dan Anda hanya perlu mengelola UI Anda di satu tempat: storyboard.

memmons
sumber
2
Saya telah memposting jawaban dengan kode lengkap termasuk caching; lihat stackoverflow.com/a/16881312/292166
JosephH
1
Wow-wow-wow! Saya mengangkat jawaban, tetapi Waspadalah! Metode ini menyebabkan hukuman kinerja tidak hanya seperti yang dikatakan @rennan dalam komentar, itu juga menyebabkan meningkatnya alokasi memori pada setiap reloadData sesuatu seperti kebocoran memori! Ini diperlukan untuk menggunakan solusi lensovet di atas! Habiskan sehari untuk menangkap kebocoran memori ini!
skywinder
Tidak berfungsi di Swift, karena cell.bounds.size.height selalu mengembalikan 0,0
King-Wizard
1
Sel-sel belum ada pada saat sistem memanggil tableView Anda: heightForRowAtIndexPath metode. Anda seharusnya dapat menggunakan indexPath yang diberikan kepada Anda untuk mengindeks ke dalam model data Anda dan melihat jenis sel apa yang akan digunakan di sana, dan kemudian menghitung tinggi untuk sel itu dan mengembalikannya. Itu memungkinkan sistem untuk meletakkan sel dalam tabel sebelum membuat sel apa pun.
King-Wizard
1
Selain itu, Anda tidak boleh memanggil metode cellForRowAtIndexPath Anda sendiri. Tampilan tabel memiliki metode cellForRowAtIndexPath yang akan mengembalikan sel untuk jalur indeks jika saat ini terlihat di layar, tetapi sering jalur indeks itu tidak memiliki sel yang terkait dengannya.
King-Wizard
22

Saya telah membangun kode yang berisi berbagai jawaban / komentar yang mengisyaratkan agar ini berfungsi untuk storyboard yang menggunakan sel prototipe.

Kode ini:

  • Tidak memerlukan tinggi sel untuk ditetapkan di tempat lain selain tempat yang jelas di storyboard
  • Tembolok ketinggian karena alasan kinerja
  • Menggunakan fungsi umum untuk mendapatkan pengidentifikasi sel untuk jalur indeks untuk menghindari duplikasi logika

Berkat Answerserbot, Brennan, dan lensovet.

- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = nil;

    switch (indexPath.section)
    {
        case 0:
            cellIdentifier = @"ArtworkCell";
            break;
         <... and so on ...>
    }

    return cellIdentifier;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
    static NSMutableDictionary *heightCache;
    if (!heightCache)
        heightCache = [[NSMutableDictionary alloc] init];
    NSNumber *cachedHeight = heightCache[cellIdentifier];
    if (cachedHeight)
        return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    <... configure cell as usual...>
JosephH
sumber
Saya tahu ini adalah jawaban lama, tetapi apakah ada orang lain yang menemukan ini menghasilkan stack overflow? Ketika tampilan dimuat, saya mendapatkan refresh UISectionRowDataWithSection: tableViewRowData: yang memanggil tableView: heightForRowAtIndexPath: yang memanggil dequeueReusableCellWithIdentifier: yang memanggil [UISectionRowData ...] jadi saya memiliki stack overflow rekursif. Saya benar-benar ingin menggunakan solusi ini, tetapi sepertinya tidak berfungsi dengan iOS7.
sbaker
Tidak berfungsi di Swift, karena cell.bounds.size.height selalu mengembalikan 0,0
King-Wizard
Sel-sel belum ada pada saat sistem memanggil tableView Anda: heightForRowAtIndexPath metode. Anda seharusnya dapat menggunakan indexPath yang diberikan kepada Anda untuk mengindeks ke dalam model data Anda dan melihat jenis sel apa yang akan digunakan di sana, dan kemudian menghitung tinggi untuk sel itu dan mengembalikannya. Itu memungkinkan sistem untuk meletakkan sel dalam tabel sebelum membuat sel apa pun.
King-Wizard
Selain itu, Anda tidak boleh memanggil metode cellForRowAtIndexPath Anda sendiri. Tampilan tabel memiliki metode cellForRowAtIndexPath yang akan mengembalikan sel untuk jalur indeks jika saat ini terlihat di layar, tetapi sering jalur indeks itu tidak memiliki sel yang terkait dengannya.
King-Wizard
@ Snow-Tiger Saya belum mencoba ini dengan cepat, tapi saya tidak mengerti komentar Anda. Saya tidak 'memanggil metode cellForRowAtIndexPath [saya] sendiri', dan sengaja saya tidak melakukannya. Saya juga sadar bahwa sel-sel tidak ada pada tabel waktu. Lihat: heightForRowAtIndexPath disebut, itulah inti dari kode ini, dan mengapa menggunakan dequeueReusableCellWithIdentifier untuk mendapatkan sel. Kode yang diposting dalam jawaban ini berfungsi. Entah ada sesuatu yang ekstra yang terjadi di swift, ada sesuatu yang tidak beres dalam konversi swift, atau sedang mencoba untuk memecahkan masalah yang berbeda yang dituju oleh pertanyaan / jawaban ini.
JosephH
19

Sebenarnya ada dua tempat di mana Anda perlu mengubah ke ketinggian baris, pertama sel (Anda sudah mengubahnya) dan sekarang pilih Table View dan periksa Size Inspector

Kristjan H.
sumber
di tableview (bukan cellview)> dalam tab inspektur ukuran> tinggi baris
iman kazemayni
Membuatku gila setiap kali aku melupakan detail ini. Tidak tahu mengapa menyesuaikan sel tidak memperbarui tableView secara otomatis saat menggunakan storyboard!
Scooter
11

Saya pikir itu adalah bug.

Coba sesuaikan ketinggian bukan oleh inspektur Utilitas tetapi dengan seret mouse di storyboard secara langsung.

Saya memecahkan masalah ini dengan metode ini.

Fogni
sumber
10

Jika Anda menggunakan swift, gunakan seperti ini. Jangan Gunakan storyboard untuk memilih tinggi baris. Secara terprogram mengatur ketinggian baris tabel seperti ini,

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 0 || indexPath.row == 1{
        let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
        self.tableView.rowHeight = 150
        cell.label1.text = "hiiiiii"
        cell.label2.text = "Huiiilllllll"
        return cell

    } else {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
        self.tableView.rowHeight = 60
        cell.label3.text = "llll"
        return cell
    }

}
Chathuranga Silva
sumber
Ini berfungsi, tetapi lebih umum yang dapat Anda lakukan:cell.sizeToFit(); self.tableView.rowHeight = cell.frame.height
Andy Chou
7

Anda bisa mendapatkan ketinggian UITableviewCell (di UITableviewController - sel statis) dari storyboard dengan bantuan baris berikut.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}
Hiren Panchal
sumber
6

Buka storyboard dalam tampilan XML dan coba edit rowHeightatribut elemen yang diinginkan.

Itu bekerja untuk saya ketika saya mencoba untuk mengatur baris kustom Tinggi untuk baris prototipe saya. Itu tidak bekerja melalui inspektur, tetapi melalui XML berfungsi.

Shtirlic
sumber
1
Saya mengklik kanan dan memilih "open as" -> "source code". RowHeight sudah diatur ke 120. Saya percaya storyboard memiliki bug di sana dan mengabaikan tinggi sel kustom.
zirinisp
6

Anda dapat menggunakan prototipe cellsdengan kebiasaan height, lalu memohon cellForRowAtIndexPath:dan mengembalikannya frame.height.:.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}
Henrik Hartz
sumber
Penambahan metode ini bekerja dengan sangat baik, dan sekarang menyimpan semua penyesuaian di storyboard sebagaimana mestinya.
daspianist
Sejauh ini solusi terbaik
TheJeff
4

Jika Anda ingin mengatur tinggi baris statis, Anda dapat melakukan sesuatu seperti ini:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}
Victor Palhares
sumber
4

Saya baru-baru ini bergulat dengan ini. Masalah saya adalah solusi yang diposting di atas menggunakanheightForRowAtIndexPath: metode ini akan bekerja untuk iOS 7.1 di Simulator tetapi kemudian benar-benar mengacaukan hasil dengan hanya beralih ke iOS 8.1.

Saya mulai membaca lebih banyak tentang sel ukuran sendiri (diperkenalkan di iOS 8, baca di sini ). Tampak jelas bahwa penggunaan UITableViewAutomaticDimensionakan membantu di iOS 8. Saya mencoba menggunakan teknik itu dan menghapus penggunaan heightForRowAtIndexPath:dan voila, sekarang berfungsi dengan sempurna di iOS 8 sekarang. Tetapi iOS 7 tidak. Apa yang harus saya lakukan? Saya diperlukan heightForRowAtIndexPath:untuk iOS 7 dan bukan untuk iOS 8.

Inilah solusi saya (dipangkas demi singkatnya) yang meminjam dari jawaban @ JosephephH diposting di atas:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 50.;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

    // ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
        return UITableViewAutomaticDimension;

    } else {
        NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
        static NSMutableDictionary *heightCache;
        if (!heightCache)
            heightCache = [[NSMutableDictionary alloc] init];
        NSNumber *cachedHeight = heightCache[cellIdentifier];
        if (cachedHeight)
            return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
    }
}

- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
    NSString * reuseIdentifier;
    switch (indexPath.row) {
        case 0:
            reuseIdentifier = EventTitleCellIdentifier;
            break;
        case 2:
            reuseIdentifier = EventDateTimeCellIdentifier;
            break;
        case 4:
            reuseIdentifier = EventContactsCellIdentifier;
            break;
        case 6:
            reuseIdentifier = EventLocationCellIdentifier;
            break;
        case 8:
            reuseIdentifier = NotesCellIdentifier;
            break;
        default:
            reuseIdentifier = SeparatorCellIdentifier;
            break;
    }

    return reuseIdentifier;
}

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO (@ "8.0") sebenarnya dari sekumpulan definisi makro yang saya gunakan yang saya temukan di suatu tempat (sangat membantu). Mereka didefinisikan sebagai:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
speby
sumber
2

Masalah yang sama terjadi ketika bekerja pada XCode 9 menggunakan Swift 4 .

Tambahkan AutoLayout untuk elemen UI di dalam Sel dan tinggi baris sel kustom akan bekerja sesuai yang ditentukan.

Murari Varma
sumber
1
Hai, tolong bagaimana Anda melakukan itu?
Back Packer
Anda hanya perlu menambahkan set kendala ke bagian bawah sel.
Justin
Ketika saya melakukan ini dan memilih "otomatis" di storyboard untuk tinggi sel, ia ingin mengatur semua ketinggian ke 44 di storyboard meskipun tampaknya benar ketika saya menjalankan. Bagaimana saya bisa menampilkan storyboard dengan benar?
David
1

Untuk sel dinamis, rowHeight yang diatur pada UITableView selalu mengesampingkan rowHeight masing-masing sel. Hitung saja tinggi dinamis jika konten di dalam baris.

Aks
sumber
0

Satu-satunya solusi nyata yang bisa saya temukan adalah ini

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
    return cell.frame.size.height;
}

Ini berfungsi dan memungkinkan untuk tidak memiliki saklar yang mengerikan / jika menduplikasi logika sudah ada di StoryBoard. Tidak yakin tentang kinerja tetapi saya kira ketika tiba dicellForRow: sel yang sudah diinisialisasi itu secepat. Tentu saja mungkin ada kerusakan jaminan di sini, tetapi sepertinya itu berfungsi dengan baik untuk saya di sini.

Saya juga memposting ini di sini: https://devforums.apple.com/message/772464

EDIT: Ortwin Gentz mengingatkan saya bahwa heightForRowAtIndexPath:akan dipanggil untuk semua sel TableView, tidak hanya yang terlihat. Kedengarannya logis karena iOS perlu mengetahui tinggi total untuk dapat menampilkan bilah gulir yang benar. Itu berarti mungkin baik-baik saja pada TableViews kecil (seperti 20 Cell) tetapi lupakan tentang itu pada 1000 Cell TableView.

Juga, trik sebelumnya dengan XML: Sama seperti komentar pertama untuk saya. Nilai yang benar sudah ada di sana.

StuFF mc
sumber
0

Ditambahkan sebagai komentar, tetapi memposting sebagai jawaban untuk visibilitas:

Tampaknya juga ada masalah jika Anda awalnya mengatur tampilan tabel sebagai "sel statis" dan kemudian mengubahnya menjadi "prototipe dinamis." Saya memiliki masalah di mana bahkan metode delegasi untuk heightForRowAtIndexPathdiabaikan. Saya pertama kali mengatasinya dengan langsung mengedit storyboard XML, kemudian akhirnya hanya membangun kembali adegan storyboard dari awal, menggunakan prototipe dinamis dari awal.

Eric Goldberg
sumber
0

Mengingat bahwa saya tidak menemukan solusi untuk masalah ini melalui Interface Builder, saya memutuskan untuk mengirim solusi terprogram untuk masalah di Swift menggunakan dua sel dinamis , meskipun pertanyaan awal meminta solusi melalui Interface Builder. Bagaimanapun saya pikir ini bisa bermanfaat untuk komunitas Stack Overflow:

    import UIKit

    enum SignInUpMenuTableViewControllerCellIdentifier: String {
       case BigButtonCell = "BigButtonCell"
       case LabelCell = "LabelCell"
    }

    class SignInUpMenuTableViewController: UITableViewController {
            let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
                              SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]

    private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
        if indexPath.row == 2 {
            return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
        } else {
            return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
        }
    }

   override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
   }

   ...

  }
Raja-Penyihir
sumber
Ini semua bagus dan bagus tapi kecuali saya salah membaca kode, ini hanya bergantung pada angka ajaib dan benar-benar mengabaikan nilai apa pun yang Anda tetapkan dalam IB untuk sel dinamis jadi ... bukan solusi untuk pertanyaan OP
Danny
0

Satu hal lain yang dapat Anda lakukan adalah pergi ke Document Outline Anda, pilih tampilan tabel bahwa sel prototipe Anda bersarang. Kemudian pada Pemeriksa Ukuran, ubah tampilan tabel Anda Ketinggian Baris ke nilai yang Anda inginkan dan hapus centang pada kotak Otomatis.

Amin Rezapour
sumber