首页 文章

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

提问于
浏览
157

我正在使用Xcode 6 Beta 3,iOS 8 SDK . 使用Swift构建目标iOS 7.0 . 请通过以下屏幕截图逐步查看我的问题 .

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

当我在iOS 8上构建应用程序时 . 一切都很好 .

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

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

但是,在iOS 7上,Cell中的所有子视图突然缩小到(0,0,50,50)的帧,并且永远不再符合我的自动调整规则 .

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

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


Update 1: 官方Xcode 6.0.1中仍存在此问题!最好的解决方法就像KoCMoHaBTa在下面通过设置单元格的cellForItem中的框架所建议的那样(你必须为你的单元子类化) . 事实证明,这是iOS 8 SDK和iOS 7之间的不兼容性(请查看Apple引用的ecotax的答案) .

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

12 回答

  • 61

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

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

    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]
    }
    
  • 4

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

    在iOS 7中,单元格的内容视图通过自动调整掩码自行调整大小 . 在iOS 8中,这已更改,单元格停止使用自动调整蒙版并开始调整layoutSubviews中的内容视图大小 . 如果在iOS 8中对nib进行编码然后在iOS 7上对其进行解码,则您将拥有一个没有自动调整掩码的内容视图,并且没有其他方法可以自行调整大小 . 因此,如果您更改了单元格的框架,则内容视图将不会跟随 . 要部署回iOS 7的应用程序必须通过调整内容视图本身,添加自动调整掩码或添加约束来解决此问题 .

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

    正如我之前评论的那样,丹尼尔普拉曼描述的解决方法对我有用 . Igor Palaguta和KoCMoHaBTa描述的那些看起来更简单,并且似乎有理由给予Apple DTS的答案,所以我稍后会尝试 .

  • 1

    我遇到了同样的问题,并希望Apple能够在下一个Xcode版本中解决这个问题 . 同时我使用了一种解决方法 . 在我的 UICollectionViewCell 子类中,我刚刚覆盖 layoutSubviews 并在大小与 collectionViewCell size不同的情况下手动调整contentView的大小 .

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

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

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

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

  • 60

    在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)]];
    
  • 6

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

    • Build在Xcode 5.1中运行应用程序 .

    • 转到模拟器应用程序的目录并复制已遇到问题的xib的已编译.nib文件 .

    • Build在Xcode 6 GM中运行应用程序 .

    • 停止应用程序 .

    • 使用Xcode 5.1创建的.nib文件替换新构建的应用程序的模拟器文件夹中的.nib文件

    • 从模拟器重新启动应用程序,而不是从Xcode重新启动 .

    • 从.nib加载的单元格应按预期工作 .

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

    编辑:根据ecotax's post,我只是想更新这个,说现在确认建筑物之间的行为差异iOS 8 vs iOS 7,但不是bug . 我的黑客修复了这个问题,因为在iOS 7上构建时,将自动调整掩码添加到了使其工作所需的内容视图中,Apple不再添加 .

  • 4

    这篇文章的答案,我从未理解的是 why 它有效 .

    首先,有两个“规则”:

    • 对于以编程方式创建的视图(例如 [UIView new] ),属性 translatesAutoresizingMaskIntoConstraints 设置为 YES

    • 在界面构建器中创建的视图,启用了AutoLayout,将属性 translatesAutoresizingMaskIntoConstraints 设置为 NO

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

    查看Storyboard单元格时,请注意该单元格没有公开其 contentView . 我们不是"controlling",Apple是 .

    深入了解故事板源代码,并了解如何定义 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 said .

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

    所以有两个结论:

    • contentView translatesAutoresizingMaskIntoConstraints 设置为 YES .

    • contentView 缺乏布局的定义 .

    这引出了两个已经讨论过的解决方案 .

    您可以在 awakeFromNib 中手动设置自动调整蒙版:

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

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

  • 2

    这是@ Igor的答案的Swift版本,这是接受的,谢谢你的答案 .

    First 转到你的 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上进行了测试,它运行良好 .

    谢谢,希望这有帮助 .

  • -1

    我发现在iOS 8中也存在 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
    }
    

    应在将单元格出列后调用此方法 .

  • 166

    我修好了这样做:

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

    见:here

  • 38

    只需确保选中该集合视图单元格的nib中的“Autoresize subviews”复选框 . 它可以在iOS 8和iOS 7上正常运行 .

相关问题