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

我用的是 Xcode 6 Beta 3,iOS 8 SDK。使用 Swift 构建目标 iOS 7.0。请参考我的问题一步一步与下面的截图。

我在故事板中有一个 UICollectionView。1原型 UICollectionViewCell,中心包含1个标签(无自动调整大小规则)。紫色背景是为了标记一个 contentView,我猜它是由 Cell 在运行时生成的。该视图最终将根据我的 UICollectionViewLayoutgenerate 进行适当调整,但不会在 iOS7上进行调整。注意,我使用的是 Xcode 6,问题只发生在 iOS 7上。

当我在 iOS8上构建应用程序时,一切都很好。

注: 紫色是 ContentView,蓝色是我的圆角 UIButton。

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

然而,在 iOS7中,Cell 中所有的子视图突然缩小到(0,0,50,50)的框架,再也不符合我的自动调整大小规则了。

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

我假设这是 iOS8SDK 或者 Swift 或者 Xcode 中的一个 bug?


更新1: 这个问题在官方的 Xcode 6.0.1中仍然存在!最好的解决办法是像 KoCMoHaBTa 建议的那样,在 cell 的 cellForItem 中设置框架(但是您必须对 cell 进行子类化)。事实证明,这是 iOS8SDK 和 iOS7之间的不兼容性(请查看下面引自苹果的 ecotax 的回答)。

更新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 **/
55379 次浏览

我遇到了同样的问题,希望苹果能够在下一个 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;
}
}

另一个解决方案是在 -collectionView:cellForItemAtIndexPath:中像下面这样设置 contentView 的 size 和 autoresize 掩码:

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

这也适用于自动布局,因为自动调整大小掩码被转换为约束。

ContentView 被破坏。它也可以在 awakeFromNib 中修复

目的:

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

如果没有其他提到的解决方案,这将无法正常工作,因为 Xcode 6 GM 中存在一个 bug,Xcode 将 xib 文件编译成 nib 格式。虽然我不能100% 肯定它与 Xcode 有关,而且与运行时无关,但我非常有信心——下面是我可以展示的方法:

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

我希望每个读到这个问题的人都能向苹果公司提交一份 Radar。这是一个巨大的问题,需要在最终的 Xcode 发布之前解决。

编辑: 根据 Ecotax 的邮件,我只是想更新一下,现在已经证实了构建在 iOS8和 iOS7之间的行为差异,但不是一个 bug。我的黑客技术解决了这个问题,因为基于 iOS7的系统在内容视图中添加了自动调整大小的掩码,而苹果已经不再添加这个掩码了。

我遇到了同样的问题,向苹果 DTS 寻求帮助,他们的回答是:

在 iOS7中,单元格的内容视图通过自动调整大小来调整自己的大小 在 iOS8中,这个改变了,单元格停止使用 中调整内容视图的大小 如果一个笔尖在 iOS8中编码,然后在 iOS8中解码 7,您将拥有一个没有自动调整大小掩码的内容视图 其他方法来调整自己的大小。所以如果你改变了框架 单元格,则内容视图不会跟随。

正在部署回 iOS7的应用程序必须解决这个问题 调整内容视图本身的大小,添加自动调整大小的掩码,或者添加 约束。

我猜这意味着它不是 XCode 6中的 bug,而是 iOS 8 SDK 和 iOS 7 SDK 之间的不兼容性,如果你升级到 XCode 6,你会受到影响,因为它会自动开始使用 iOS 8 SDK。

正如我之前所评论的,Daniel Plamann 描述的解决方案对我很有用。Igor Palaguta 和 KoCMoHaBTa 描述的那些看起来更简单,给出苹果 DTS 的答案似乎是有意义的,所以我稍后会尝试这些。

我发现在 iOS8中 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
}

此方法应在退出单元格队列后调用。

在 Xcode 6.0.1中,UICollectionViewCell 的 contentView 对于 iOS7设备是中断的。 它也可以通过向 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)]];

迅速地,在集合视图单元格子类中放置以下代码:

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

只要确保选中该集合视图单元格的笔尖中的复选框“ Autoresize subviews”即可。它在 iOS8和 iOS7上都能正常工作。

这个帖子的答案,我从来没有理解的是 为什么它的工作原理。

首先,有两条“规则”:

  1. 对于以编程方式创建的视图(Exp.[UIView new]) ,属性 translatesAutoresizingMaskIntoConstraints设置为 YES
  2. 在启用了自动布局的 Interface Builder 中创建的视图,其属性 translatesAutoresizingMaskIntoConstraints将设置为 NO

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

当查看 Storyboard 单元格时,请注意该单元格没有暴露其 contentView。我们不是在“控制”contentView,苹果才是。

深入研究故事板源代码,看看如何定义 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. translatesAutoresizingMaskIntoConstraints设置为 YES
  2. contentView缺乏布局的定义。

这就引出了我们已经讨论过的两个解决方案。

您可以在 awakeFromNib中手动设置自动调整大小的掩码:

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

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

我决定这么做:

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

见: 给你

这是@Igor 的答案的 Swift 版本,我们接受并感谢你的好答案伙伴。

首先 转到您的 UICollectionViewCell子类并将下面的代码粘贴到类中。

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

顺便说一下,我使用的是 Xcode 7.3.1和 Swift 2.3。解决方案在 iOS 9.3上进行了测试,运行良好。

谢谢,希望这对你有帮助。