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。
但是,在iOS 7中,Cell内部的所有子视图突然缩小到(0,0,50,50)的框架,并且不再符合我的Autoresizing规则。
我认为这是在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相关的,而不是与运行时间有关,我非常有信心 – 以下是我可以显示它:
- 编译+在Xcode 5.1中运行应用程序。
- 转到模拟器应用程序的目录,并复制你有问题的xib编译的.nib文件。
- Build +在Xcode 6 GM中运行应用程序。
- 停止应用程序。
- 将新build应用程序的模拟器文件夹中的.nib文件replace为使用Xcode 5.1创build的.nib文件
- 从模拟器重新启动应用程序,而不是从Xcode。
- 您的单元格从该.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。
谢谢,希望这有助于。
这个后期工作的答案,我从来不明白的是为什么它的工作原理。
首先,有两个“规则”:
- 对于以编程方式创build的视图(例如
[UIView new]
),属性translatesAutoresizingMaskIntoConstraints
设置为YES
- 在启用了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"/>
所以有两个结论:
-
contentView
translatesAutoresizingMaskIntoConstraints
设置为YES
。 -
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上都能正常工作。