带有customView的自动布局iOS 11工具栏UIBarButtonItem
Posted
技术标签:
【中文标题】带有customView的自动布局iOS 11工具栏UIBarButtonItem【英文标题】:Auto Layout iOS 11 Toolbar UIBarButtonItem with customView 【发布时间】:2017-10-05 08:38:07 【问题描述】:最近在我们的项目中,使用 customView 的 UIBarButtonItem 出现问题。在 ios 11 之前,我们通过灵活间距项进行布局。这不再起作用,因此没有显示任何内容。
因为我在 SO 上没有找到真正为我解决问题的答案,所以我对其进行了调查,并提出了一个(诚然有点老套的)解决方案,我想与您分享。
也许它可以帮助你或者你有一些反馈。这是混合了 objc 和 swift 代码,希望你不要介意。
【问题讨论】:
【参考方案1】:如WWDC视频Updating Your App for 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 的子视图。这可能是 UIBarButtonItem 中包含 customView 的结果。 customView 上的任何(附加)约束保持不变(或由于视图不在同一层次结构中而崩溃)。
在了解了所有这些之后,我在 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
也会这样做,但我想确定一下。
然后设置布局约束,瞧:它以全宽工作。
我希望有人会觉得这很有用。如果有 cmets:我非常愿意接受对此的反馈。也许我错过了什么,而这一切都没有必要。
编辑:“查找”功能是对序列的扩展。它执行“filter.first”,看起来像这样:
extension Sequence
func find(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> Self.Element?
return try filter(isIncluded).first
【讨论】:
间隙可能由一些默认的 layoutMargins 定义,通常每边有 8 个点。出于某种原因,这里他们是 16 分H:|-(16)-[_UIButtonBarStackView
。
上述解决方案与已经为stackView定义的一些约束冲突..."<NSLayoutConstraint:0x60000028acd0 _UIButtonBarStackView:0x7ffbced16f10.trailing == _UIToolbarContentView:0x7ffbced16780.trailing - 16 (active)>"
!
感谢您的提醒。我没有注意到。也许可以事先删除这些。尽管这感觉越来越像是在摆弄 UIKit 内部......
提供的解决方案使用私有 API。我仍在尝试为此寻找解决方案。如果我找到它会发布。
@user1447414 您是否设法在不使用私有 API 的情况下找到了解决方案以上是关于带有customView的自动布局iOS 11工具栏UIBarButtonItem的主要内容,如果未能解决你的问题,请参考以下文章
带有 customView 的 UIBarButtonItem 在 iOS4.1 中消失了