动态添加子视图到单元格导致布局约束错误输出

Adding subview to cell dynamically is causing layout constraint error output

我有一个 table 单元格视图,其中包含几个按钮和一些细节。在触摸其中一个按钮之前,细节会隐藏起来,而在触摸另一个按钮时会被移除。我正在使用自动布局。

这是添加控件和配置约束的代码(控件已重命名以保护我的客户端)。代码是 C# 但等效 Obj-C/Swift 应该相当明显:

this.ContentView.AddSubviews(this.firstButton, this.secondButton);
this.detailView.AddSubviews(this.textField1, this.textField2, this.textField3, this.textField4, this.textField5);

this.ContentView.ConstrainLayout(() =>
    this.firstButton.Top() == this.ContentView.Top() + Layout.StandardSiblingViewSpacing &&
    this.firstButton.Bottom() <= this.ContentView.Bottom() - Layout.StandardSiblingViewSpacing &&
    this.firstButton.Left() == this.ContentView.Left() + Layout.StandardSuperviewSpacing &&
    this.secondButton.Top() == this.firstButton.Top() &&
    this.secondButton.Bottom() <= this.ContentView.Bottom() - Layout.StandardSiblingViewSpacing &&
    this.secondButton.Left() == this.firstButton.Left());

this.detailView.ConstrainLayout(() =>
    this.textField1.Top() == this.detailView.Top() &&
    this.textField1.Left() == this.detailView.Left() &&
    this.textField1.Right() == this.detailView.Right() &&
    this.textField2.Top() == this.textField1.Bottom() + Layout.StandardSiblingViewSpacing &&
    this.textField2.Left() == this.textField1.Left() &&
    this.textField2.Right() == this.textField1.Right() &&
    this.textField3.Top() == this.textField2.Bottom() + Layout.StandardSiblingViewSpacing &&
    this.textField3.Left() == this.textField2.Left() &&
    this.textField3.Right() == this.textField2.Right() &&
    this.textField4.Top() == this.textField3.Bottom() + Layout.StandardSiblingViewSpacing &&
    this.textField4.Left() == this.textField3.Left() &&
    this.textField4.Right() == this.textField3.Right() &&
    this.textField5.Top() == this.textField4.Bottom() + Layout.StandardSiblingViewSpacing &&
    this.textField5.Bottom() <= this.detailView.Bottom() - Layout.StandardSiblingViewSpacing &&
    this.textField5.Left() == this.textField4.Left() &&
    this.textField5.Right() == this.textField4.Right());

detailView 中的动画代码如下所示:

private void AnimateDetailsIn()
{
    this.ContentView.AddSubview(this.detailView);
    this.ContentView.ConstrainLayout(() =>
        this.detailView.Top() == this.ContentView.Top() + Layout.StandardSiblingViewSpacing &&
        this.detailView.Bottom() <= this.ContentView.Bottom() - Layout.StandardSiblingViewSpacing &&
        this.detailView.Left() == this.secondButton.Right() + Layout.StandardSiblingViewSpacing &&
        this.detailView.Right() == this.ContentView.Right() - Layout.StandardSuperviewSpacing);

    var tableView = this.FindParent<UITableView>();

    if (tableView == null)
    {
        return;
    }

    tableView.BeginUpdates();
    tableView.EndUpdates();
}

每当调用 AnimateDetailsIn 时,所有内容 在屏幕上看起来 都很好,但我在输出中看到此错误消息:

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:0x7fccb670 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fd8efd0(36)]>",
    "<NSLayoutConstraint:0x7fd94330 V:|-(0)-[UITextField:0x7fd905a0]   (Names: '|':UIView:0x7fd90050 )>",
    "<NSLayoutConstraint:0x7fd943c0 V:[UITextField:0x7fd905a0]-(8)-[UITextField:0x7fd90e90]>",
    "<NSLayoutConstraint:0x7fd94450 V:[UITextField:0x7fd90e90]-(8)-[UITextField:0x7fd91720]>",
    "<NSLayoutConstraint:0x7fd944e0 V:[UITextField:0x7fd91720]-(8)-[UITextField:0x7fd91fb0]>",
    "<NSLayoutConstraint:0x7fd94570 V:[UITextField:0x7fd91fb0]-(8)-[UITextField:0x7fd92850]>",
    "<NSLayoutConstraint:0x7fd945a0 UITextField:0x7fd92850.bottom <= UIView:0x7fd90050.bottom - 8>",
    "<NSLayoutConstraint:0x7fdaa080 V:|-(8)-[UIView:0x7fd90050]   (Names: '|':UITableViewCellContentView:0x7fd8efd0 )>",
    "<NSLayoutConstraint:0x7fdaa200 UIView:0x7fd90050.bottom <= UITableViewCellContentView:0x7fd8efd0.bottom - 8>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fd94570 V:[UITextField:0x7fd91fb0]-(8)-[UITextField:0x7fd92850]>

为了排除故障,我尝试从一开始就在视图层次结构中包含 detailView 并删除动画。这工作正常(没有错误输出,一切都正确显示)。很明显,我在这里的处理方式有些不对劲。谁能告诉我如何在使用自动布局时为我的 detailView 设置动画而不会出现错误输出?

将子视图添加到内容视图后,您需要在每个子视图上将 'translatesautoresizingmaskintoconstraints' 设置为 NO。你在某个地方这样做吗?否则系统会添加自己的一堆你不想要的约束。如果你还没有,你能试试吗

为了回答我自己的问题,问题归结为以下突出显示的约束之间的相互作用:

前两个是(我认为)UITableViewCell自动添加的。它们具有最高优先级 (1000)。另外两个突出显示的约束是我用此代码添加的前两个(顶部和底部):

this.ContentView.ConstrainLayout(() =>
        this.detailView.Top() == this.ContentView.Top() + Layout.StandardSiblingViewSpacing &&
        this.detailView.Bottom() <= this.ContentView.Bottom() - Layout.StandardSiblingViewSpacing &&
        this.detailView.Left() == this.secondButton.Right() + Layout.StandardSiblingViewSpacing &&
        this.detailView.Right() == this.ContentView.Right() - Layout.StandardSuperviewSpacing);

问题是我的约束也是以最高优先级添加的。由于我的约束(暂时)与 UITableViewCell 自动施加的约束冲突,我收到约束错误。

"solution"(我认为这有点 hack)是为了降低我的约束的优先级,这样就不会有冲突。

虽然这解决了问题,但它确实改变了显示细节视图时执行的动画的性质。它们不是我的 "expanding" 更改,而是从上到下滑动。当您考虑时,这是有道理的 - 由于优先级降低,我的详细信息视图不再受限于内容视图的大小。

唉,我还不知道解决这个问题的办法,所以现在只能凑合着用低于标准的动画。

PS。感谢 Reuben Scratton,他用 this post.

为我指明了正确的方向