ios UITableViewCell 中 iOS7 上的自动布局约束问题

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

Auto layout constraints issue on iOS7 in UITableViewCell

iosios7uitableviewautolayoutnslayoutconstraint

提问by Alexis

I'm using auto layout constraints programmatically to layout my custom UITableView cells and I'm correctly defining the cell sizes in tableView:heightForRowAtIndexPath:

我正在以编程方式使用自动布局约束来布局我的自定义 UITableView 单元格,并且我正确地定义了单元格大小 tableView:heightForRowAtIndexPath:

It's working just fine on iOS6 and it does lookfine in iOS7 as well

它在 iOS6 上运行良好,在 iOS7 中看起来也不错

BUT when I run the app on iOS7, here's the kind of message I see in the console:

但是当我在 iOS7 上运行该应用程序时,这是我在控制台中看到的消息类型:

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2013-10-02 09:56:44.847 Vente-Exclusive[76306:a0b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
        "<NSLayoutConstraint:0xac4c5f0 V:|-(15)-[UIImageView:0xac47f50]   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
        "<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>",
        "<NSLayoutConstraint:0xac43680 V:[UIView:0xac4d0f0(1)]>",
        "<NSLayoutConstraint:0xac436b0 V:[UIView:0xac4d0f0]-(0)-|   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>

And indeedthere's one of the constraint in that list I don't want :

而且的确有在该列表中,我不想约束之一:

"<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"

and I cannot set the translatesAutoresizingMaskIntoConstraintsproperty of the contentViewto NO => it would mess up the entire cell.

而且我无法将translatesAutoresizingMaskIntoConstraints属性设置contentView为 NO => 它会弄乱整个单元格。

44 is the default cell height but I defined my custom heights in the table view delegate so why does the cell contentView has this constraint? What could cause this?

44 是默认的单元格高度,但我在表格视图委托中定义了我的自定义高度,那么为什么单元格 contentView 有这个约束?什么可能导致这种情况?

In iOS6 it's not happening and everything looks just fine on both iOS6 and iOS7.

在 iOS6 中它没有发生,在 iOS6 和 iOS7 上一切看起来都很好。

My code is quite big so I won't post it here but feel free to ask for a pastebin if you need it.

我的代码很大,所以我不会在这里发布它,但如果您需要它,请随时要求一个 pastebin。

To specify how I'm doing it, on cell intialization:

要指定我是如何做的,关于单元格初始化:

  • I create all my labels, buttons, etc
  • I set their translatesAutoresizingMaskIntoConstraintsproperty to NO
  • I add them as subviews of the contentViewof the cell
  • I add the constraints on the contentView
  • 我创建了我所有的标签、按钮等
  • 我将他们的translatesAutoresizingMaskIntoConstraints属性设置为 NO
  • 我将它们添加为contentView单元格的子视图
  • 我在 contentView

I'm also deeply interested in understanding why this happens only on iOS7.

我也很想了解为什么这种情况只发生在 iOS7 上。

回答by liamnichols

I had this problem as well.. It appears that the contentView's frame doesn't get updated until layoutSubviewsis called however the frame of the cell is updated earlier leaving the contentView's frame set to {0, 0, 320, 44}at the time when the constraints are evaluated.

我也有这个问题.. 似乎 contentView 的框架在layoutSubviews被调用之前不会更新, 但是单元格的框架更早更新,{0, 0, 320, 44}在评估约束时将contentView 的框架设置为。

After looking at the contentView in more detail, It appears that autoresizingMasks are no longer being set.

更详细地查看 contentView 后,似乎不再设置 autoresizingMasks。

Setting the autoresizingMask before you constrain your views can resolve this issue:

在约束视图之前设置 autoresizingMask 可以解决此问题:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self)
    {
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        [self loadViews];
        [self constrainViews];
    }
    return self;
}

回答by KoCMoHaBTa

Apparently there is something wrong with UITableViewCell and UICollectionViewCell on iOS 7 using iOS 8 SDK.

显然,使用 iOS 8 SDK 的 iOS 7 上的 UITableViewCell 和 UICollectionViewCell 存在问题。

You can update cell's contentView when the cell is reused like this:

当单元格被重用时,您可以更新单元格的 contentView ,如下所示:

For Static UITableViewController:

对于静态 UITableViewController:

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }

    //your code goes here

    return cell;
}

#endif
#endif

Since Static Table View Controllers are fragile and can easy be broken if you implement some datasource or deletegate methods - there are checks that will ensure that this code will only be compiled and run on iOS 7

由于静态表视图控制器是脆弱的,如果你实现一些数据源或删除门方法很容易被破坏 - 有一些检查可以确保这些代码只能在 iOS 7 上编译和运行

It is similar for standard dynamic UITableViewController:

它与标准动态 UITableViewController 类似:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }
    //your code goes here       
    return cell;
}

For this case we don't need the compilation extra check, since implementing this method is required.

对于这种情况,我们不需要编译额外检查,因为需要实现此方法。

The idea is the same for both cases and for UICollectionViewCell, like commented in this thread: Autoresizing issue of UICollectionViewCell contentView's frame in Storyboard prototype cell (Xcode 6, iOS 8 SDK) happens when running on iOS 7 only

对于这两种情况和 UICollectionViewCell 的想法是相同的,就像在这个线程中评论的一样:故事板原型单元(Xcode 6,iOS 8 SDK)中 UICollectionViewCell contentView's frame 的自动调整问题仅在 iOS 7 上运行时发生

回答by Steven

As cells are being reused and the height can change based on the content, I think in general it would be better to set the priority of spacings to less than required.

由于单元格被重用并且高度可以根据内容改变,我认为通常将间距的优先级设置为小于要求会更好。

In your case the UIImageView has a spacing of 15 to the top and the bottom view has a spacing of 0 to the bottom. If you set the priority of those constraints to 999 (instead of 1000), the app will not crash, because the constraints are not required.

在您的情况下,UIImageView 与顶部的间距为 15,底部视图与底部的间距为 0。如果您将这些约束的优先级设置为 999(而不是 1000),则应用程序不会崩溃,因为不需要这些约束。

Once the layoutSubviews method is called, the cell will have the correct height, and the constraints can be satisfied normally.

一旦调用 layoutSubviews 方法,单元格就会有正确的高度,并且可以正常满足约束。

回答by catamphetamine

I still didn't find a good solution for storyboards... Some info also here: https://github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

我仍然没有找到故事板的好解决方案......这里还有一些信息:https: //github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

From what they advice there:

从他们那里的建议来看:

self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

I've induced my solution:

我已经诱导了我的解决方案:

  • right click the storyboard
  • Open As -> Source Code
  • search for string "44" there
  • it's gonna be like
  • 右键单击故事板
  • 打开为 -> 源代码
  • 在那里搜索字符串“44”
  • 它会像

.

.

<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
        <rect key="frame" x="0.0" y="22" width="320" height="44"/>

.

.

  • replace rowHeight="44" with rowHeight="9999" and height="44" with height="9999"
  • right click the storyboard
  • Open As -> Interface Builder
  • run your app and check the output
  • 将 rowHeight="44" 替换为 rowHeight="9999",将 height="44" 替换为 height="9999"
  • 右键单击故事板
  • 打开为 -> 界面生成器
  • 运行您的应用程序并检查输出

回答by Vadim Yelagin

Just increase the default cell height. Looks like the problem is that the content of the cell is larger than the default (initial) cell size, violating some non-negativity constraints until the cell is resized to its actual size.

只需增加默认单元格高度即可。看起来问题在于单元格的内容大于默认(初始)单元格大小,违反了一些非负约束,直到将单元格调整为实际大小。

回答by heramerom

Maybe set the view's priority large than 750 and less than 1000 can solve.

也许将视图的优先级设置为大于 750 小于 1000 可以解决。

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",

回答by Cormentis

I had the same problem. My solution based upon others above:

我有同样的问题。我的解决方案基于上述其他人:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // initialize my stuff
        [self layoutSubviews]; // avoid debugger warnings regarding constraint conflicts
    }
    return self;
}

Best, Alessandro

最好的,亚历山德罗

回答by Centurion

I'v also faced this problem and none of the suggestions helped. In my case I had size selection cell, and it contained collectionView inside (every collectionView cell contained full size image). Now, the cell size heigh was a little bit bigger (60) than the collectionView (50) and images inside it (50). Because of that collectionView view has align bottom to superview constraint with a value of 10. That case me a warning, and the only way to fix that was to make cell height the same as its collectionView.

我也遇到过这个问题,但没有任何建议有帮助。在我的例子中,我有大小选择单元格,它里面包含 collectionView(每个 collectionView 单元格都包含完整大小的图像)。现在,单元格大小的高度 (60) 比 collectionView (50) 和其中的图像 (50) 大一点。由于该 collectionView 视图具有 align bottom to superview 约束,值为 10。在这种情况下,我发出警告,解决该问题的唯一方法是使单元格高度与其 collectionView 相同。

回答by Renetik

I ended up by not using UITableViewCell in designer at all... I create there custom view and add it to content view of cell programmatically... With some help categories there is also no code boilerplate...

我最终没有在设计器中使用 UITableViewCell ......我在那里创建自定义视图并以编程方式将其添加到单元格的内容视图......使用一些帮助类别也没有代码样板......

回答by NSDeveloper

If it works fine in iOS8,and get the warning in iOS7,you can search the storyboard source code, and find the right tableviewCell, then append the rect attribute after the tableviewCell line. Thanks to kuchumovn.

如果它在iOS8中运行良好,并且在iOS7中得到警告,您可以搜索storyboard源代码,找到正确的tableviewCell,然后在tableviewCell行后面附加rect属性。感谢kuchumovn

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>