Auto Layout iOS 11 Toolbar UIBarButtonItem with customView

夙愿已清 提交于 2020-01-23 03:11:07

问题


Recently in our project there was a problem with a UIBarButtonItem that was using a customView. Before iOS 11 we did the layout via flexible spacing items. This didn't work anymore and so nothing was displayed.

Because I didn't find an answer here on SO that really solved the issue for me, I looked into it and came up with a (admittedly kind of hacky) solution I wanted to share with you.

Maybe it can help you or you have some feedback. This is mixed objc and swift code, hope you don't mind.


回答1:


As shown in the WWDC Video Updating Your App for iOS 11:

"And so now in iOS 11, UI toolbar and UI navigation bar both have intricate and express support for auto layout."

So my first step was to use layout constraints on he custom view itself:

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

This resulted in the toolbar showing the customView. The problem was that left and right of the view, there was a gap. And you could see it. So I looked in the View Hierarchy Debugging tool and realized, there is a UIToolbarContentView on the toolbar. This contentView had the right size (especially width) and I began wondering. I looked at the only subview the contentView had and it was a UIBarButtonStackView. This stackView was somehow limiting my customView in terms of width.

So it looks like this:

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

What made me curios was, that the customView is not a subview of the stackView. This is probably a consequence of the customView being included in UIBarButtonItem. Any (additional) constrains on the customView remained without change (or crashes because the views aren't in the same hierarchy).

After learing all this, I added an extension to the 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

    }
}

So what it does is this: It gets the contentView from the subviews by comparing the names to "ContentView" and gets the stackView by doing the same on the contentView. Probably a return subviews.first would do the same, but I wanted to be sure.

Then the layout constraints are set and voila: it works in the full width.

I hope someone may find this useful. If there's comments: I'm very open to feedback on this one. Maybe I missed something and all this isn't even necessary.

Edit: The 'find' function is an extension to Sequence. It does 'filter.first' and looks like this:

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

}



来源:https://stackoverflow.com/questions/46581263/auto-layout-ios-11-toolbar-uibarbuttonitem-with-customview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!