使用 UITableViewCell 子类“在执行-layoutSubviews 之后仍然需要自动布局”

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

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

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

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. ShopCell's implementation of -layoutSubviews needs to call super.'

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

我几乎可以肯定,我遗漏了一些简单的东西,但是找不到任何文档或指南来说明我做错了什么。如果你能帮忙,我将不胜感激。

Edit: Just tried changing it to a UITableViewCell in IB and leaving all the subviews in place, still the same error.

53940 次浏览

我在代码中手动添加约束时遇到了同样的问题:

{
[self setTranslatesAutoresizingMaskIntoConstraints:YES];
[self addSubview:someView];
[self addSubview:someOtherView];
[self addConstraint:...];
}

Hypothesis

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

解决方案

我的解决办法是把所有东西都移到 contentView上。

{
[self.contentView addSubview:someView];
[self.contentView addSubview:someOtherView];
[self.contentView addConstraint:...];
}

我不能100% 确定这个 Interface Builder 是否能正常工作,但是如果你把所有的东西都从你的手机上推开(假设你手机上有东西) ,那么它应该能正常工作。希望这个能帮到你!

我也经历过同样的事。结果表明,如果以编程方式从 ShopCell 添加一个子视图。Xib/Storyboard,它使用自动布局作为另一个视图的子视图,这个异常可能会被抛出,这取决于您的约束是如何配置的。我的猜测是,在 IB 中创建的约束正是在以编程方式添加视图作为子视图时造成麻烦的原因,因为它会维护来自 viewA 的约束—— > viewB 同时,您可以将 viewB 作为 viewC 的子视图添加。你明白了吗(这句话连我自己都搞不懂) ?

In my situation - since it was very simple views that caused the problem - I created the views programmatically and not in IB. That solved it. You might extract those views to other xib files and disable auto layout for those. I guess that'd work.

显然,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

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

注意: 看起来这个 bug 在 iOS7中已经修复了; 我可以删除这段代码,或者至少添加一个运行时检查,这样只有在 iOS6上运行时才能执行。

我解决了这个问题,关闭“自动布局”的所有子视图的自定义表格视图单元格。

在自定义单元格的 xib 中,选择一个子视图并取消选中 File spector > Interface Builder 文档 > Use autoayout

我遇到这个问题是因为我最初在 xib 文件中添加了 UIView 而不是 UITableViewCell。

几个月来我一直有同样的问题,但是我发现了问题所在。

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

事实上,您应该 一直都是使用这个项目,因为所有的子视图都被添加到 UITableViewCellcontentView中。

就这样,一切都会好起来的。

我遇到了这种情况,它似乎与 UITableViewCell 子类作为原型单元有关,这些原型单元专门添加了其他定制的 UIView 子类。我在这里强调“自定义”,因为我已经成功地使用了只有 UIKit 子元素的单元格,但是在尝试为我已经创建的定制视图构建约束时失败了,抛出了作者问题中提到的错误。

我不得不把我的单元格分成不使用 AutoLayout 的独立笔尖。

让我们希望苹果能收拾这个烂摊子。

我通过将 backgroundView连接器从我的后台 UIImageViewaccessoryView连接器从我的 UIButton定制解耦来消除这个错误。我怀疑这些并不是我想要的使用方式。

我也有同样的问题。问题在于我创造细胞 Xib 的方式。我像往常一样创建了一个 Xib,并将默认的“ UIView”类型更改为自定义的 UITableViewCell 类。正确的方法是首先删除默认视图,然后将表视图单元格对象拖到 xib 上。详情请浏览这里: http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/

我今天第一次遇到这个问题。到目前为止,我在使用原型 UITableViewCell 子类方面有一些不同的经验,但从未遇到过这个问题。我所使用的单元格的不同之处在于我有一个 IBOutlet to-backoundView,我用它来给单元格上色。我发现,如果我创建了一个新的属性,并且仍然添加了一个新的 UIView,从而扩展了整个单元格的跨度,那么这个断言就会消失。为了验证这是原因,我返回到将这个视图附加到 backoundView 出口,断言再次出现。到目前为止,在子类原型 UITableViewCell 中使用 AutoLayout 没有其他问题,因为我已经做了这个更改。

Add your subviews to the contentView of the cell instead of the cell itself. 所以不是:

[self addSubview:someView];

你必须使用

[self.contentView addSubview:someView];

I was seeing this as a result of modifying constraints in my implementation of layoutSubviews. Moving the call to super from the beginning to the end of the method fixed the problem.

在某些情况下,这很容易解决布局问题(取决于您的布局)。在 UITableView 子类中,在 awakeFromNib 或 init 中设置自动调整大小掩码:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

默认情况下,它设置为 UIViewAutoresizingNothing

对我来说,

The referenced UIImageView for the auto layout for UITableView is assigned to backgroundView of the UITableView.

self.tableView.backgroundView = self.tableBackgroundImageView;

因此,我从 UIView (根视图)中删除了 backoundView 的 UIImageView,并重置(删除)了对该 UIImageView 的所有自动布局引用。我将 UIImageView 作为背景放在 UIView (根视图)的外部。然后在代码中赋值给 UITableView 的 backoundView。

然后修好了。

我也有同样的问题,从 UIView 改为 UITableViewCell 解决了这个问题。

正如上面已经说过的,当您创建一个在 UITableView 中使用的视图时,您必须删除默认创建的视图,并将 UITableViewCell 或 UITableViewHeaderFooterView 作为根视图拖动。例如,您必须在文本编辑器中打开 XIB 文件,并在根标记及其直接子标记中将属性 translatesAutoresizingMaskIntoConstraints添加/更改为 YES

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

我找到解决办法了。

在我的例子中,我在情节串连图板中创建了 cell 视图(启用了自动布局) ,并在 ViewController.m 中定义了定制的 UITableViewCell 接口,我必须将接口移动到 ViewController.h。

我在使用故事板创建自定义 UITableViewCell 时遇到了同样的问题。幸运的是,我发现了这个问题,因为我将 accoryView ([ UITableViewCell setAccessoryView: ])输出到 UIButton,并将其添加到单元格中。

因此,它发生在我的项目时,运行在 iOS6上。

解决方案

我释放的插座之间的 AccoryView 和我的按钮,其中 contained the custom cell.

提议

您不应该使用 UITableViewCell 的本机元素并进行更改 它。

对于这个问题,我没有得到任何合适的解决方案,但是您可以通过使用框架并且不将 translatesAutoresizingMaskIntoConstraint 属性设置为 No (默认为 yes,所以不要设置它)来修复它

CGRect headerViewFrame = CGRectMake(0,0,320,60); //Frame for your header/footer view
UIView *tableHeaderView = [[UIView alloc] initWithFrame:headerViewFrame];
tableHeaderView.translatesAutoresizingMaskIntoConstraints = Yes; //Or don't set it at all
[self.tableView setTableHeaderView:tableHeaderView];

这个问题可能是由于在 viewDidAppear中忘记调用 [super viewDidAppear:]引起的,但是我确信这不是唯一的原因。

我也有同样的问题,这就是我的项目的问题:
当我在创建一个自定义的 uitableViewCell 的 Interface Builder 时,我从 Xcode 的对象收集窗格中拖动了一个 观景而不是一个 表格视图单元格
as the custom table cell.
如果你处于同样的情况,这里有一个解决方案:
Delete the view in interface builder, make sure you drag a Table View Cell from the object collection pane and redo the custom table cell view. You can copy the objects in the old view and paste them to the canvas for the new Table View Cell.

我在 Xcode 6,iOS 7 + 中设置的表页脚视图也有类似的问题。 The solution was in the format of the nib file. Apparently it was stuck in Xcode 4 format or something. Changing the file settings to "opens in: Xcode 6.0" (or Default, for that matter), instantly fixed it. Found the solution by chance: it was driving me crazy, so I deleted the entire file and created again, obviously with the default settings. I have no idea why simply editing the file in the latest Xcode didn't convert it to a Xcode 5+ format, as it usually happens.

f

在 iOS7中也有同样的问题(iOS8似乎修复了)。我的解决方案是在 viewDidLayoutSubviews方法的末尾调用 [self.view layoutIfNeeded]

我有一个类似的问题不是在 UITableViewCell,而是在 UITableView本身。因为这是谷歌的第一个搜索结果,我会把它贴在这里。结果是 viewForHeaderInSection是问题所在。我创建了一个 UITableViewHeaderFooterView并将 translatesAutoresizingMaskIntoConstraints设置为 NO。现在有趣的部分来了:

IOS7:

// don't do this on iOS 7
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;

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

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

好吧,我认为你不能在表格视图头部使用自动布局,而且只能在子视图上使用。但这并不是你以后看到的全部真相。除此之外一切正常。

IOS8:

// you have to do this, otherwise you get an auto layout error
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;

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

无法同时满足约束。

For iOS 8 you have to disable auto resizing mask for the header.

不知道为什么会这样,但看起来苹果确实在 iOS8中修复了一些东西,并且在 iOS7和 iOS8中自动布局的工作方式不同。

我有同样的麻烦与定制 UITableViewHeaderFooterView + xib。

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

-(void)layoutSubviews
{
[super layoutSubviews];
[self layoutIfNeeded]; // this line is key
}

我也有同样的问题。我转到 DetailViewController 并将标识符重命名为 UIView。它之前在 UITableView 上出现过。问题解决了。这个问题并不一定出现在 DetailViewController 中。可能在其他任何一本书里。尝试将其重命名为受尊敬的标识符。

I had a similar issue with static table view cells in IB. One of the cells had a subview that had a class that was mistakenly altered to a subclass of UITextfield. The compiler didn't give any warnings/errors. But at runtime the system was unable to load the view controller with the aforementioned crash as a result.

问题是对子视图的布局调用的顺序:

看看这个

出现在 IOS < 8

解决方案: 在调用 super layoutSubviews 之前更改约束

- (void)layoutSubviews
{


[self _updateConstraints];


[super layoutSubviews];
}

I modified 卡尔 · 林德伯格的回答 to override UITableView instead and it started working for me:

UITableView + AutoLayoutFix.h

@interface UITableView (AutoLayoutFix)
@end

UITableView + AutoLayoutFix.m

#import <objc/runtime.h>


@implementation UITableView (AutoLayoutFix)


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


method_exchangeImplementations(existingMethod, newMethod);
}


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


@end

然后在 MyViewController.m中,我只是导入了这个类别:

#import "UITableView+AutoLayoutFix.h"

我遇到了同样的问题,最后发现 原因是我向 UITableViewCell 添加了一个约束,它应该是 UITableViewCell 的 ContentView。当我更改约束时,一切都很好!