ปัญหาข้อ จำกัด การจัดวางอัตโนมัติบน iOS7 ใน UITableViewCell


104

ฉันใช้ข้อ จำกัด การจัดวางอัตโนมัติโดยทางโปรแกรมเพื่อจัดวางเซลล์ UITableView ที่กำหนดเองของฉันและฉันกำหนดขนาดเซลล์อย่างถูกต้องใน tableView:heightForRowAtIndexPath:

มันทำงานได้ดีบน iOS6 และมันก็ดูดีใน iOS7 เช่นกัน

แต่เมื่อฉันเรียกใช้แอปบน iOS7 นี่คือประเภทของข้อความที่ฉันเห็นในคอนโซล:

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]>

และแน่นอนมีหนึ่งข้อ จำกัด ในรายการที่ผมไม่อยากไปนี้:

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

และฉันไม่สามารถตั้งค่าtranslatesAutoresizingMaskIntoConstraintsคุณสมบัติของเป็นcontentViewNO => มันจะทำให้เซลล์ทั้งหมดสับสน

44 เป็นความสูงของเซลล์เริ่มต้น แต่ฉันกำหนดความสูงที่กำหนดเองของฉันในมุมมองตารางมอบหมายเหตุใดเซลล์ contentView จึงมีข้อ จำกัด นี้ อะไรที่ทำให้เกิดสิ่งนี้?

ใน iOS6 จะไม่เกิดขึ้นและทุกอย่างดูดีทั้งบน iOS6 และ iOS7

รหัสของฉันค่อนข้างใหญ่ดังนั้นฉันจะไม่โพสต์ที่นี่ แต่อย่าลังเลที่จะขอ pastebin ถ้าคุณต้องการ

หากต้องการระบุวิธีที่ฉันทำในการเริ่มต้นเซลล์:

  • ฉันสร้างป้ายกำกับปุ่ม ฯลฯ ทั้งหมดของฉัน
  • ฉันตั้งค่าtranslatesAutoresizingMaskIntoConstraintsคุณสมบัติเป็น NO
  • ฉันเพิ่มเป็นมุมมองย่อยcontentViewของเซลล์
  • ฉันเพิ่มข้อ จำกัด ในไฟล์ contentView

ฉันยังสนใจที่จะทำความเข้าใจว่าทำไมสิ่งนี้จึงเกิดขึ้นเฉพาะบน iOS7 เท่านั้น


ความสูงของเซลล์ที่กำหนดเองของคุณตั้งค่าเป็นเท่าใด
Mike Pollard

ความสูงของเซลล์ที่กำหนดเองของฉันตั้งไว้ที่ 90
Alexis

เพื่อนร่วมงานมีปัญหาเดียวกันเมื่อวานนี้ แต่ความกว้างเริ่มต้นคือ 320 (สำหรับแอป iPad)
jrturton

มีโครงการตัวอย่างที่แสดงให้เห็นถึงปัญหาเดียวกันนี้: github.com/Alex311/TableCellWithAutoLayout นี่คือข้อสังเกตบางส่วนของฉันเกี่ยวกับเรื่องนี้: github.com/Alex311/TableCellWithAutoLayout/commit/…
smileyborg

ฉันพบข้อผิดพลาดเดียวกัน แต่เป็นเพราะฉันไม่เคยเริ่มต้นเซลล์ต้นแบบเพิ่มเติมที่ฉันใช้เพื่อค้นหาความสูงของเซลล์ที่กำหนดเองของฉัน
Steve Moser

คำตอบ:


132

ฉันมีปัญหานี้เช่นกัน .. ดูเหมือนว่าเฟรมของ contentView จะไม่ได้รับการอัปเดตจนกว่า layoutSubviewsจะถูกเรียกอย่างไรก็ตามเฟรมของเซลล์จะได้รับการอัปเดตก่อนหน้านี้โดยปล่อยให้เฟรมของ contentView ตั้งค่าเป็น{0, 0, 320, 44}ในเวลาที่มีการประเมินข้อ จำกัด

หลังจากดูรายละเอียด contentView แล้วดูเหมือนว่าจะไม่มีการตั้งค่า autoresizingMasks อีกต่อไป

การตั้งค่า autoresizingMask ก่อนที่คุณจะ จำกัด มุมมองของคุณสามารถแก้ไขปัญหานี้ได้:

- (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;
}

งานนี้ต้องขอบคุณคน จะเกิดอะไรขึ้นเมื่อใช้สไตล์การแก้ไข
Alexis

11
@ L14M333 ดูรหัสที่ฉันโพสต์ไว้ในความคิดเห็นนี้- โดยพื้นฐานแล้วคุณควรจะตั้งค่าได้self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);ก่อนที่จะเพิ่มข้อ จำกัด ซึ่งจะช่วยแก้ปัญหาได้
smileyborg

2
autoresizingMask ใช้ไม่ได้สำหรับฉัน: ข้อ จำกัด เริ่มต้นหายไป แต่มีการเพิ่ม 3 รายการใหม่ "<NSAutoresizingMaskLayoutConstraint: 0x8b79740 h = - & - v = - & - UITableViewCellContentView: 0x8b44010.height == UITableViewCellScrollView, 0x8b4a> "<NSAutoresizingMaskLayoutConstraint: 0x8b7b9f0 h = - & - v = - & - UITableViewCellScrollView: 0x8b4a130.height == LibraryCell: 0x8ac19d0.height>", "<NSAutoresizingMaskLayoutConstraint = 0x8b7 ไลบรารี: 0x8ac19d0 (0)]> "
catamphetamine

1
ได้ผลสำหรับฉันเช่นกันฉันดิ้นรนมานานกว่าหนึ่งชั่วโมงแล้ว! ขอบคุณ! <3
mokagio

2
หลังจากที่ได้รับการกำจัดของปัญหารูปแบบอื่นโดยอัตโนมัติ (iOS 7 / iOS 8) ผมพบว่าการใช้งานที่ดีที่สุดเท่าที่ใช้self.contentView.bounds = CGRectMake(0, 0, 99999, 99999); self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;ฉันใส่สิ่งนี้ไว้updateConstraintsก่อนที่จะเพิ่มข้อ จำกัด ในมุมมองเนื้อหาของฉัน
ทดสอบ

35

เห็นได้ชัดว่ามีบางอย่างผิดปกติกับ UITableViewCell และ UICollectionViewCell บน iOS 7 โดยใช้ iOS 8 SDK

คุณสามารถอัปเดต contentView ของเซลล์เมื่อเซลล์ถูกนำกลับมาใช้เช่นนี้:

สำหรับ 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

เนื่องจากตัวควบคุมมุมมองตารางแบบคงที่มีความเปราะบางและอาจพังได้ง่ายหากคุณใช้แหล่งข้อมูลหรือวิธีการลบบางอย่างจึงมีการตรวจสอบเพื่อให้แน่ใจว่าโค้ดนี้จะถูกคอมไพล์และรันบน iOS 7 เท่านั้น

มันคล้ายกับ UITableViewController มาตรฐานแบบไดนามิก:

-(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;
}

ในกรณีนี้เราไม่จำเป็นต้องตรวจสอบการคอมไพล์เพิ่มเติมเนื่องจากจำเป็นต้องใช้วิธีนี้

แนวคิดนี้เหมือนกันสำหรับทั้งสองกรณีและสำหรับ UICollectionViewCell เช่นความคิดเห็นในหัวข้อนี้: ปัญหาการปรับอัตโนมัติของเฟรมของ UICollectionViewCell contentView ในเซลล์ต้นแบบ Storyboard (Xcode 6, iOS 8 SDK) เกิดขึ้นเมื่อทำงานบน iOS 7 เท่านั้น


1
นี่คือคำตอบที่ดีที่สุดหรืออย่างน้อยก็เป็นทางออกที่ดีที่สุดสำหรับฉัน My Cell (กฎการจ่ายอัตโนมัติ) ทำงานได้ดีใน iOS8 กับ XCode6 และทำงานได้ดีกับ iOS7 และ 6 ด้วย XCode 5 ฉันอัปเดต XCode เป็น XCode6 และมันไม่ทำงานใน iOS6 และ 7 อีกต่อไปขอบคุณ !!!!
xarly

นี่ไม่ใช่ปัญหากับ Xcode 6.1 อีกต่อไป นอกจากนี้อย่าใช้ NSFoundationVersionNumber โปรดดูที่nshipster.com/swift-system-version-checking
onmyway133

1
@ onmyway133: เหตุใดจึงไม่เป็นปัญหาอีกต่อไปใน Xcode 6.1 ฉันยังคงมีปัญหาแม้ว่าฉันจะใช้ Xcode 6.1 และ iOS 8.1 SDK ปัญหานี้เกิดขึ้นเฉพาะบน iOS 7 การเปลี่ยนขอบเขตหรือการตั้งค่ามาสก์การปรับขนาดอัตโนมัติจะช่วยแก้ปัญหาได้ แต่ฉันใช้แนวทางที่ระบุไว้ในคำตอบที่ได้รับการโหวตมากที่สุดหรือในความคิดเห็นดังกล่าว
ทดสอบ

ใช่นี่คือคำตอบที่ดีที่สุดโดยพิจารณาจาก googling 3 ชั่วโมงของฉัน "โซลูชัน" อื่น ๆ ที่คล้ายกันไม่ได้ระบุรายการทั้งหมดของ cell.contentView.autoresizingMask อันนี้ใช้ได้กับโปรเจ็กต์ iPad 7.1 ของฉันที่สร้างใน Xcode 6 เท่านั้น
Golden Thumb

13

เนื่องจากเซลล์ถูกนำกลับมาใช้ใหม่และความสูงสามารถเปลี่ยนแปลงได้ตามเนื้อหาฉันคิดว่าโดยทั่วไปแล้วการกำหนดลำดับความสำคัญของระยะห่างให้น้อยกว่าที่กำหนดจะดีกว่า

ในกรณีของคุณ UIImageView มีระยะห่าง 15 ถึงด้านบนและมุมมองด้านล่างมีระยะห่างจาก 0 ถึงด้านล่าง หากคุณตั้งค่าลำดับความสำคัญของข้อ จำกัด เหล่านั้นเป็น 999 (แทนที่จะเป็น 1,000) แอปจะไม่ขัดข้องเนื่องจากไม่จำเป็นต้องใช้ข้อ จำกัด

เมื่อเรียกเมธอด layoutSubviews เซลล์จะมีความสูงที่ถูกต้องและสามารถตอบสนองข้อ จำกัด ได้ตามปกติ


คุณคืออัจฉริยะ! ทางออกที่ดีและสะอาดขอบคุณ :)
Blacky

9

ฉันยังไม่พบทางออกที่ดีสำหรับสตอรีบอร์ด ... มีข้อมูลบางส่วนอยู่ที่นี่: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

จากสิ่งที่พวกเขาแนะนำที่นั่น:

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

ฉันได้กระตุ้นวิธีแก้ปัญหาของฉัน:

  • คลิกขวาที่กระดานเรื่องราว
  • เปิดเป็น -> ซอร์สโค้ด
  • ค้นหาสตริง "44" ที่นั่น
  • มันจะเป็นยังไง

.

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

.

  • แทนที่ rowHeight = "44" ด้วย rowHeight = "9999" และ height = "44" ด้วย height = "9999"
  • คลิกขวาที่กระดานเรื่องราว
  • เปิดเป็น -> ตัวสร้างส่วนต่อประสาน
  • เรียกใช้แอปของคุณและตรวจสอบผลลัพธ์

สิ่งนี้ได้ผลสำหรับฉัน ฉันได้สร้าง UITableViewController ในสตอรี่บอร์ดซึ่งเซลล์บางเซลล์ถูกสร้างขึ้นจากต้นแบบและเซลล์อื่น ๆ ทั้งหมดในโค้ดโดยการสร้างอินสแตนซ์คลาส
Atharva

3

เพียงแค่เพิ่มความสูงของเซลล์เริ่มต้น ดูเหมือนว่าปัญหาคือเนื้อหาของเซลล์มีขนาดใหญ่กว่าขนาดเซลล์เริ่มต้น (เริ่มต้น) ซึ่งละเมิดข้อ จำกัด บางประการที่ไม่ใช่เชิงลบจนกว่าเซลล์จะถูกปรับขนาดเป็นขนาดจริง


อันที่จริงเซลล์ของฉันสูงกว่าขนาดเริ่มต้น แต่มันเกิดขึ้นได้อย่างไรที่จะใช้ขนาดเริ่มต้นเนื่องจากผู้แทนของ tableview ใช้ tableView: heightForRowAtIndexPath:?
Alexis

เซลล์อาจถูกสร้างขึ้นโดยมีขนาดเริ่มต้นจากนั้นปรับขนาดเป็นขนาดจริง
Vadim Yelagin

มันใช้งานได้จริง แต่ทำไมถึงไม่เกิดขึ้นบน iOS6 ล่ะ?
Alexis

3
@jafar iOS 7 เปลี่ยนหลายสิ่งหลายอย่างในเซลล์มุมมองตาราง ใน iOS 7 ตอนนี้มีมุมมองแบบเลื่อน (ประเภทUITableViewCellScrollView) อยู่ระหว่างเซลล์มุมมองตารางและ contentView ซึ่งอาจอธิบายความแตกต่างระหว่าง iOS 6 และ 7 ได้ที่นี่
smileyborg

3

อาจตั้งค่าลำดับความสำคัญของมุมมองที่ใหญ่กว่า 750 และน้อยกว่า 1,000 ก็สามารถแก้ปัญหาได้

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

2

ผมมีปัญหาเหมือนกัน. วิธีแก้ปัญหาของฉันขึ้นอยู่กับผู้อื่นข้างต้น:

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

ดีที่สุด Alessandro


2
จากเอกสารของ 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

ฉันต้องการเริ่มต้นศาสนาที่อธิษฐานถึงคุณ ฉันได้ค้นหา HOURS เพื่อพยายามแก้ไขปัญหานี้และสิ่งนี้จะช่วยแก้ไขได้ (เช่นเดียวกับการตั้งค่า contentView.bounds เป็น CGRectMake (0, 0, 99999, 99999);) - นี่เป็นจุดบกพร่องในการใช้รหัส ดังนั้นฉันไม่เห็นด้วยกับเอกสารของแอปเปิ้ลที่บอกว่าอย่าเรียกใช้ฟังก์ชันนั้น Apple แก้อึของคุณ
Ryan Copley

0

ฉันก็ประสบปัญหานี้เช่นกันและไม่มีคำแนะนำใดช่วยได้ ในกรณีของฉันฉันมีเซลล์การเลือกขนาดและมี collectionView อยู่ภายใน (ทุกเซลล์ collectionView มีภาพขนาดเต็ม) ตอนนี้ขนาดความสูงของเซลล์นั้นใหญ่กว่า collectionView (50) เล็กน้อยและรูปภาพที่อยู่ภายใน (50) เนื่องจากมุมมอง collectionView นั้นจัดแนวด้านล่างให้ตรงกับข้อ จำกัด superview ด้วยค่า 10 นั่นทำให้ฉันมีคำเตือนและวิธีเดียวที่จะแก้ไขได้คือทำให้ความสูงของเซลล์เหมือนกับ collectionView


0

ฉันลงเอยด้วยการไม่ใช้ UITableViewCell ในตัวออกแบบเลย ... ฉันสร้างมุมมองที่กำหนดเองและเพิ่มลงในมุมมองเนื้อหาของเซลล์โดยทางโปรแกรม ... ด้วยหมวดหมู่ความช่วยเหลือบางประเภทยังไม่มีรหัสต้นแบบ ...


0

หากใช้งานได้ดีใน iOS8 และรับคำเตือนใน iOS7 คุณสามารถค้นหาซอร์สโค้ดสตอรีบอร์ดและค้นหา tableviewCell ที่ถูกต้องจากนั้นต่อท้ายแอตทริบิวต์ rect หลังบรรทัด tableviewCell ขอขอบคุณที่kuchumovn

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.