自动布局iOS 11工具栏与customView的UIBarButtonItem

最近在我们的项目中,使用customView的UIBarButtonItem存在问题。 在iOS 11之前,我们通过灵活的间距项目进行了布局。 这不起作用,所以什么也没有显示。

因为我在这里没有find答案,真正解决了我的问题,所以我研究了一下,并提出了一个我想与大家分享的(一种可靠的解决scheme)解决scheme。

也许它可以帮助你,或者你有一些反馈。 这是混合objc和swift代码,希望你不介意。

如WWDCvideo更新您的iOS版本11所示 :

“而现在在iOS 11中,UI工具栏和UI导航栏都有错综复杂的自动布局支持。”

所以我的第一步是对自定义视图本身使用布局约束:

UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customView]; [barButtonItem.customView.widthAnchor constraintEqualToConstant:375].active = YES; [barButtonItem.customView.heightAnchor constraintEqualToConstant:44].active = YES; 

这导致在工具栏显示customView。 问题是这个观点的左右两边存在差距。 你可以看到它。 所以我查看了View Hierarchy Debugging工具,发现工具栏上有一个UIToolbarContentView。 这contentView有正确的大小(尤其是宽度),我开始想知道。 我查看了contentView的唯一子视图,它是一个UIBarButtonStackView。 这个stackView以某种方式限制了我的customView的宽度。

所以看起来像这样:

 contentView |<-fullWidth-------->| stackView |<-reducedWidth->| customView |<-reducedWidth->| 

让我好奇的是,customView不是stackView的子视图。 这可能是customView包含在UIBarButtonItem中的结果。 自定义视图上的任何(额外)约束都保持不变(或因为视图不在同一层次结构中而崩溃)。

在学习完所有这些之后,我在UIToolbar中添加了一个扩展:

 extension UIToolbar { private var contentView: UIView? { return subviews.find { (view) -> Bool in let viewDescription = String(describing: type(of: view)) return viewDescription.contains("ContentView") } } private var stackView: UIView? { return contentView?.subviews.find { (view) -> Bool in let viewDescription = String(describing: type(of: view)) return viewDescription.contains("ButtonBarStackView") } } func fitContentViewToToolbar() { guard let stackView = stackView, let contentView = contentView else { return } stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true stackView.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true } } 

所以它是这样做的:它通过比较名称到“ContentView”从子视图获取contentView,并通过在contentView上执行相同的操作来获取stackView。 可能return subviews.first也会这样做,但我想确定。

然后设置布局约束,瞧:它工作在全宽度。

我希望有人可能会觉得这有用。 如果有评论:我很乐意回应这一个。 也许我错过了一些东西,而这一切都不是必要的。

编辑:“查找”function是序列的扩展。 它“filter.first”,看起来像这样:

 extension Sequence { func find(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> Self.Element? { return try filter(isIncluded).first } 

}