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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24750158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:23:37  来源:igfitidea点击:

Autoresizing issue of UICollectionViewCell contentView's frame in Storyboard prototype cell (Xcode 6, iOS 8 SDK) happens when running on iOS 7 only

objective-cios7ios8xcode6uicollectionviewcell

提问by thkeen

I'm using Xcode 6 Beta 3, iOS 8 SDK. Build Target iOS 7.0 using Swift. Please refer to my problem step by step with screenshots below.

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

I have a UICollectionView in Storyboard. 1 Prototype UICollectionViewCell which contains 1 label in the centre (no autoresizing rule). Purple background was to mark a contentView that is generated in runtime by the Cell I guess. That view will be resized properly base on my UICollectionViewLayoutDelegate eventually, but not on iOS 7. Notice that I'm using Xcode 6 and the problem only happens on iOS 7.

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

When I build the app on iOS 8. Everything is okay.

当我在 iOS 8 上构建应用程序时。一切正常。

Note: Purple is the contentView, Blue is my UIButton with rounded corner.

注意:紫色是contentView,蓝色是带圆角的 UIButton 。

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

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

However, on iOS 7, all the subViews inside the Cell suddenly shrink to the frame of (0,0,50,50) and never conforms to my Autoresizing rule anymore.

然而,在iOS 7上,Cell内的所有子视图突然缩小到(0,0,50,50)的框架,不再符合我的自动调整规则。

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

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

I assume this is a bug in iOS 8 SDK or Swift or maybe Xcode?

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



Update 1:This problem still exists in the official Xcode 6.0.1 ! The best work around is like what KoCMoHaBTa suggested below by setting the frame in cellForItem of the cell (You have to subclass your cell though). It turned out that this is a incompatibility between iOS 8 SDK and iOS 7 (check ecotax's answer below quoted from Apple).

更新1:这个问题在官方的Xcode 6.0.1中仍然存在!最好的解决方法就像下面 KoCMoHaBTa 建议的那样,通过在单元格的 cellForItem 中设置框架(尽管您必须对单元格进行子类化)。事实证明,这是 iOS 8 SDK 和 iOS 7 之间的不兼容(请查看下面从 Apple 引用的 ecotax 的回答)。

Update 2:Paste this code at the beginning of your cellForItemand things should be okay:

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

回答by Igor Palaguta

contentView is broken. It can be also fixed in awakeFromNib

内容视图坏了。它也可以在awakeFromNib中修复

ObjC:

对象:

- (void)awakeFromNib {

    [super awakeFromNib];

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

Swift3:

斯威夫特3:

override func awakeFromNib() {
    super.awakeFromNib()

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

回答by ecotax

I encountered the same problem and asked Apple DTS for help. Their reply was:

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

In iOS 7, cells' content views sized themselves via autoresizing masks. In iOS 8, this was changed, cells stopped using the autoresizing masks and started sizing the content view in layoutSubviews. If a nib is encoded in iOS 8 and then decode it on iOS 7, you'll have a content view without an autoresizing mask and no other means by which to size itself. So if you ever change the frame of the cell, the content view won't follow.

Apps being deploying back to iOS 7 will have to work around this by sizing the content view itself, adding autoresizing masks, or adding constraints.

在 iOS 7 中,单元格的内容视图通过自动调整大小蒙版来调整自己的大小。在 iOS 8 中,这被改变了,单元格停止使用自动调整大小掩码并开始在 layoutSubviews 中调整内容视图的大小。如果在 iOS 8 中对笔尖进行编码,然后在 iOS 7 上对其进行解码,您将拥有一个没有自动调整大小掩码的内容视图,也没有其他方法可以调整自身大小。因此,如果您更改了单元格的框架,内容视图将不会跟随。

正在部署回 iOS 7 的应用程序必须通过调整内容视图本身的大小、添加自动调整大小蒙版或添加约束来解决这个问题。

I guess this means that it's not a bug in XCode 6, but an incompatibility between the iOS 8 SDK and iOS 7 SDK, which will hit you if you upgrade to Xcode 6, because it will automatically start using the iOS 8 SDK.

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

As I commented before, the workaround Daniel Plamann described works for me. The ones described by Igor Palaguta and KoCMoHaBTa look simpler though, and appear to make sense giving Apple DTS' answer, so I'll try those later.

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

回答by Daniel Plamann

I encountered the same issue and hope that Apple will fix this with the next Xcode version. Meanwhile I use a workaround. In my UICollectionViewCellsubclass I've just overridden layoutSubviewsand resize the contentView manually in case the size differs from collectionViewCellsize.

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

回答by KoCMoHaBTa

Another solution is to set the contentView's size and autoresizing masks in -collectionView:cellForItemAtIndexPath:like the following:

另一种解决方案是设置 contentView 的大小和自动调整大小掩码,-collectionView:cellForItemAtIndexPath:如下所示:

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

This works with Auto Layout too, since auto resizing masks are translated to constraints.

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

回答by SerJ_G

In Xcode 6.0.1 contentView for UICollectionViewCell is broken for iOS7 devices. It can be also fixed by adding proper constraints to UICollectionViewCell and its contentView in awakeFromNib or init methods.

在 Xcode 6.0.1 中 UICollectionViewCell 的 contentView 对于 iOS7 设备已损坏。也可以通过在awakeFromNib 或init 方法中向UICollectionViewCell 及其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)]];

回答by Acey

This will not work correctly without any of the other mentioned workarounds because of a bug in Xcode 6 GM with how Xcode compiles xib files into the nib format. While I cannot say for 100% certainty it is Xcode related and not having to do with runtime, I'm very confident - here's how I can show it:

如果没有任何其他提到的解决方法,这将无法正常工作,因为 Xcode 6 GM 中存在一个错误,即 Xcode 如何将 xib 文件编译为 nib 格式。虽然我不能 100% 肯定地说它与 Xcode 相关并且与运行时无关,但我非常有信心 - 这是我如何展示它:

  1. Build+Run the application in Xcode 5.1.
  2. Go to the simulator application's directory and copy the compiled .nib file for the xib you are having issues with.
  3. Build+Run the application in Xcode 6 GM.
  4. Stop the application.
  5. Replace the .nib file in the newly built application's simulator folder with the .nib file created using Xcode 5.1
  6. Relaunch the app from the simulator, NOT from Xcode.
  7. Your cell loaded from that .nib should work as expected.
  1. 在 Xcode 5.1 中构建+运行应用程序。
  2. 转到模拟器应用程序的目录并为您遇到问题的 xib 复制已编译的 .nib 文件。
  3. 在 Xcode 6 GM 中构建+运行应用程序。
  4. 停止应用程序。
  5. 将新建应用程序模拟器文件夹中的 .nib 文件替换为使用 Xcode 5.1 创建的 .nib 文件
  6. 从模拟器重新启动应用程序,而不是从 Xcode。
  7. 从该 .nib 加载的单元格应该按预期工作。

I hope everyone who reads this question will file a Radar with Apple. This is a HUGE issue and needs addressing before the final Xcode release.

我希望看到这个问题的每个人都会向 Apple 提交 Radar。这是一个巨大的问题,需要在最终 Xcode 发布之前解决。

Edit: In light of ecotax's post, I just wanted to update this to say it is now confirmed behavior differences between building in iOS 8 vs iOS 7, but not a bug. My hack fixed the issue because building on iOS 7 added the autoresizing mask to the content view needed to make this work, which Apple no longer adds.

编辑:根据ecotax 的帖子,我只是想更新一下,说现在已确认在 iOS 8 和 iOS 7 中构建之间的行为差​​异,但不是错误。我的 hack 解决了这个问题,因为在 iOS 7 上构建将自动调整大小掩码添加到使这项工作所需的内容视图中,Apple 不再添加。

回答by kgaidis

The answers in this post work, what I never understood is whyit works.

这篇文章中的答案有效,我从来不明白它为什么有效。

First, there are two "rules":

首先,有两个“规则”:

  1. For views created programmatically (Ex. [UIView new]), the property translatesAutoresizingMaskIntoConstraintsis set to YES
  2. Views created in interface builder, with AutoLayout enabled, will have the property translatesAutoresizingMaskIntoConstraintsset to NO
  1. 对于以编程方式创建的视图(例如[UIView new]),该属性translatesAutoresizingMaskIntoConstraints设置为YES
  2. 在界面构建器中创建的视图,启用了 AutoLayout,将属性translatesAutoresizingMaskIntoConstraints设置为NO

The second rule does not seem to apply to top-level views for which you do not define constraints for. (Ex. the content view)

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

When looking at a Storyboard cell, notice that the cell does not have its contentViewexposed. We are not "controlling" the contentView, Apple is.

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

Deep dive into storyboard source code and see how contentViewcell is defined:

深入了解情节提要源代码并查看contentView单元格是如何定义的:

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

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

Now the cell's subviews (notice the translatesAutoresizingMaskIntoConstraints="NO"):

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

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

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

The contentViewdoes not have it's translatesAutoresizingMaskIntoConstraintsset to NO. Plus it lacks layout definition, maybe because of what @ecotax said.

contentView没有它的translatesAutoresizingMaskIntoConstraints设置NO。另外它缺少布局定义,可能是因为@ecotax 所说的

If we look into the contentView, it does have an autoresizing mask, but no definition for it: <autoresizingMask key="autoresizingMask"/>

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

So there are two conclusions:

所以有两个结论:

  1. contentViewtranslatesAutoresizingMaskIntoConstraintsis set to YES.
  2. contentViewlacks definition of a layout.
  1. contentViewtranslatesAutoresizingMaskIntoConstraints设置为YES
  2. contentView缺少布局的定义。

This leads us to two solutions which have been talked about.

这将我们引向了已经讨论过的两种解决方案。

You can set the autoresizing masks manually in awakeFromNib:

您可以在以下位置手动设置自动调整大小蒙版awakeFromNib

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

Or you can set the contentViewtranslatesAutoresizingMaskIntoConstraintsto NOin awakeFromNiband define constraints in - (void)updateConstraints.

或者您可以将 设置contentViewtranslatesAutoresizingMaskIntoConstraintsNOinawakeFromNib并在 中定义约束- (void)updateConstraints

回答by onCompletion

This is the Swift version of @Igor's answer which is accepted and thanks for your nice answer mate.

这是@Igor 答案的 Swift 版本,已被接受,感谢您的好回答伙伴。

FirstGoto your UICollectionViewCellSubclass and paste the following code as it is inside the class.

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

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

By the way I am using Xcode 7.3.1 and Swift 2.3. Solution is tested on iOS 9.3 which is working flawlessly.

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

Thanks, Hope this helped.

谢谢,希望这有帮助。

回答by Ian

In swift, place the following code in the collection view cell subclass:

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

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

回答by phatmann

I have found that there are also issues with contentViewsizing in iOS 8. It tends to get laid out very late in the cycle, which can cause temporary constraint conflicts. To solve this, I added the following method in a category of UICollectionViewCell:

我发现contentViewiOS 8 中的尺寸调整也存在问题。它往往会在周期的后期布局,这可能会导致临时约束冲突。为了解决这个问题,我在一个类别中添加了以下方法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
}

This method should be called after dequeuing the cell.

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