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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12610783/
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-08-30 20:25:31  来源:igfitidea点击:

"Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass

objective-ciosxcode4.5autolayout

提问by Mike Mayo

Using XCode 4.5 and iOS 6, I'm developing an app with a simple table view with custom cells. I've done this a hundred times in iOS 5 and below, but for some reason the new autoLayout system is giving me a lot of trouble.

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

I setup my table view and prototype cell in IB, added subviews and wired them up as IBOutlets then setup my delegate and dataSource. However now whenever the first cell is fetched from cellForRowAtIndexPath, I get the following error:

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

*** Assertion failure in -[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 layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

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

I haven't implemented a -layoutSubviews method in my subclassed cell (ShopCell), and even when I try to do that and add the super call as it suggests I still get the same error. If I remove the subviews from the cell in IB, and change it to a standard UITableViewCell, everything works as expected, though of course I'm left with no data in my cells.

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

I'm almost certain that there's something simple I'm missing, but can't find any documentation or guides to suggest what I've done wrong. Any help would be appreciated.

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

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

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

回答by Malaxeur

I encountered the same problem while manually adding constraints in code. In code, I was doing the following:

我在代码中手动添加约束时遇到了同样的问题。在代码中,我正在执行以下操作:

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

Hypothesis

假设

From what I can tell, the issue is that when you disable translatesAutoresizingMaskIntoConstraints, UITableViewCell starts to use Auto Layout and naturally fails because the underlying implementation of layoutSublayersForLayerdoes not call super. Someone with Hopper or some other tool can confirm this. Since you're using IB you're probably wondering why this is an issue... and that's because using IB automatically disables translatesAutoresizingMaskIntoConstraintsfor views that it adds constraints to (it will automatically add a width and height constraint in their place).

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

Solution

解决方案

My solution was to move everything to the contentView.

我的解决方案是将所有内容移动到contentView.

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

I'm not 100% sure if this will work in Interface Builder, but if you push everything off of your cell (assuming that you have something directly on it) then it should work. Hope this helps you!

我不是 100% 确定这是否可以在 Interface Builder 中工作,但是如果你把所有东西都从你的单元中推开(假设你直接在上面有东西),那么它应该可以工作。希望这对你有帮助!

回答by Carl Lindberg

Apparently, UITableViewCell's layoutSubviews implementation does not call super, which is a problem with auto layout. I'd be interested to see if dropping the below category into projects fixes things. It helped in a test project.

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

I might add the problem showed up for me when using a backgroundView on the table cell, as that gets added as a subview to the cell (whereas most subviews should be added to the table cell's contentView, which should usually work better).

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

Note:It appears this bug is fixed in iOS7; I was able to remove this code, or at least add a runtime check so that it's only done if running on iOS6.

注意:这个bug似乎在iOS7中已经修复;我能够删除此代码,或者至少添加一个运行时检查,以便仅在 iOS6 上运行时才能完成。

回答by Arnaud

I had the same bug for few months. But I found what was the problem.

几个月来我遇到了同样的错误。但我发现了问题所在。

When I create an IB file, a UIViewis already added. If you use this view, the app doesn't crash when auto layout is disabled (but there are other issues). When you use auto layout, you have to select the rightview in the Object Library : UITableViewCell.

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

In fact, you should alwaysuse this item because all subviews are added to the contentViewof the UITableViewCell.

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

That's all. All will be fine.

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

回答by Sound Blaster

I had same trouble with custom UITableViewHeaderFooterView+ xib.

我在自定义UITableViewHeaderFooterView+ xib 上遇到了同样的问题。

I saw some answers here, but I found what implementation -layoutSubviewsin my custom footer view class fixes issue:

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

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

回答by Keller

Had the same problem in iOS 7 (iOS 8 seems to fix). The solution for me was to call [self.view layoutIfNeeded]at the end of my viewDidLayoutSubviewsmethod.

在 iOS 7 中有同样的问题(iOS 8 似乎已修复)。我的解决方案是[self.view layoutIfNeeded]在我的viewDidLayoutSubviews方法结束时调用。

回答by Phil Loden

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.

我看到这是因为我在 layoutSubviews 的实现中修改了约束。将调用从方法的开头移到结尾修复了问题。

回答by Trunal Bhanse

I had the same issue. The problem was in the way I was creating the cell Xib. I created a Xib like normal and just changed the type of the default "UIView" to my custom UITableViewCell class. The correct way to is to first delete the default view and then drag the table view cell object onto the xib. More details here : http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/

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

回答by Johno

I resolved the issue by turning off "Autolayout" for all the subviews of my custom Table View Cell.

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

In the xib for a custom cell, select a subview and uncheck File Inspector > Interface Builder Document > Use Autolayout

在自定义单元格的 xib 中,选择一个子视图并取消选中 File Inspector > Interface Builder Document > Use Autolayout

回答by testing

I had a similar problem not on UITableViewCellbut rather on UITableViewitself. Because it is the first result in Google I'll post it here. It turned out that viewForHeaderInSectionwas the problem. I created a UITableViewHeaderFooterViewand set translatesAutoresizingMaskIntoConstraintsto NO. Now here comes the interesting part:

我有一个类似的问题,UITableViewCell而不是它UITableView本身。因为它是 Google 中的第一个结果,所以我将其发布在这里。原来这viewForHeaderInSection就是问题所在。我创建了一个UITableViewHeaderFooterView并设置translatesAutoresizingMaskIntoConstraintsNO. 现在有趣的部分来了:

iOS 7:

IOS 7:

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

If I do this the app crashes with

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

Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.

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

OK, I thought you can't use auto layout on a table view header and only on the subviews. But that's not the full truth as you see it later. To sum up: Don't disable auto resizing mask for the header on iOS 7.Otherwise it's working fine.

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

iOS 8:

iOS 8:

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

If I wouldn't use this I'd get the following output:

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

Unable to simultaneously satisfy constraints.

无法同时满足约束。

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

对于 iOS 8,您必须禁用标题的自动调整大小掩码。

Don't know why it behaves in this way but it seems that Apple did fix some things in iOS 8 and auto layout is working differently on iOS 7 and iOS 8.

不知道为什么它会以这种方式运行,但似乎 Apple 确实在 iOS 8 中修复了一些问题,并且自动布局在 iOS 7 和 iOS 8 上的工作方式有所不同。

回答by Maksymilian Wojakowski

As someone above has already stated, when you create a view for use in a UITableView, you have to delete the view created by default and drag a UITableViewCell or UITableViewHeaderFooterView as the root view. However, there is a way to fix the XIB in case you had missed that part.You have to open the XIB file in a text editor and in the root tag and its direct child add/change the attribute translatesAutoresizingMaskIntoConstraintsto YES, for example

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

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

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