Masalah batasan tata letak otomatis pada iOS7 di UITableViewCell


104

Saya menggunakan batasan tata letak otomatis secara terprogram untuk mengatur tata letak sel UITableView kustom saya dan saya menentukan ukuran sel dengan benar di tableView:heightForRowAtIndexPath:

Ini berfungsi dengan baik di iOS6 dan terlihat baik-baik saja di iOS7 juga

TETAPI ketika saya menjalankan aplikasi di iOS7, inilah jenis pesan yang saya lihat di konsol:

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2013-10-02 09:56:44.847 Vente-Exclusive[76306:a0b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
        "<NSLayoutConstraint:0xac4c5f0 V:|-(15)-[UIImageView:0xac47f50]   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
        "<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>",
        "<NSLayoutConstraint:0xac43680 V:[UIView:0xac4d0f0(1)]>",
        "<NSLayoutConstraint:0xac436b0 V:[UIView:0xac4d0f0]-(0)-|   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>

Dan memang ada salah satu kendala dalam daftar itu yang tidak saya inginkan:

"<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"

dan saya tidak dapat mengatur translatesAutoresizingMaskIntoConstraintsproperti dari contentViewke NO => itu akan mengacaukan seluruh sel.

44 adalah tinggi sel default tetapi saya menentukan ketinggian kustom saya dalam delegasi tampilan tabel jadi mengapa sel contentView memiliki batasan ini? Apa yang menyebabkan ini?

Di iOS6 itu tidak terjadi dan semuanya terlihat baik-baik saja di iOS6 dan iOS7.

Kode saya cukup besar jadi saya tidak akan mempostingnya di sini tetapi jangan ragu untuk meminta pastebin jika Anda membutuhkannya.

Untuk menentukan bagaimana saya melakukannya, pada inisialisasi sel:

  • Saya membuat semua label, tombol, dll
  • Saya menetapkan translatesAutoresizingMaskIntoConstraintsproperti mereka ke NO
  • Saya menambahkannya sebagai subview dari contentViewsel
  • Saya menambahkan batasan pada contentView

Saya juga sangat tertarik untuk memahami mengapa ini hanya terjadi di iOS7.


Berapa tinggi sel khusus Anda yang disetel?
Mike Pollard

tinggi sel khusus saya disetel ke 90
Alexis

Seorang kolega mengalami masalah yang sama kemarin, tetapi dengan lebar default 320 (untuk aplikasi iPad).
jrturton

Ada proyek contoh di sini yang mendemonstrasikan masalah yang sama ini: github.com/Alex311/TableCellWithAutoLayout Berikut adalah beberapa pengamatan saya tentangnya: github.com/Alex311/TableCellWithAutoLayout/commit/…
smileyborg

Saya mengalami kesalahan yang sama tetapi itu karena saya tidak pernah menginisialisasi sel prototipe tambahan yang saya gunakan untuk menemukan ketinggian sel khusus saya.
Steve Moser

Jawaban:


132

Saya mengalami masalah ini juga .. Tampaknya bingkai contentView tidak diperbarui sampai layoutSubviewsdipanggil namun bingkai sel diperbarui lebih awal sehingga bingkai contentView disetel {0, 0, 320, 44}pada saat batasan dievaluasi.

Setelah melihat contentView lebih detail, tampaknya autoresizingMasks tidak lagi disetel.

Menyetel autoresizingMask sebelum membatasi tampilan Anda dapat mengatasi masalah ini:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self)
    {
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        [self loadViews];
        [self constrainViews];
    }
    return self;
}

Ini melakukan pekerjaan, terima kasih. Apa yang bisa terjadi saat menggunakan gaya pengeditan?
Alexis

11
@ L14M333 Lihat kode yang saya posting dalam komentar ini di sini - pada dasarnya, Anda hanya dapat mengatur self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);sebelum Anda menambahkan batasan Anda, yang seharusnya menyelesaikan masalah.
smileyborg

2
autoresizingMask tidak berfungsi untuk saya: batasan awal sudah hilang tetapi 3 yang baru ditambahkan "<NSAutoresizingMaskLayoutConstraint: 0x8b79740 h = - & - v = - & - UITableViewCellContentView: 0x8b44010.height == UITableViewCellScrollView: 0x8b4a>", "<NSAutoresizingMaskLayoutConstraint: 0x8b7b9f0 h = - & - v = - & - UITableViewCellScrollView: 0x8b4a130.height == LibraryCell: 0x8ac19d0.height>", "<NSAutoresizing - & Vb7: [Library 0Cellonstraint: &c5908 = V 0x8ac19d0 (0)]> "
catamphetamine

1
Bekerja untuk saya juga, saya telah berjuang selama satu jam di atasnya! Terima kasih! <3
mokagio

2
Setelah menyingkirkan masalah tata letak otomatis lainnya (iOS 7 / iOS 8) saya menemukan bahwa menggunakan self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);berfungsi sebaik menggunakan self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;. Saya memasukkan ini ke dalam updateConstraintssebelum menambahkan batasan ke tampilan konten saya.
menguji

35

Ternyata ada yang salah dengan UITableViewCell dan UICollectionViewCell di iOS 7 yang menggunakan iOS 8 SDK.

Anda bisa memperbarui contentView sel saat sel digunakan kembali seperti ini:

Untuk Static UITableViewController:

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

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

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }

    //your code goes here

    return cell;
}

#endif
#endif

Karena Pengontrol Tampilan Tabel Statis sangat rapuh dan mudah rusak jika Anda menerapkan beberapa sumber data atau metode penghapusan - ada pemeriksaan yang akan memastikan bahwa kode ini hanya akan dikompilasi dan dijalankan di iOS 7

Ini serupa untuk UITableViewController dinamis standar:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }
    //your code goes here       
    return cell;
}

Untuk kasus ini kami tidak memerlukan pemeriksaan tambahan kompilasi, karena menerapkan metode ini diperlukan.

Idenya adalah sama untuk kedua kasus dan untuk UICollectionViewCell, seperti yang dikomentari di utas ini: Masalah autoresisasi bingkai UICollectionViewCell contentView dalam sel prototipe Storyboard (Xcode 6, iOS 8 SDK) terjadi saat berjalan di iOS 7 saja


1
Ini adalah jawaban terbaik, atau setidaknya solusi terbaik untuk saya. My Cell (aturan Autolayout) bekerja dengan baik di iOS8 dengan XCode6 dan bekerja dengan baik dengan iOS7 dan 6 dengan XCode 5. Saya memperbarui XCode ke XCode6 dan tidak lagi bekerja di iOS6 dan 7. Jadi, terima kasih !!!!
xarly

Ini tidak lagi menjadi masalah dengan Xcode 6.1. Selain itu, jangan gunakan NSFoundationVersionNumber, silakan lihat nshipster.com/swift-system-version-checking
onmyway133

1
@ onmyway133: Mengapa ini tidak menjadi masalah lagi di Xcode 6.1? Saya masih mengalami masalah meskipun saya menggunakan Xcode 6.1 dan iOS 8.1 SDK. Masalahnya hanya terjadi di iOS 7. Mengubah batas atau menyetel topeng autoresizing memecahkan masalah. Tetapi saya menggunakan pendekatan yang dinyatakan dalam jawaban yang paling banyak dipilih atau di komentarnya.
menguji

Ya, ini adalah jawaban terbaik berdasarkan googling 3 jam saya. "Solusi" serupa lainnya tidak menyediakan daftar lengkap cell.contentView.autoresizingMask. Hanya yang ini yang berfungsi untuk proyek iPad 7.1 saya yang dibuat di Xcode 6.
Golden Thumb

13

Karena sel digunakan kembali dan ketinggian dapat berubah berdasarkan konten, saya pikir secara umum akan lebih baik untuk mengatur prioritas jarak kurang dari yang dibutuhkan.

Dalam kasus Anda, UIImageView memiliki jarak 15 ke atas dan tampilan bawah memiliki jarak 0 ke bawah. Jika Anda menyetel prioritas batasan tersebut ke 999 (bukan 1000), aplikasi tidak akan mogok, karena batasan tidak diperlukan.

Setelah metode layoutSubviews dipanggil, sel akan memiliki ketinggian yang benar, dan batasan dapat dipenuhi secara normal.


Anda jenius! solusi yang bagus dan bersih terima kasih :)
Blacky

9

Saya masih belum menemukan solusi yang baik untuk storyboard ... Beberapa info juga ada di sini: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

Dari saran mereka di sana:

self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

Saya telah mendorong solusi saya:

  • klik kanan storyboard
  • Buka Sebagai -> Kode Sumber
  • cari string "44" di sana
  • itu akan menjadi seperti

.

<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
        <rect key="frame" x="0.0" y="22" width="320" height="44"/>

.

  • ganti rowHeight = "44" dengan rowHeight = "9999" dan tinggi = "44" dengan tinggi = "9999"
  • klik kanan storyboard
  • Buka Sebagai -> Pembuat Antarmuka
  • jalankan aplikasi Anda dan periksa hasilnya

Ini berhasil untuk saya. Saya telah membuat UITableViewController di storyboard di mana beberapa sel dibuat dari prototipe dan yang lainnya seluruhnya dalam kode dengan membuat instance kelas.
Atharva

3

Tingkatkan saja tinggi sel default. Sepertinya masalahnya adalah konten sel lebih besar dari ukuran sel default (awal), melanggar beberapa batasan non-negatif hingga sel diubah ukurannya ke ukuran sebenarnya.


Memang sel saya lebih tinggi dari ukuran default tetapi bagaimana bisa terjadi bahwa ukuran default digunakan sejak delegasi tableview mengimplementasikan tableView: heightForRowAtIndexPath:?
Alexis

Mungkin sel dibuat dengan ukuran default dan kemudian diubah ukurannya ke ukuran sebenarnya.
Vadim Yelagin

memang berhasil, tetapi mengapa tidak terjadi di iOS6?
Alexis

3
@jafar iOS 7 mengubah banyak hal di sekitar sel tampilan tabel. Di iOS 7, sekarang ada tampilan gulir (tipe UITableViewCellScrollView) di antara sel tampilan tabel dan tampilan konten; yang mungkin menjelaskan perbedaan antara iOS 6 dan 7 di sini.
smileyborg

3

Mungkin mengatur prioritas tampilan lebih besar dari 750 dan kurang dari 1000 dapat menyelesaikannya.

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",

2

Saya memiliki masalah yang sama. Solusi saya berdasarkan yang lain di atas:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // initialize my stuff
        [self layoutSubviews]; // avoid debugger warnings regarding constraint conflicts
    }
    return self;
}

Hormat kami, Alessandro


2
Dari dokumen Apple:You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.
Ricardo Sanchez-Saez

Saya ingin memulai agama berdoa untuk Anda. Saya telah mencari JAM-JAM mencoba untuk memperbaiki masalah ini, dan ini menyelesaikannya (serta mengatur contentView.bounds ke CGRectMake (0, 0, 99999, 99999);) - INI ADALAH BUG DALAM KODE APPLES. Jadi, saya dengan hormat tidak setuju dengan apple docs yang mengatakan jangan panggil fungsi itu. Apple, perbaiki omong kosongmu.
Ryan Copley

0

Saya juga menghadapi masalah ini dan tidak ada saran yang membantu. Dalam kasus saya, saya memiliki sel pemilihan ukuran, dan itu berisi collectionView di dalamnya (setiap sel collectionView berisi gambar ukuran penuh). Sekarang, tinggi ukuran sel sedikit lebih besar (60) dari collectionView (50) dan gambar di dalamnya (50). Karena tampilan collectionView tersebut memiliki batasan align bottom to superview dengan nilai 10. Hal itu membuat saya mendapat peringatan, dan satu-satunya cara untuk memperbaikinya adalah dengan membuat ketinggian sel sama dengan collectionView-nya.


0

Saya akhirnya tidak menggunakan UITableViewCell di desainer sama sekali ... Saya membuat tampilan kustom di sana dan menambahkannya ke tampilan konten sel secara terprogram ... Dengan beberapa kategori bantuan, juga tidak ada kode boilerplate ...


0

Jika berfungsi dengan baik di iOS8, dan mendapatkan peringatan di iOS7, Anda dapat mencari kode sumber storyboard, dan menemukan tableviewCell yang tepat, lalu menambahkan atribut rect setelah baris tableviewCell. Terima kasih kepada kuchumovn .

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
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.