使用UITableViewCell子类执行-layoutSubviews后仍需要"自动布局"

Mik*_*ayo 115 objective-c ios autolayout xcode4.5

使用XCode 4.5和iOS 6,我正在开发一个带有自定义单元格的简单表视图的应用程序.我已经在iOS 5及以下版本中完成了这一百次,但由于某种原因,新的autoLayout系统给了我很多麻烦.

我在IB中设置了我的表格视图和原型单元格,添加了子视图并将它们连接起来作为IBOutlets然后设置我的委托和dataSource.但是现在每当从第一个单元格中取出时cellForRowAtIndexPath,我都会收到以下错误:

***断言失败 - [ShopCell layoutSublayersOfLayer:],/ SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

***由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'执行-layoutSubviews后仍需要自动布局.ShopCell的-layoutSubviews实现需要调用super.

我没有在我的子类化单元格(ShopCell)中实现-layoutSubviews方法,即使我尝试这样做并添加超级调用,因为它表明我仍然得到相同的错误.如果我从IB中的单元格中删除子视图,并将其更改为标准的UITableViewCell,一切都按预期工作,但当然我的单元格中没有数据.

我几乎可以肯定,我有一些简单的东西,但我找不到任何文件或指南来暗示我做错了什么.任何帮助,将不胜感激.

编辑:只是尝试将其更改为IB中的UITableViewCell并保留所有子视图,仍然是相同的错误.

Mal*_*eur 57

我在代码中手动添加约束时遇到了同样的问题.在代码中,我正在做以下事情:

{
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    [self addSubview:someView];
    [self addSubview:someOtherView];
    [self addConstraint:...];
}
Run Code Online (Sandbox Code Playgroud)

假设

据我所知,问题是当你禁用时translatesAutoresizingMaskIntoConstraints,UITableViewCell开始使用自动布局并自然失败,因为底层实现layoutSublayersForLayer不会调用超级.使用Hopper或其他工具的人可以确认这一点.既然你正在使用IB,你可能想知道为什么这是一个问题......那是因为使用IB会自动禁用translatesAutoresizingMaskIntoConstraints它添加约束的视图(它会自动在它们的位置添加宽度和高度约束).

我的解决方案是把所有东西都搬到了contentView.

{
   [self.contentView addSubview:someView];
   [self.contentView addSubview:someOtherView];
   [self.contentView addConstraint:...];
}
Run Code Online (Sandbox Code Playgroud)

我不是百分之百确定这是否适用于Interface Builder,但是如果你把所有东西都推出你的单元格(假设你有直接的东西)那么它应该可行.希望这对你有所帮助!

  • 这对我有用.另外,请确保不要为`UITableViewCell`调用`self.contentView.translatesAutoresizingMaskIntoConstraints = NO`. (5认同)
  • 我还需要在我添加到contentView的每个子视图中添加`subview.translatesAutoresizingMaskIntoConstraints = NO'. (4认同)

Car*_*erg 53

显然,UITableViewCell的layoutSubviews实现不会调用super,这是自动布局的一个问题.我有兴趣看看是否将以下类别放入项目中可以解决问题.它帮助了一个测试项目.

#import <objc/runtime.h>
#import <objc/message.h>

@implementation UITableViewCell (FixUITableViewCellAutolayoutIHope)

+ (void)load
{
    Method existing = class_getInstanceMethod(self, @selector(layoutSubviews));
    Method new = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews));

    method_exchangeImplementations(existing, new);
}

- (void)_autolayout_replacementLayoutSubviews
{
    [super layoutSubviews];
    [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling
    [super layoutSubviews];
}

@end
Run Code Online (Sandbox Code Playgroud)

我可能会在表格单元格上使用backgroundView时添加问题,因为它会作为子视图添加到单元格中(而大多数子视图应该添加到表格单元格的contentView中,通常应该更好).

注意:看来这个bug在iOS7中已得到修复; 我能够删除此代码,或至少添加运行时检查,以便只有在iOS6上运行才能执行.

  • 由于同样的原因,我不得不在`UITableView`上创建这样一个类别(iOS 6.1 b1) (6认同)
  • TableHeaderView是否有类似的修复,因为问题仍存在于ios 7中? (5认同)

Arn*_*aud 33

几个月我有同样的错误.但我发现问题是什么.

当我创建一个IB文件时,UIView已经添加了一个.如果您使用此视图,则在禁用自动布局时应用程序不会崩溃(但还有其他问题).使用自动布局时,必须在对象库中选择正确的视图:UITableViewCell.

事实上,你应该永远使用这个项目,因为所有的子视图添加到contentViewUITableViewCell.

就这样.一切都会好起来的.


Sou*_*ter 17

我在使用custom UITableViewHeaderFooterView+ xib时也遇到了同样的问题.

我在这里看到了一些答案,但我发现-layoutSubviews我的自定义页脚视图类中的实现修复了问题:

-(void)layoutSubviews
{
    [super layoutSubviews];
    [self layoutIfNeeded]; // this line is key
}
Run Code Online (Sandbox Code Playgroud)

  • 你是对的[self layoutIfNeeded]; 是关键:) (2认同)

Phi*_*den 15

我在layoutSubviews的实现中修改了约束,因此我看到了这一点.从方法的开头到结尾将调用移动到super修复了问题.


Kel*_*ler 15

在iOS 7中有相同的问题(iOS 8似乎修复).我的解决方案是[self.view layoutIfNeeded]在我的viewDidLayoutSubviews方法结束时打电话.


Tru*_*nse 14

我遇到过同样的问题.问题在于我创建单元格Xib的方式.我创建了一个像普通的Xib,只是将默认的"UIView"的类型更改为我的自定义UITableViewCell类.正确的方法是先删除默认视图,然后将表视图单元格对象拖到xib上.更多细节:http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/


Joh*_*hno 7

我通过关闭自定义表视图单元的所有子视图的"Autolayout"解决了这个问题.

在自定义单元格的xib中,选择子视图并取消选中文件检查器>界面生成器文档>使用Autolayout

  • 我做了同样的事.虽然如果你想使用自动布局,但不是真正的解决方案 (4认同)

tes*_*ing 7

我有一个类似的问题没有,UITableViewCell而是在UITableView自己.因为这是谷歌的第一个结果,我会在这里发布.原来那viewForHeaderInSection是问题所在.我创建了一个UITableViewHeaderFooterView并设置translatesAutoresizingMaskIntoConstraintsNO.现在来到这里有趣的部分:

IOS 7:

// don't do this on iOS 7
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;
Run Code Online (Sandbox Code Playgroud)

如果我这样做,应用程序崩溃

执行-layoutSubviews后仍需要自动布局.UITableView的-layoutSubviews实现需要调用super.

好的,我以为你不能在表视图标题上使用自动布局,只能在子视图上使用.但这不是你后来看到的全部真相.总结一下:不要为iOS 7上的标题禁用自动调整大小掩码.否则它工作正常.

iOS 8:

// you have to do this, otherwise you get an auto layout error
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;
Run Code Online (Sandbox Code Playgroud)

如果我不使用它,我会得到以下输出:

无法同时满足约束.

对于iOS 8,您必须为标头禁用自动调整大小掩码.

不知道为什么它会以这种方式表现,但似乎Apple确实修复了iOS 8中的一些内容,并且自动布局在iOS 7和iOS 8上的工作方式不同.


Mak*_*ski 5

正如上面的人已经说过的,当你创建一个在UITableView中使用的视图时,你必须删除默认创建的视图,并将UITableViewCell或UITableViewHeaderFooterView作为根视图拖动.但是,有一种方法可以修复XIB,以防错过该部分.你要打开在文本编辑器,并在根标签的XIB文件及其直接子添加/更改属性translatesAutoresizingMaskIntoConstraintsYES,例如

<view contentMode="scaleToFill" horizontalHuggingPriority="1000" id="1" translatesAutoresizingMaskIntoConstraints="YES" customClass="MXWCollapsibleTableHeaderView">