Storyboard原型单元(Xcode 6,iOS 8 SDK)中的UICollectionViewCell contentView框架的自动调整问题仅在iOS 7上运行时发生

我正在使用Xcode 6 Beta 3,iOS 8 SDK。 使用Swift构build目标iOS 7.0。 请参阅下面的截图一步一步的问题。

在Storyboard中有一个UICollectionView。 1原型UICollectionViewCell在中间包含1个标签(没有自动调整规则)。 紫色的背景是标记一个contentView,它是由我猜测的Cell在运行时生成的。 该视图将根据我的UICollectionViewLayoutDelegate最终resize,但不会在iOS 7上。请注意,我正在使用Xcode 6,并且问题仅发生在iOS 7上。

当我在iOS 8上构build应用程序时,一切都可以。

注:紫色是contentView ,蓝色是我的UIButton圆angular。

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

但是,在iOS 7中,Cell内部的所有子视图突然缩小到(0,0,50,50)的框架,并且不再符合我的Autoresizing规则。

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

我认为这是在iOS 8 SDK或Swift或Xcode的错误?


更新1:这个问题在官方的Xcode 6.0.1中依然存在! 最好的解决方法就像KoCMoHaBTa通过在单元格的cellForItem中设置框架(你必须inheritance你的单元格)。 事实certificate,这是iOS 8 SDK和iOS 7之间的不兼容(请检查ecotax下面引用的Apple的答案)。

更新2:将此代码粘贴到您的cellForItem的开头,事情应该没问题:

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

contentView被破坏。 它也可以在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] } 

我遇到了同样的问题,并要求Apple DTS帮忙。 他们的答复是:

在iOS 7中,单元格的内容视图通过自动调整掩码大小。 在iOS 8中,这已经改变,单元格停止使用自动调整掩码,并开始在layoutSubviews中调整内容视图的大小。 如果一个笔尖在iOS 8中进行了编码,然后在iOS 7上对其进行解码,那么您将拥有一个没有自动识别掩码的内容视图,并且没有其他方法可以自行resize。 所以如果你改变了单元格的框架,内容视图将不会跟随。

正在部署回iOS 7的应用程序将不得不通过调整内容视图本身,添加自动调整掩码或添加约束来解决此问题。

我想这意味着它不是XCode 6中的一个错误,而是iOS 8 SDK和iOS 7 SDK之间的不兼容问题,如果升级到Xcode 6,将会打到你,因为它会自动开始使用iOS 8 SDK。

正如我以前所说,解决scheme丹尼尔·普拉曼描述为我工作。 Igor Palaguta和KoCMoHaBTa所描述的看起来比较简单,而且看起来对于苹果DTS的答案是有道理的,所以我会在后面尝试。

我遇到了同样的问题,并希望苹果公司将解决这个下一个Xcode版本。 同时我使用一种解决方法。 在我的UICollectionViewCell子类中,我刚刚重写了layoutSubviews并手动调整了contentView的大小,以防大小不同于collectionViewCell大小。

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

另一个解决scheme是在-collectionView:cellForItemAtIndexPath中设置contentView的大小和自动调整掩码:如下所示:

 -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellID = @"CellID"; UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath]; //set contentView frame and autoresizingMask cell.contentView.frame = cell.bounds; cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin; //You custom code goes here return cell; } 

这也适用于自动布局,因为自动resize的蒙版被转换为约束。

在Xcode 6.0.1中,针对iOS7设备的contentView for UICollectionViewCell被破坏。 它也可以通过向UICollectionViewCell及其在awakeFromNib或init方法中的contentView添加适当的约束来解决。

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

由于Xcode 6 GM中的一个错误,Xcode如何将xib文件编译为nib格式,这将无法正确工作,而没有提到任何其他解决方法。 虽然我不能100%肯定地说这是Xcode相关的,而不是与运行时间有关,我非常有信心 – 以下是我可以显示它:

  1. 编译+在Xcode 5.1中运行应用程序。
  2. 转到模拟器应用程序的目录,并复制你有问题的xib编译的.nib文件。
  3. Build +在Xcode 6 GM中运行应用程序。
  4. 停止应用程序。
  5. 将新build应用程序的模拟器文件夹中的.nib文件replace为使用Xcode 5.1创build的.nib文件
  6. 从模拟器重新启动应用程序,而不是从Xcode。
  7. 您的单元格从该.nib加载应该按预期工作。

我希望每个读到这个问题的人都会向苹果提交一份雷达。 这是一个巨大的问题,需要在最终的Xcode版本之前解决。

编辑:根据ecotax的post ,我只是想更新这个说现在确认在iOS 8的build设与iOS 7的行为差异,但不是一个错误。 我的黑客修复了这个问题,因为在iOS 7上构build了自动调整掩码的内容视图,这是苹果不再需要的。

这是@伊戈尔答案的Swift版本,接受并感谢你的好回答队友。

首先转到您的UICollectionViewCell子类并粘贴以下代码,因为它在类中。

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

顺便说一下,我使用Xcode 7.3.1和Swift 2.3。 解决scheme在完美工作的iOS 9.3上进行testing。

谢谢,希望这有助于。

这个后期工作的答案,我从来不明白的是为什么它的工作原理。

首先,有两个“规则”:

  1. 对于以编程方式创build的视图(例如[UIView new] ),属性translatesAutoresizingMaskIntoConstraints设置为YES
  2. 在启用了AutoLayout的界面构build器中创build的视图将把属性translatesAutoresizingMaskIntoConstraints设置为NO

第二个规则似乎不适用于您没有为其定义约束的顶级视图。 (例如内容视图)

在查看Storyboard单元格时,请注意单元格没有公开contentView 。 我们不是“控制” contentView ,苹果是。

深入介绍storyboard源代码并查看contentView单元格是如何定义的:

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

现在单元格的子视图(注意translatesAutoresizingMaskIntoConstraints="NO" ):

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

contentView没有将它的translatesAutoresizingMaskIntoConstraints设置为NO 。 另外它缺乏布局的定义,也许是因为@ecotax所说的 。

如果我们看一下contentView ,它有一个自动调整的掩码,但没有定义它: <autoresizingMask key="autoresizingMask"/>

所以有两个结论:

  1. contentView translatesAutoresizingMaskIntoConstraints设置为YES
  2. contentView缺less布局的定义。

这导致我们已经谈到了两个解决scheme。

您可以在awakeFromNib手动设置自动调整掩码:

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

或者您可以在awakeFromNib中将contentView translatesAutoresizingMaskIntoConstraints设置为NO ,并在- (void)updateConstraints定义约束。

在swift中,将下面的代码放在集合视图单元格子类中:

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

我发现contentView大小也存在问题。它往往会在周期后期进行布局,这可能会导致暂时的约束冲突。 为了解决这个问题,我在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 } 

这个方法应该在离开单元之后调用。

我修正了这个问题:

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

看: 这里

只要确保在该集合视图单元格的nib中选中了checkbox“Autoresize subviews”即可。 它在iOS 8和iOS 7上都能正常工作。