奇怪的 iOS 8 自动布局问题

Posted

技术标签:

【中文标题】奇怪的 iOS 8 自动布局问题【英文标题】:Strange iOS 8 auto layout issue 【发布时间】:2014-10-15 15:04:03 【问题描述】:

我有一个自定义 UITableViewCell。

    最初在单元格的内容视图上设置了一些子视图和一些自动布局约束。一切正常。 然后我以编程方式更改(删除/添加)一些子视图并完全重置约束(删除所有,然后添加新约束)。之后,包含单元格的 UITable 会被刷新(重新计算行高)并且 setNeedsUpdateContraintsupdateConstraintsIfNeeded 也会在单元格上显式调用。

这里是重现问题的完整代码。它在 C# (Xamarin) 中,但很容易阅读这个想法。 Here is Swift 中几乎相同的代码。

public class TableViewController : UITableViewController

    public override void ViewDidLoad()
    
        base.ViewDidLoad();

        var source = new TableSource(TableView);

        var updateButton = new UIBarButtonItem("Update", UIBarButtonItemStyle.Plain, (s, args) => source.DoUpdate());
        NavigationItem.RightBarButtonItem = updateButton;

        TableView.Source = source;
        TableView.ReloadData();
    


public class TableSource : UITableViewSource

    private readonly UITableView _tableView;
    private readonly TableCell _cell;

    public TableSource(UITableView tableView)
    
        _tableView = tableView;
        _cell = new TableCell();
    

    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
    
        return _cell;
    

    public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
    
        return 55.0f;
    

    public override int RowsInSection(UITableView tableview, int section)
    
        return 1;
    

    public void DoUpdate()
    
        _cell.DoUpdate();
        _tableView.ReloadData();
    


public class TableCell : UITableViewCell

    private UILabel _label;

    public TableCell()
    
        DoUpdate();
    

    public void DoUpdate()
    
        foreach (var subview in ContentView.Subviews)
        
            subview.RemoveFromSuperview();
        

        _label = new UILabel Text = "Text here";
        ContentView.Add(_label);

        foreach (var subview in ContentView.Subviews)
        
            subview.TranslatesAutoresizingMaskIntoConstraints = false;
        

        ContentView.RemoveConstraints(ContentView.Constraints);
        ContentView.AddConstraints(
            new[]
            
                NSLayoutConstraint.Create(_label, NSLayoutAttribute.Left, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Left, 1.0f, 15.0f),
                NSLayoutConstraint.Create(_label, NSLayoutAttribute.Width, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1.0f, 100.0f),
                NSLayoutConstraint.Create(_label, NSLayoutAttribute.Top, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Top, 1.0f, 20.0f),
                NSLayoutConstraint.Create(_label, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Bottom, 1.0f, -20.0f)
            );
    

启动时一切正常:

但点击更新按钮后(重置子视图和约束):

iOS 7 上没有任何变化(按预期工作)。

iOS 8 上,布局无法按预期工作。看起来它失去了一些约束,定义了一些子视图和单元格的内容视图边界之间的边距:

任何想法为什么会发生这种情况?貌似是ios自动布局系统的bug。

【问题讨论】:

你在实现 heightForRowAtIndexPath 方法吗?屏幕截图或绘图可以很好地了解您所面临的布局问题。 是的,实现 heightForRowAtIndexPath。添加截图,谢谢。 请展示您创建约束的代码。 您不再需要使用 RevealApp。 Xcode 6 吞下了它。 :) 好吧,靠第三方框架在你和API之间生存的人,死于第三方框架在你和 API 之间。基本上这是在你和 xamarin 之间,不管是什么。我的意思是,是的,自动布局在 iOS 8 中已经 发生了变化,因为现在有 layoutMargins,但是 xamarin 可能知道也可能不知道这是任何人的猜测。 【参考方案1】:

是的,iOS 8 AutoLayout 现在真的定义了边距。

更新

你这样做打破了contentView的约束:

ContentView.RemoveConstraints(ContentView.Constraints);

这一行打破了contentView 与其父级的关系。删除此行。

【讨论】:

所有约束都是在代码中创建的,所以我没有使用与边距相关的约束。 @alexey,不过,|-[subview]-| 为您提供相对于边距。请改用|[subview]|。并检查UIViewlayoutMargins 属性。 我猜字符串描述包含'-',因为 Xamarin 实现。我肯定会使用 NSLayoutAttribute 定义所有约束,并且从不使用新的 iOS 8 类型的属性。 @alexey,好的,我明白了。所以我可以建议你首先联系 lib creator。然后更改您的代码,为 iOS8/pre-iOS8 版本使用不同的值。某种解决方法。 @orkenstrein,完全更新了问题。现在的示例要简单得多。还删除了对库的任何依赖项。所以库不是问题。

以上是关于奇怪的 iOS 8 自动布局问题的主要内容,如果未能解决你的问题,请参考以下文章

iOS9 此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃

iOS 7 自动布局与 iOS 8 自适应布局,有区别吗?

iOS 9 键盘:此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃

在 iOS 8 中如何在不使用自动布局的情况下布局 UITableViewCell?

Xcode 8 - 自动布局问题

iOS 自动布局 ios 7 与 ios 8