Sự cố tự động hóa khung của UICollectionViewCell contentView trong ô nguyên mẫu Storyboard (Xcode 6, SDK iOS 8) chỉ xảy ra khi chạy trên iOS 7


158

Tôi đang sử dụng Xcode 6 Beta 3, SDK iOS 8. Xây dựng mục tiêu iOS 7.0 bằng Swift. Vui lòng tham khảo vấn đề của tôi từng bước với ảnh chụp màn hình bên dưới.

Tôi có một UICollectionView trong Storyboard. 1 Nguyên mẫu UICollectionViewCell chứa 1 nhãn ở giữa (không có quy tắc tự động hóa). Nền màu tím là để đánh dấu một nội dung được tạo trong thời gian chạy bởi Ô tôi đoán. Chế độ xem đó sẽ được thay đổi kích thước đúng dựa trên UICollectionViewLayoutDelegate của tôi, nhưng không phải trên iOS 7. Lưu ý rằng tôi đang sử dụng Xcode 6 và sự cố chỉ xảy ra trên iOS 7.

Khi tôi xây dựng ứng dụng trên iOS 8. Mọi thứ đều ổn.

Lưu ý: Màu tím là contentView , Blue là UIButton của tôi với góc tròn.

http://i.stack.imgur.com/uDNDY.png

Tuy nhiên, trên iOS 7, tất cả các Chế độ xem bên trong Ô đột nhiên co lại thành khung (0,0,50,50) và không bao giờ tuân thủ quy tắc Tự động hóa của tôi nữa.

http://i.stack.imgur.com/lOZH9.png

Tôi cho rằng đây là một lỗi trong SDK iOS 8 hoặc Swift hoặc có thể là Xcode?


Cập nhật 1: Sự cố này vẫn tồn tại trong Xcode 6.0.1 chính thức! Công việc tốt nhất xung quanh giống như những gì KoCMoHaBTa đã đề xuất bên dưới bằng cách đặt khung trong cellForItem của ô (Mặc dù vậy, bạn phải phân lớp ô của mình). Hóa ra đây là sự không tương thích giữa SDK iOS 8 và iOS 7 (kiểm tra câu trả lời của ecotax bên dưới được trích dẫn từ Apple).

Cập nhật 2: Dán mã này vào đầu cellForItem của bạn và mọi thứ sẽ ổn:

/** Xcode 6 on iOS 7 hot fix **/
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
/** End of Xcode 6 on iOS 7 hot fix **/

1
Tôi phát hiện ra rằng vấn đề này vẫn tồn tại trong Xcode 6 Beta 5. Có ai cũng gặp phải vấn đề này không?
thkeen

2
Tôi đang vật lộn với điều này ngay bây giờ trong dự án của tôi. iOS 7 và iOS 8 được xây dựng bằng Xcode 5 trông ổn. iOS 8 được xây dựng bằng Xcode 6 beta 6 có vẻ ổn. iOS 7 được xây dựng bằng Xcode 6 beta 6 đang gặp sự cố mà bạn đang mô tả. Sử dụng Reveal tôi có thể thấy rằng UICollectionViewCell của tôi đã được kích thước đúng. Nhưng nội dung của ô xem không được thay đổi kích thước, mặc dù là cha mẹ, UICollectionViewCell đã bật Tự động xem xét các mục. Kích thước của contentView được đặt thành những gì bảng phân cảnh có. Tôi không sử dụng autolayout trong dự án này. Dự án của tôi là hoàn toàn khách quan - c.
Del Brown

2
Tôi chỉ muốn thêm rằng vấn đề này vẫn tồn tại kể từ hạt giống GM Xcode 6 / iOS 8. Câu trả lời của @ DanielPlamann để buộc contentViewthay đổi kích thước với ô hoạt động tốt để khắc phục sự cố. Tôi đoán rằng trong iOS 8, Apple đã thay đổi điều gì đó về cách xử lý các lượt xem nội dung di động khi được tạo trong Interface Builder (dù sao vẫn là một hộp đen). Nhưng thực tế là nó thay đổi hành vi khi nhắm mục tiêu iOS 7 chắc chắn là một lỗi.
Stuart

Tương tự ở đây với Xcode 6 GM, bố trí tự động và một ô dựa trên nib. Tôi sửa nó bằng cách ghim các contentViewcạnh vào các cạnh của ô.
sergiou87

3
Tôi đã tải xuống xcode 6.1 nhưng vẫn thấy vấn đề tương tự trong trình giả lập.
Haitao Li

Câu trả lời:


169

contentView bị hỏng. Nó cũng có thể được sửa trong awakeFromNib

ObjC:

- (void)awakeFromNib {

    [super awakeFromNib];

    self.contentView.frame = self.bounds;
    self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}

Swift3:

override func awakeFromNib() {
    super.awakeFromNib()

    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}

3
Đã thực hiện thủ thuật mà không có self.contentView.frame = self.bound; Nghĩ rằng tôi cần nó? Dẫu sao cũng xin cảm ơn!
Michal Shatz

Xin chào Michal, đồng ý với bạn. Nhưng để chắc chắn 100%, nó sẽ hoạt động như thế nào trong các iOS tiếp theo tốt hơn để thêm nó tôi nghĩ.
Igor Palaguta

5
Tôi thích câu trả lời này nhưng bạn cần gọi [super awakeFromNib]; Ngoài ra, tôi đang suy nghĩ về việc thêm một kiểm tra cho iOS 7.1 trở xuống, bởi vì tôi không chắc việc thêm các mặt nạ thay đổi kích thước này ảnh hưởng đến hành vi mặc định trên iOS8 như thế nào.
GingerBreadMane

Nếu bạn không sử dụng ngòi hoặc bảng phân cảnh, điều này cũng hoạt động nếu bạn đặt nó trong applicationLayoutAttribution:
cetcet

Điều này không làm việc cho tôi. Tôi không sử dụng Autolayout !! Bất kỳ trợ giúp?
thatzprem

61

Tôi gặp phải vấn đề tương tự và nhờ Apple DTS giúp đỡ. Câu trả lời của họ là:

Trong iOS 7, lượt xem nội dung của các ô có kích thước thông qua mặt nạ tự động hóa. Trong iOS 8, điều này đã được thay đổi, các ô đã ngừng sử dụng mặt nạ tự động hóa và bắt đầu định cỡ kích thước chế độ xem nội dung trong layoutSubview. Nếu một ngòi được mã hóa trong iOS 8 và sau đó giải mã nó trên iOS 7, bạn sẽ có chế độ xem nội dung mà không cần mặt nạ tự động và không có cách nào khác để tự điều chỉnh kích thước. Vì vậy, nếu bạn từng thay đổi khung của ô, chế độ xem nội dung sẽ không tuân theo.

Các ứng dụng đang triển khai trở lại iOS 7 sẽ phải khắc phục điều này bằng cách tự định cỡ chế độ xem nội dung, thêm mặt nạ tự động hoặc thêm các ràng buộc.

Tôi đoán điều này có nghĩa là đó không phải là lỗi trong XCode 6, mà là sự không tương thích giữa SDK iOS 8 và SDK iOS 7, nó sẽ tấn công bạn nếu bạn nâng cấp lên Xcode 6, bởi vì nó sẽ tự động bắt đầu sử dụng SDK iOS 8.

Như tôi đã nhận xét trước đây, cách giải quyết Daniel Plamann đã mô tả các tác phẩm cho tôi. Mặc dù những cái được mô tả bởi Igor Palaguta và KoCMoHaBTa trông đơn giản hơn và dường như có ý nghĩa cho câu trả lời của Apple DTS, vì vậy tôi sẽ thử những điều đó sau.


Điều này thật thú vị, nhưng tôi vẫn hy vọng họ sửa nó. Hành vi này chỉ được giới thiệu trong Xcode 6 GM có thêm hỗ trợ iPhone 6. Nó đã hoạt động tốt trong các betas trước đó. Tôi thậm chí đã đưa một dự án trở lại bản beta trước đó sau khi tôi nhận thấy nó và nó hoạt động như mong đợi. Tôi hy vọng tất cả mọi người tập tin lỗi với Apple về vấn đề này.
arton

@arton Tôi đã nộp một báo cáo lỗi cùng ngày tôi đã yêu cầu DTS giúp đỡ. Nó đã được đóng lại dưới dạng Bản sao của 18312246. Không chắc điều này giúp được bao nhiêu.
ecotax

Tôi đã sử dụng công việc xung quanh bằng cách định cỡ ContentView và hoạt động cho tôi. - (CGSize) bộ sưu tậpViewContentSize {return CGSizeMake (self.collectionView.bound.size. Thong, self.collectionView.bound.size.height); }
Jesús Hurtado

60

Tôi gặp phải vấn đề tương tự và hy vọng rằng Apple sẽ khắc phục điều này với phiên bản Xcode tiếp theo. Trong khi đó tôi sử dụng một cách giải quyết. Trong UICollectionViewCelllớp con của tôi, tôi vừa ghi đè layoutSubviewsvà thay đổi kích thước nội dung thủ công trong trường hợp kích thước khác với collectionViewCellkích thước.

- (void)layoutSubviews
{
  [super layoutSubviews];

  BOOL contentViewIsAutoresized = CGSizeEqualToSize(self.frame.size, self.contentView.frame.size);

  if( !contentViewIsAutoresized) {
    CGRect contentViewFrame = self.contentView.frame;
    contentViewFrame.size = self.frame.size;
    self.contentView.frame = contentViewFrame;
  }
}

Vâng, tôi đã sử dụng một công việc tương tự xung quanh nhưng tôi đã làm nó trong cellForItem / cellForRow cũng hoạt động.
từ

1
Đây là giải pháp tốt nhất. Thêm phần này vào cellForItem / cellForRow sẽ gây ra các tạo phẩm lạ nếu bạn xoay thiết bị và kích thước ô thay đổi.
spybart

Chào! Tôi có một vấn đề với mã này. Lần đầu tiên, nội dung booleanViewIsAutoresized sẽ đúng nếu được tải từ bảng phân cảnh hoặc ô nguyên mẫu. Chỉ khi bạn thực hiện một reloadData, lần thứ hai nó sẽ chính xác. Vì vậy, bạn không thực sự cần phải kiểm tra kích thước. Thay vào đó chỉ cần làm: self.contentView.frame = self.bound;
thkeen

Xác nhận: chúng ta nên làm điều đó trong cellForItem hoặc cellForRow vì layoutSubview chỉ được gọi sau khi ô được trả về. Bất cứ điều gì bạn làm trước đó như vẽ công cụ sẽ bị tính toán sai.
thkeen

1
Hừm, có lẽ tốt hơn là đặt [cell layoutIfNeeded];trong cellForItem hoặc cellForRow?
wtori

38

Một giải pháp khác là đặt kích thước của mặt nạ nội dung và mặt nạ -collectionView:cellForItemAtIndexPath:tự động hóa như sau:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

     static NSString *cellID = @"CellID";

     UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

     // Set contentView's frame and autoresizingMask
     cell.contentView.frame = cell.bounds;
     cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;

     // Your custom code goes here

     return cell;
}

Điều này cũng hoạt động với Bố cục tự động, vì mặt nạ tự động thay đổi kích thước được dịch thành các ràng buộc.


2
Đây là một giải pháp ưu việt vì nó hoạt động với bất kỳ loại ô nào mà không cần phân lớp và không yêu cầu thay đổi ở nhiều nơi khi bạn đang sử dụng nhiều loại ô trong chế độ xem bộ sưu tập của mình.
nacross

6

Trong Xcode 6.0.1 contentView cho UICollectionViewCell bị hỏng cho các thiết bị iOS7. Nó cũng có thể được sửa bằng cách thêm các ràng buộc thích hợp vào UICollectionViewCell và contentView của nó trong các phương thức awakeFromNib hoặc init.

        UIView *cellContentView = self.contentView;
        cellContentView.translatesAutoresizingMaskIntoConstraints = NO;

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];

Chỉ điều này hoạt động ngay bây giờ, bạn phải làm điều đó chỉ dành cho iOS 8, và tôi phải gọi nó sau mỗi lần giải quyết! Nhưng đây cũng không phải là giải pháp lý tưởng vì nhiều lựa chọn không hoạt động như mong muốn ...
Renetik

Tốt nhất là sử dụng tính năng tự động thanh toán thực sự, với lỗi này, bạn tiết kiệm thời gian trớ trêu bằng cách sử dụng sự kiện tự động thanh toán trong trường hợp đơn giản ..
Renetik

Mặt nạ không hoạt động đối với tôi; tuy nhiên thiết lập các ràng buộc hoạt động!
entropid 18/03/2015

4

Điều này sẽ không hoạt động chính xác mà không có bất kỳ cách giải quyết nào khác được đề cập do lỗi trong Xcode 6 GM với cách Xcode biên dịch các tệp xib thành định dạng nib. Mặc dù tôi không thể nói chắc chắn 100% rằng nó liên quan đến Xcode và không liên quan đến thời gian chạy, tôi rất tự tin - đây là cách tôi có thể chỉ ra:

  1. Xây dựng + Chạy ứng dụng trong Xcode 5.1.
  2. Chuyển đến thư mục của ứng dụng giả lập và sao chép tệp .nib đã biên dịch cho xib mà bạn đang gặp vấn đề.
  3. Xây dựng + Chạy ứng dụng trong Xcode 6 GM.
  4. Dừng ứng dụng.
  5. Thay thế tệp .nib trong thư mục giả lập của ứng dụng mới được tạo bằng tệp .nib được tạo bằng Xcode 5.1
  6. Khởi chạy lại ứng dụng từ trình giả lập, KHÔNG phải từ Xcode.
  7. Di động của bạn được tải từ đó .nib sẽ hoạt động như mong đợi.

Tôi hy vọng tất cả những ai đọc câu hỏi này sẽ nộp Radar với Apple. Đây là một vấn đề HẤP DẪN và cần giải quyết trước khi phát hành Xcode cuối cùng.

Chỉnh sửa: Trong bài đăng của ecotax , tôi chỉ muốn cập nhật thông tin này để nói rằng hiện tại đã xác nhận sự khác biệt về hành vi giữa việc xây dựng trong iOS 8 so với iOS 7, nhưng không phải là lỗi. Bản hack của tôi đã khắc phục sự cố vì xây dựng trên iOS 7 đã thêm mặt nạ tự động vào chế độ xem nội dung cần thiết để thực hiện công việc này, điều mà Apple không còn bổ sung.


Tôi không chắc chắn liệu họ có thể phát hành một xCode khác với phiên bản GM hay không
Mabedan

Haha họ sẽ đi tù? = P Nhưng trong tất cả sự nghiêm túc, chắc chắn họ có thể. Họ đã có nhiều phiên bản GM cho Mavericks nếu bạn không nhớ. Nó không quá phổ biến nhưng nó có thể xảy ra.
Acey

4

Các câu trả lời trong bài viết này hoạt động, điều tôi không bao giờ hiểu là tại sao nó hoạt động.

Đầu tiên, có hai "quy tắc":

  1. Đối với các chế độ xem được tạo theo chương trình (Ví dụ [UIView new]), thuộc tính translatesAutoresizingMaskIntoConstraintsđược đặt thànhYES
  2. Chế độ xem được tạo trong trình tạo giao diện, với tính năng AutoLayout được bật, sẽ có thuộc tính translatesAutoresizingMaskIntoConstraintsđược đặt thànhNO

Quy tắc thứ hai dường như không áp dụng cho các chế độ xem cấp cao nhất mà bạn không xác định các ràng buộc cho. (Ví dụ: chế độ xem nội dung)

Khi nhìn vào một ô Storyboard, hãy chú ý rằng ô đó không bị contentViewlộ. Chúng tôi không "kiểm soát" contentView, Apple là.

Đi sâu vào mã nguồn bảng phân cảnh và xem cách contentViewxác định ô:

<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">

Bây giờ các cuộc phỏng vấn của tế bào (chú ý translatesAutoresizingMaskIntoConstraints="NO"):

<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NaT-qJ-npL" userLabel="myCustomLabel">

contentViewkhông được translatesAutoresizingMaskIntoConstraintsđặt thành NO. Thêm vào đó, nó thiếu định nghĩa bố cục, có thể vì những gì @ecotax nói .

Nếu chúng ta nhìn vào contentView, nó có mặt nạ tự động, nhưng không có định nghĩa cho nó: <autoresizingMask key="autoresizingMask"/>

Vì vậy, có hai kết luận:

  1. contentView translatesAutoresizingMaskIntoConstraintsđược đặt thành YES.
  2. contentView thiếu định nghĩa của một bố cục.

Điều này dẫn chúng ta đến hai giải pháp đã được nói đến.

Bạn có thể đặt mặt nạ tự động theo cách thủ công trong awakeFromNib:

self.contentView.frame = cell.bounds;
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Hoặc bạn có thể thiết lập contentView translatesAutoresizingMaskIntoConstraintsđể NOawakeFromNibvà xác định ràng buộc trong - (void)updateConstraints.


4

Đây là phiên bản Swift của câu trả lời của @ Igor được chấp nhận và cảm ơn vì người bạn trả lời tốt đẹp của bạn.

Đầu tiên Goto UICollectionViewCelllớp con của bạn và dán mã sau đây vì nó nằm trong lớp.

override func awakeFromNib() {
    super.awakeFromNib()
    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
}

Nhân tiện, tôi đang sử dụng Xcode 7.3.1 và Swift 2.3. Giải pháp được thử nghiệm trên iOS 9.3 đang hoạt động hoàn hảo.

Cảm ơn, Hy vọng điều này đã giúp.


xin lỗi vì tiếng Anh không tốt của tôi, tôi có nghĩa là "làm việc như một bùa mê" :)
Aznix

@Aznix Không có vấn đề .. :)
onCompletion

2

Trong swift, đặt đoạn mã sau vào lớp con ô xem bộ sưu tập:

override var bounds: CGRect {
  didSet {
    // Fix autolayout constraints broken in Xcode 6 GM + iOS 7.1
    self.contentView.frame = bounds
  }
}

Đây là câu trả lời tôi đang tìm kiếm. Tôi đã sử dụng để ghi đè setBound trong Objective-C để khắc phục sự cố này (không chắc chắn cách viết nó trong Swift). Cảm ơn bạn :)
Matthew Cawley

1

Tôi đã thấy rằng cũng có vấn đề với contentViewkích thước trong iOS 8. Nó có xu hướng được đặt ra rất muộn trong chu kỳ, điều này có thể gây ra xung đột ràng buộc tạm thời. Để giải quyết điều này, tôi đã thêm phương pháp sau vào một danh mục UICollectionViewCell:

- (void)fixupContentView
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 80100
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) {
        self.contentView.frame = self.bounds;
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    } else {
        [self layoutIfNeeded];
    }
#endif
#endif
}

Phương pháp này nên được gọi sau khi khử tế bào.


Sẽ thật lý tưởng nếu phương pháp này được gọi tự động. Tôi không thích nó, nhưng điều này có thể được thực hiện bằng cách phồng lên dequeueReusableCellWithReuseIdentifier:forIndexPath:.
phatmann

Apple dường như đã khắc phục sự cố này trong phiên bản 8.1 của SDK iOS trong Xcode 6.1 GM (Build 6A1042b). Do đó, tôi đã cập nhật mã ở trên để không chạy khi sử dụng SDK 8.1. Khi nhóm của bạn đã chuyển sang Xcode 6.1, bạn có thể xóa hoàn toàn bản hack này.
phatmann

1

Tôi đã sửa lỗi này:

override func layoutSubviews() {
   contentView.superview?.frame = bounds
   super.layoutSubviews()
}

xem: ở đây


-1

Chỉ cần đảm bảo rằng bạn chọn hộp kiểm "Tự động hóa các cuộc phỏng vấn" trong ngòi cho ô xem bộ sưu tập đó. Nó sẽ hoạt động tốt trên cả iOS 8 và iOS 7.


Không, nó không có. Đây là một tế bào nguyên mẫu nhúng.
thkeen
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.