奇怪的 iOS 8 自动布局问题
Posted
技术标签:
【中文标题】奇怪的 iOS 8 自动布局问题【英文标题】:Strange iOS 8 auto layout issue 【发布时间】:2014-10-15 15:04:03 【问题描述】:我有一个自定义 UITableViewCell。
-
最初在单元格的内容视图上设置了一些子视图和一些自动布局约束。一切正常。
然后我以编程方式更改(删除/添加)一些子视图并完全重置约束(删除所有,然后添加新约束)。之后,包含单元格的 UITable 会被刷新(重新计算行高)并且 setNeedsUpdateContraints、updateConstraintsIfNeeded 也会在单元格上显式调用。
这里是重现问题的完整代码。它在 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]|
。并检查UIView
的layoutMargins
属性。
我猜字符串描述包含'-',因为 Xamarin 实现。我肯定会使用 NSLayoutAttribute 定义所有约束,并且从不使用新的 iOS 8 类型的属性。
@alexey,好的,我明白了。所以我可以建议你首先联系 lib creator。然后更改您的代码,为 iOS8/pre-iOS8 版本使用不同的值。某种解决方法。
@orkenstrein,完全更新了问题。现在的示例要简单得多。还删除了对库的任何依赖项。所以库不是问题。以上是关于奇怪的 iOS 8 自动布局问题的主要内容,如果未能解决你的问题,请参考以下文章
iOS9 此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃
iOS 9 键盘:此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃