Created
May 14, 2020 18:10
-
-
Save mrfarukturgut/2e3bb23774bae7649183743268db3e86 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Original code from https://github.com/SwiftUIX/SwiftUIX by @vmanot | |
import Foundation | |
import SwiftUI | |
import UIKit | |
extension View { | |
@inlinable | |
public func navigationBarItems<Leading: View, Center: View, Trailing: View>( | |
leading: Leading, | |
center: Center, | |
trailing: Trailing, | |
displayMode: NavigationBarItem.TitleDisplayMode? = .automatic | |
) -> some View { | |
background(NavigationBarConfigurator(leading: leading, center: center, trailing: trailing, displayMode: displayMode)) | |
} | |
@inlinable | |
public func navigationBarItems<Leading: View, Center: View>( | |
leading: Leading, | |
center: Center, | |
displayMode: NavigationBarItem.TitleDisplayMode = .automatic | |
) -> some View { | |
navigationBarItems(leading: leading, center: center, trailing: EmptyView(), displayMode: displayMode) | |
} | |
@inlinable | |
public func navigationBarTitleView<V: View>( | |
_ center: V, | |
displayMode: NavigationBarItem.TitleDisplayMode | |
) -> some View { | |
navigationBarItems(leading: EmptyView(), center: center, trailing: EmptyView(), displayMode: displayMode) | |
} | |
@inlinable | |
public func navigationBarTitleView<V: View>( | |
_ center: V | |
) -> some View { | |
navigationBarItems(leading: EmptyView(), center: center, trailing: EmptyView(), displayMode: .automatic) | |
} | |
@inlinable | |
public func navigationBarItems<Center: View, Trailing: View>( | |
center: Center, | |
trailing: Trailing, | |
displayMode: NavigationBarItem.TitleDisplayMode = .automatic | |
) -> some View { | |
navigationBarItems(leading: EmptyView(), center: center, trailing: trailing, displayMode: displayMode) | |
} | |
} | |
@usableFromInline | |
struct NavigationBarConfigurator<Leading: View, Center: View, Trailing: View>: UIViewControllerRepresentable { | |
@usableFromInline | |
class UIViewControllerType: UIViewController { | |
var leading: Leading? { | |
didSet { | |
updateNavigationBar(parent: parent) | |
} | |
} | |
var center: Center? { | |
didSet { | |
updateNavigationBar(parent: parent) | |
} | |
} | |
var trailing: Trailing? { | |
didSet { | |
updateNavigationBar(parent: parent) | |
} | |
} | |
var displayMode: NavigationBarItem.TitleDisplayMode? { | |
didSet { | |
updateNavigationBar(parent: parent) | |
} | |
} | |
override func willMove(toParent parent: UIViewController?) { | |
updateNavigationBar(parent: parent) | |
super.willMove(toParent: parent) | |
} | |
private func updateNavigationBar(parent: UIViewController?) { | |
guard let parent = parent else { | |
return | |
} | |
#if os(iOS) || targetEnvironment(macCatalyst) | |
if let displayMode = displayMode { | |
switch displayMode { | |
case .automatic: | |
parent.navigationItem.largeTitleDisplayMode = .automatic | |
case .inline: | |
parent.navigationItem.largeTitleDisplayMode = .never | |
case .large: | |
parent.navigationItem.largeTitleDisplayMode = .always | |
@unknown default: | |
parent.navigationItem.largeTitleDisplayMode = .automatic | |
} | |
} | |
#endif | |
if let leading = leading { | |
if !(leading is EmptyView) { | |
if parent.navigationItem.leftBarButtonItem == nil { | |
parent.navigationItem.leftBarButtonItem = .init(customView: UIHostingView(rootView: leading)) | |
} else if let view = parent.navigationItem.leftBarButtonItem?.customView as? UIHostingView<Leading> { | |
view.rootView = leading | |
} else { | |
parent.navigationItem.leftBarButtonItem?.customView = UIHostingView(rootView: leading) | |
} | |
} | |
} else { | |
parent.navigationItem.leftBarButtonItem = nil | |
} | |
if let center = center { | |
if !(center is EmptyView) { | |
if let view = parent.navigationItem.titleView as? UIHostingView<Center> { | |
view.rootView = center | |
} else { | |
parent.navigationItem.titleView = UIHostingView(rootView: center) | |
} | |
} | |
} else { | |
parent.navigationItem.titleView = nil | |
} | |
if let trailing = trailing { | |
if !(trailing is EmptyView) { | |
if parent.navigationItem.rightBarButtonItem == nil { | |
parent.navigationItem.rightBarButtonItem = .init(customView: UIHostingView(rootView: trailing)) | |
} else if let view = parent.navigationItem.rightBarButtonItem?.customView as? UIHostingView<Trailing> { | |
view.rootView = trailing | |
} else { | |
parent.navigationItem.rightBarButtonItem?.customView = UIHostingView(rootView: trailing) | |
} | |
} | |
} else { | |
parent.navigationItem.rightBarButtonItem = nil | |
} | |
parent.navigationItem.leftBarButtonItem?.customView?.sizeToFit() | |
parent.navigationItem.titleView?.sizeToFit() | |
parent.navigationItem.rightBarButtonItem?.customView?.sizeToFit() | |
} | |
} | |
let leading: Leading | |
let center: Center | |
let trailing: Trailing | |
let displayMode: NavigationBarItem.TitleDisplayMode? | |
@usableFromInline | |
init( | |
leading: Leading, | |
center: Center, | |
trailing: Trailing, | |
displayMode: NavigationBarItem.TitleDisplayMode? | |
) { | |
self.leading = leading | |
self.center = center | |
self.trailing = trailing | |
self.displayMode = displayMode | |
} | |
@usableFromInline | |
func makeUIViewController(context: Context) -> UIViewControllerType { | |
.init() | |
} | |
@usableFromInline | |
func updateUIViewController(_ viewController: UIViewControllerType, context: Context) { | |
viewController.displayMode = displayMode | |
viewController.leading = leading | |
viewController.center = center | |
viewController.trailing = trailing | |
} | |
} | |
/// A `UIView` subclass capable of hosting a SwiftUI view. | |
open class UIHostingView<Content: View>: UIView { | |
private let rootViewHostingController: UIHostingController<Content> | |
public var rootView: Content { | |
get { | |
return rootViewHostingController.rootView | |
} set { | |
rootViewHostingController.rootView = newValue | |
} | |
} | |
public required init(rootView: Content) { | |
self.rootViewHostingController = UIHostingController(rootView: rootView) | |
super.init(frame: .zero) | |
rootViewHostingController.view.backgroundColor = .clear | |
addSubview(rootViewHostingController.view) | |
} | |
public required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override open func sizeThatFits(_ size: CGSize) -> CGSize { | |
rootViewHostingController.sizeThatFits(in: size) | |
} | |
override open func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize { | |
rootViewHostingController.sizeThatFits(in: targetSize) | |
} | |
override open func systemLayoutSizeFitting( | |
_ targetSize: CGSize, | |
withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, | |
verticalFittingPriority: UILayoutPriority | |
) -> CGSize { | |
rootViewHostingController.sizeThatFits(in: targetSize) | |
} | |
override open func layoutSubviews() { | |
super.layoutSubviews() | |
rootViewHostingController.view.frame = bounds | |
} | |
override open func sizeToFit() { | |
if let superview = superview { | |
frame.size = rootViewHostingController.sizeThatFits(in: superview.frame.size) | |
} else { | |
super.sizeToFit() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment