仅在iOS 7上运行时,才会在Storyboard原型单元(Xcode 6,iOS 8 SDK)中自动调整UICollectionViewCell contentView框架的大小


158

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

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

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

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

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

但是,在iOS 7上,单元内的所有子视图突然缩小到(0,0,50,50)的帧,并且不再符合我的自动调整大小规则。

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

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


更新1:官方Xcode 6.0.1中仍然存在此问题!最好的解决方法是像KoCMoHaBTa所建议的那样,方法是在单元格的cellForItem中设置框架(尽管您必须对单元格进行子类化)。事实证明,这是iOS 8 SDK和iOS 7之间的不兼容性(请参阅下面引自Apple的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 **/

1
我发现Xcode 6 Beta 5中仍然存在此问题。有人也经历过吗?
thkeen

2
我现在在我的项目中为此感到挣扎。使用Xcode 5构建的iOS 7和iOS 8看起来不错。使用Xcode 6 beta 6构建的iOS 8看起来不错。使用Xcode 6 beta 6构建的iOS 7存在您正在描述的问题。使用Reveal,我可以看到UICollectionViewCell的大小已正确设置。但是,即使单元格的contentView是父级,它也没有调整大小,即使UICollectionViewCell的Autoresize Subviews处于打开状态。contentView的大小设置为情节提要所具有的大小。我没有在这个项目中使用自动布局。我的项目完全是目标C。
德尔布朗

2
我只是想补充一点,这个问题从Xcode 6 / iOS 8 GM种子开始仍然存在。@DanielPlamann的答案可以强制contentView使用单元格调整大小,可以很好地解决此问题。我猜想在iOS 8中,Apple更改了在Interface Builder中创建单元格内容视图时的处理方式(无论如何,它仍然是一个黑匣子)。但是,它在以iOS 7为目标时会改变行为,这一事实肯定是一个错误。
Stuart

与Xcode 6 GM,自动布局和基于笔尖的单元格相同。我通过将contentView边缘固定到单元格边缘来修复它。
sergiou87 2014年

3
我下载了xcode 6.1,但在模拟器中仍然看到相同的问题。
李海涛

Answers:


169

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

3
没有使用self.contentView.frame = self.bounds; 想我需要吗?不管怎么说,还是要谢谢你!
Michal Shatz 2014年

您好Michal,同意您的观点。但可以肯定的是,我认为100%会更好地在下一个iOS中添加它。
伊戈尔·帕拉古塔

5
我喜欢这个答案,但您需要致电[super awakeFromNib];另外,我正在考虑添加针对iOS 7.1及以下版本的检查,因为我不确定添加这些调整大小的掩码如何影响iOS8上的默认行为。
GingerBreadMane 2014年

如果您不使用笔尖或情节提要,将其放在applyLayoutAttributes中也可以使用:
cetcet 2014年

这对我不起作用。我没有使用自动版式!有什么帮助吗?
thatzprem 2014年

61

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

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

要重新部署到iOS 7的应用程序必须通过调整内容视图本身的大小,添加自动调整大小的遮罩或添加约束来解决此问题。

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

正如我之前评论的那样,解决方法Daniel Plamann为我描述了工作。Igor Palaguta和KoCMoHaBTa所描述的方法看起来更简单,并且给出Apple DTS的答案似乎很有意义,因此我将在以后再进行尝试。


这很有趣,但是我仍然希望他们能够解决它。此行为仅在添加了iPhone 6支持的Xcode 6 GM中引入。在早期的Beta中,它运行良好。我注意到该项目后,甚至将项目恢复到较早的Beta版本,并且按预期工作。我希望每个人都可以向Apple报告此问题。
arton 2014年

@arton我向DTS寻求帮助的同一天提交了错误报告。它被关闭为18312246的重复项。不确定这样做有多大帮助。
ecotax 2014年

我通过调整ContentView的大小来解决这个问题,并为我工作。-(CGSize)collectionViewContentSize {return CGSizeMake(self.collectionView.bounds.size.width,self.collectionView.bounds.size.height); }
赫苏斯·乌尔塔多

60

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

是的,我在周围也使用了类似的方法,但是我在cellForItem / cellForRow中做到了,它也可以工作。
thkeen

1
这是最好的解决方案。如果您要旋转设备并且像元大小发生变化,则将其添加到cellForItem / cellForRow中将导致异常的伪像。
spybart 2014年

嗨!我对此代码有问题。如果是从情节提要或原型单元中加载的,则布尔contentViewIsAutoresize首次为true。仅当您执行一次reloadData时,第二秒才是正确的。因此,您实际上不需要检查大小。而是做:self.contentView.frame = self.bounds;
thkeen

确认:我们应该在cellForItem或cellForRow中执行此操作,因为layoutSubviews仅在返回单元格之后才调用。您在此之前所做的任何操作(例如绘图操作)都将被错误地计算。
thkeen

1
嗯,也许最好放在[cell layoutIfNeeded];cellForItem或cellForRow中?
wtorsi 2014年

38

另一个解决方案是设置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;
}

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


2
这是一种出色的解决方案,因为它可以与任何类型的单元格一起使用而无需子类化,并且当您在集合视图中使用一种以上类型的单元格时,无需在多个位置进行更改。
2014年

6

在Xcode 6.0.1中,iOS7设备的UICollectionViewCell的contentView已损坏。也可以通过在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)]];

现在只有这种方式有效,您只需要为IOS 8进行操作,每次出队后我都必须调用它!但这也不是理想的解决方案,因为多重选择在视觉上不起作用……
Renetik 2015年

最好是真正使用自动布局,这个错误你使用autolayout事件讽刺意味的是节省时间,在简单的情况..
Renetik

面具对我不起作用;但是设置约束是可行的!

4

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

  1. 在Xcode 5.1中生成并运行该应用程序。
  2. 转到模拟器应用程序的目录,并为遇到问题的xib复制已编译的.nib文件。
  3. 在Xcode 6 GM中生成并运行该应用程序。
  4. 停止应用程序。
  5. 用Xcode 5.1创建的.nib文件替换新建应用程序的模拟器文件夹中的.nib文件。
  6. 从模拟器而不是Xcode重新启动应用。
  7. 从该.nib加载的单元格应该可以正常工作。

希望所有阅读此问题的人都可以向Apple提交Radar。这是一个巨大的问题,需要在最终的Xcode版本之前解决。

编辑:鉴于ecotax的帖子,我只是想更新一下,以表示现在已确认iOS 8和iOS 7之间的行为差​​异,但不是bug。我的黑客解决了该问题,因为在iOS 7上构建时,自动调整大小蒙版已添加到完成此工作所需的内容视图中,Apple不再添加了该功能。


我不确定他们是否可以合法发布与通用汽车版本不同的
xCode

哈哈他们会坐牢吗?= P但是总的来说,可以肯定。如果您不记得,他们有针对小牛队的多个GM版本。这不是很常见,但是有可能发生。
阿西2014年

4

在这篇文章中的答案,我从不了解是为什么它起作用。

首先,有两个“规则”:

  1. 对于以编程方式创建的视图(例如[UIView new]),该属性translatesAutoresizingMaskIntoConstraints设置为YES
  2. 在启用自动布局的界面构建器中创建的视图,其属性translatesAutoresizingMaskIntoConstraints设置为NO

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

查看情节提要板单元时,请注意该单元未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. contentView translatesAutoresizingMaskIntoConstraints设置为YES
  2. contentView 缺乏布局的定义。

这导致我们找到了两个已经讨论过的解决方案。

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

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

或者,您可以在中设置,contentView translatesAutoresizingMaskIntoConstraintsNO在中awakeFromNib定义约束- (void)updateConstraints


4

这是@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上进行了测试。

谢谢,希望对您有所帮助。


对不起,我的英语不好,我的意思是“作品如魅力” :)
Aznix

@Aznix没问题.. :)
onCompletion

2

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

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

这就是我一直在寻找的答案。我曾经在Objective-C中重写setBounds来解决此问题(不确定如何在Swift中编写它)。谢谢您:)
马修·考利

1

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

使单元出队后应调用此方法。


如果自动调用此方法将是理想的。我不喜欢它,但这可以通过摇晃来完成dequeueReusableCellWithReuseIdentifier:forIndexPath:
帕特曼2014年

Apple似乎已在Xcode 6.1 GM(内部版本6A1042b)的iOS SDK版本8.1中解决了此问题。因此,我更新了上面的代码,使其在使用8.1 SDK时无法运行。一旦您的团队全部迁移到Xcode 6.1,您就可以完全删除此黑客。
phatmann 2014年

1

我固定这样做:

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

看:这里


-1

只需确保选中该集合视图单元格的笔尖中的“自动调整子视图”复选框即可。它可以在iOS 8和iOS 7上正常运行。


不,不是。这是一个嵌入式原型单元。
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.