Vấn đề ràng buộc bố cục tự động trên iOS7 trong UITableViewCell


104

Tôi đang sử dụng các ràng buộc bố cục tự động theo lập trình để bố trí các ô UITableView tùy chỉnh của mình và tôi đang xác định chính xác kích thước ô trong tableView:heightForRowAtIndexPath:

Nó chỉ làm việc tốt trên iOS6 và nó nhìn tốt trong iOS7 cũng

NHƯNG khi tôi chạy ứng dụng trên iOS7, đây là loại thông báo tôi thấy trong bảng điều khiển:

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

thực sự có một trong những hạn chế trong danh sách đó mà tôi không muốn:

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

và tôi không thể đặt thuộc translatesAutoresizingMaskIntoConstraintstính của là contentViewNO => nó sẽ làm rối toàn bộ ô.

44 là chiều cao ô mặc định nhưng tôi đã xác định độ cao tùy chỉnh của mình trong ủy nhiệm chế độ xem bảng, vậy tại sao ô contentView lại có ràng buộc này? Điều gì có thể gây ra điều này?

Trong iOS6, điều đó không xảy ra và mọi thứ đều ổn trên cả iOS6 và iOS7.

Code của mình khá lớn nên mình sẽ không đăng ở đây nhưng bạn cứ thoải mái xin pastebin nếu cần.

Để chỉ định cách tôi đang thực hiện, trên nhập số hóa ô:

  • Tôi tạo tất cả các nhãn, nút, v.v.
  • Tôi đặt translatesAutoresizingMaskIntoConstraintstài sản của họ thành KHÔNG
  • Tôi thêm chúng dưới dạng các lần xem phụ contentViewcủa ô
  • Tôi thêm các ràng buộc vào contentView

Tôi cũng rất muốn hiểu lý do tại sao điều này chỉ xảy ra trên iOS7.


Chiều cao ô tùy chỉnh của bạn được đặt thành bao nhiêu?
Mike Pollard

chiều cao ô tùy chỉnh của tôi được đặt thành 90
Alexis

Một đồng nghiệp đã gặp vấn đề tương tự ngày hôm qua, nhưng với chiều rộng mặc định là 320 (đối với ứng dụng iPad).
jrturton

Có một dự án mẫu ở đây chứng minh vấn đề này giống nhau: github.com/Alex311/TableCellWithAutoLayout Dưới đây là một số quan sát của tôi trên nó: github.com/Alex311/TableCellWithAutoLayout/commit/...
smileyborg

Tôi đã gặp phải lỗi tương tự nhưng đó là do tôi chưa bao giờ khởi tạo ô nguyên mẫu bổ sung mà tôi đang sử dụng để tìm chiều cao của ô tùy chỉnh của mình.
Steve Moser

Câu trả lời:


132

Tôi cũng gặp sự cố này .. Có vẻ như khung của contentView không được cập nhật cho đến khi layoutSubviewsđược gọi. Tuy nhiên, khung của ô được cập nhật trước đó, khiến khung của contentView được đặt thành {0, 0, 320, 44}tại thời điểm đánh giá các ràng buộc.

Sau khi xem xét chi tiết hơn về contentView, Có vẻ như autoresizingMasks không còn được đặt nữa.

Đặt autoresizingMask trước khi bạn giới hạn chế độ xem của mình có thể giải quyết vấn đề này:

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

Điều này thực hiện công việc cảm ơn người đàn ông. Điều gì có thể xảy ra khi sử dụng kiểu chỉnh sửa?
Alexis

11
@ L14M333 Xem mã tôi đã đăng trong nhận xét này ở đây - về cơ bản, bạn chỉ có thể thiết lập self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);trước khi thêm các ràng buộc của mình, điều này sẽ giải quyết được vấn đề.
smileyborg

2
autoresizingMask không hoạt động với tôi: ràng buộc ban đầu đã biến mất nhưng 3 cái mới được thêm vào "<NSAutoresizingMaskLayoutConstraint: 0x8b79740 h = - & - v = - & - UITableViewCellContentView: 0x8b44010.height == UITableViewCellScrollView: 0x8b4a130.heightView: 0x8b4a130.heightView: "<NSAutoresizingMaskLayoutConstraint: 0x8b7b9f0 h = - & - v = - & - UITableViewCellScrollView: 0x8b4a130.height == LibraryCell: 0x8ac19d0.height>", "<NSAutoresizingMaskLayoutCellScrollView: 0x8b4a130.height: 0x8ac19d0.height>" 0x8ac19d0 (0)]>"
catamphetamine

1
Cũng có tác dụng với tôi, tôi đã phải vật lộn cả tiếng đồng hồ về nó! Cảm ơn! <3
mokagio

2
Sau khi loại bỏ các vấn đề về bố cục tự động khác (iOS 7 / iOS 8), tôi phát hiện ra rằng việc sử dụng self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);hoạt động tốt như sử dụng self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;. Tôi đặt điều này vào updateConstraintstrước khi thêm các ràng buộc vào chế độ xem nội dung của mình.
thử nghiệm

35

Rõ ràng có điều gì đó không ổn với UITableViewCell và UICollectionViewCell trên iOS 7 sử dụng iOS 8 SDK.

Bạn có thể cập nhật contentView của ô khi ô được sử dụng lại như sau:

Đối với UITableViewController tĩnh:

#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

Vì Bộ điều khiển Chế độ xem Bảng tĩnh rất mỏng manh và có thể dễ dàng bị hỏng nếu bạn triển khai một số phương pháp nguồn dữ liệu hoặc cổng xóa - nên có các kiểm tra sẽ đảm bảo rằng mã này sẽ chỉ được biên dịch và chạy trên iOS 7

Nó tương tự đối với UITableViewController động tiêu chuẩn:

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

Đối với trường hợp này, chúng tôi không cần kiểm tra thêm quá trình biên dịch, vì việc triển khai phương pháp này là bắt buộc.

Ý tưởng giống nhau đối với cả hai trường hợp và đối với UICollectionViewCell, như đã nhận xét trong chủ đề này: Vấn đề tự động hóa khung của UICollectionViewCell contentView trong ô nguyên mẫu Storyboard (Xcode 6, iOS 8 SDK) chỉ xảy ra khi chạy trên iOS 7


1
Đây là câu trả lời tốt nhất, hoặc ít nhất là giải pháp tốt nhất cho tôi. My Cell (Quy tắc tự động thanh toán) hoạt động tốt trong iOS8 với XCode6 và hoạt động tốt với iOS7 và 6 với XCode 5. Tôi cập nhật XCode lên XCode6 và nó không còn hoạt động trong iOS6 và 7. Vì vậy, cảm ơn !!!!
xarly

Đây không còn là vấn đề với Xcode 6.1. Ngoài ra, không sử dụng NSFoundationVersionNumber, vui lòng xem nshipster.com/swift-system-version-checking
onmyway133

1
@ onmyway133: Tại sao đây không phải là vấn đề nữa trong Xcode 6.1? Tôi vẫn gặp sự cố ngay cả khi tôi sử dụng Xcode 6.1 và iOS 8.1 SDK. Sự cố chỉ xảy ra trên iOS 7. Thay đổi giới hạn hoặc đặt mặt nạ tự động khôi phục kích thước sẽ giải quyết được vấn đề. Nhưng tôi đã sử dụng cách tiếp cận được nêu trong câu trả lời được bình chọn nhiều nhất hoặc trong các bình luận của chúng.
thử nghiệm

Vâng, đây là câu trả lời tốt nhất dựa trên googling 3 giờ của tôi. Các "giải pháp" tương tự khác không cung cấp danh sách đầy đủ của cell.contentView.autoresizingMask. Chỉ cái này hoạt động cho dự án iPad 7.1 của tôi được tạo trong Xcode 6.
Golden Thumb.

13

Vì các ô đang được sử dụng lại và chiều cao có thể thay đổi dựa trên nội dung, tôi nghĩ nói chung sẽ tốt hơn nếu đặt mức độ ưu tiên của khoảng cách thành ít hơn yêu cầu.

Trong trường hợp của bạn, UIImageView có khoảng cách từ 15 đến đỉnh và khung nhìn dưới cùng có khoảng cách từ 0 đến dưới. Nếu bạn đặt mức độ ưu tiên của các ràng buộc đó thành 999 (thay vì 1000), ứng dụng sẽ không bị lỗi, vì các ràng buộc đó không bắt buộc.

Khi phương thức layoutSubviews được gọi, ô sẽ có chiều cao chính xác và các ràng buộc có thể được thỏa mãn bình thường.


Bạn là một thiên tài! giải pháp tốt và sạch sẽ cảm ơn bạn :)
Blacky

9

Tôi vẫn không tìm thấy giải pháp tốt cho bảng phân cảnh ... Một số thông tin cũng có ở đây: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

Từ những gì họ khuyên ở đó:

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

Tôi đã đưa ra giải pháp của mình:

  • nhấp chuột phải vào bảng phân cảnh
  • Mở dưới dạng -> Mã nguồn
  • tìm kiếm chuỗi "44" ở đó
  • nó sẽ giống như

.

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

.

  • thay thế rowHeight = "44" bằng rowHeight = "9999" và height = "44" bằng height = "9999"
  • nhấp chuột phải vào bảng phân cảnh
  • Mở dưới dạng -> Trình tạo giao diện
  • chạy ứng dụng của bạn và kiểm tra đầu ra

Điều này đã làm việc cho tôi. Tôi đã tạo một UITableViewController trong bảng phân cảnh nơi một số ô được tạo từ nguyên mẫu và những ô khác hoàn toàn bằng mã bằng cách khởi tạo một lớp.
Atharva

3

Chỉ cần tăng chiều cao ô mặc định. Có vẻ như vấn đề là nội dung của ô lớn hơn kích thước ô mặc định (ban đầu), vi phạm một số ràng buộc không tiêu cực cho đến khi ô được thay đổi kích thước thành kích thước thực của nó.


Thật vậy, các ô của tôi cao hơn kích thước mặc định nhưng làm thế nào nó xảy ra khi kích thước mặc định được sử dụng kể từ khi ủy nhiệm của tableview triển khai tableView: heightForRowAtIndexPath:?
Alexis

Có thể các ô được tạo với kích thước mặc định và sau đó được thay đổi kích thước thành kích thước thực.
Vadim Yelagin

thực sự nó hoạt động tốt, nhưng tại sao nó không xảy ra trên iOS6?
Alexis

3
@jafar iOS 7 đã thay đổi rất nhiều thứ xung quanh các ô xem bảng. Trên iOS 7, hiện có một dạng xem cuộn (thuộc loại UITableViewCellScrollView) ở giữa ô dạng xem bảng và chế độ xem nội dung; Điều đó có thể giải thích sự khác biệt giữa iOS 6 và 7 ở đây.
smileyborg

3

Có thể đặt mức độ ưu tiên của chế độ xem lớn hơn 750 và nhỏ hơn 1000 có thể giải quyết được.

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

2

Tôi đã từng gặp vấn đề tương tự. Giải pháp của tôi dựa trên những giải pháp khác ở trên:

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

Tốt nhất, Alessandro


2
Từ tài liệu của 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,

Tôi muốn bắt đầu một tôn giáo cầu nguyện với bạn. Tôi đã tìm kiếm HOURS trong GIỜ để cố gắng khắc phục sự cố này và điều này đã giải quyết được nó (cũng như đặt contentView.bounds thành CGRectMake (0, 0, 99999, 99999);) - ĐÂY LÀ BUG TRONG ÁP DỤNG MÃ. Vì vậy, tôi tôn trọng không đồng ý với các tài liệu táo nói rằng không gọi chức năng đó. Apple, sửa lỗi của bạn.
Ryan Copley

0

Tôi cũng đã đối mặt với vấn đề này và không có đề xuất nào giúp ích được. Trong trường hợp của tôi, tôi có ô chọn kích thước và nó chứa collectionView bên trong (mọi ô collectionView đều chứa hình ảnh kích thước đầy đủ). Bây giờ, kích thước ô lớn hơn một chút (60) so với collectionView (50) và hình ảnh bên trong nó (50). Do đó, chế độ xem collectionView đã căn chỉnh giới hạn từ dưới lên thành superview với giá trị là 10. Trường hợp đó, tôi nhận được một cảnh báo và cách duy nhất để khắc phục điều đó là làm cho chiều cao của ô giống với collectionView của nó.


0

Tôi đã kết thúc bằng cách hoàn toàn không sử dụng UITableViewCell trong trình thiết kế ... Tôi tạo ở đó chế độ xem tùy chỉnh và thêm nó vào chế độ xem nội dung của ô theo lập trình ... Với một số danh mục trợ giúp, cũng không có bảng mã ...


0

Nếu nó hoạt động tốt trong iOS8 và nhận được cảnh báo trong iOS7, bạn có thể tìm kiếm mã nguồn của bảng phân cảnh và tìm đúng tableviewCell, sau đó nối thuộc tính trực tràng sau dòng tableviewCell. Cảm ơn kuchumovn .

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.