Skip to content

Instantly share code, notes, and snippets.

@LePips
Created August 30, 2022 03:45
Show Gist options
  • Save LePips/c37a83c8a09c229c641aed90f509bfba to your computer and use it in GitHub Desktop.
Save LePips/c37a83c8a09c229c641aed90f509bfba to your computer and use it in GitHub Desktop.
struct NavBarDrawerButtonsModifier<Buttons: View>: ViewModifier {
let buttons: () -> Buttons
init(@ViewBuilder buttons: @escaping () -> Buttons) {
self.buttons = buttons
}
func body(content: Content) -> some View {
NavBarDrawerButtonsView {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
buttons()
}
.padding(.horizontal)
}
.ignoresSafeArea()
} content: {
content
}
.ignoresSafeArea()
}
}
extension View {
func navBarDrawerButtons<Buttons: View>(@ViewBuilder _ buttons: @escaping () -> Buttons) -> some View {
self.modifier(NavBarDrawerButtonsModifier(buttons: buttons))
}
}
struct NavBarDrawerButtonsView<Buttons: View, Content: View>: UIViewControllerRepresentable {
private let buttons: () -> Buttons
private let content: () -> Content
init(
@ViewBuilder buttons: @escaping () -> Buttons,
@ViewBuilder content: @escaping () -> Content
) {
self.buttons = buttons
self.content = content
}
func makeUIViewController(context: Context) -> UINavBarButtonsHostingController<Buttons, Content> {
UINavBarButtonsHostingController(buttons: buttons, content: content)
}
func updateUIViewController(_ uiViewController: UINavBarButtonsHostingController<Buttons, Content>, context: Context) {}
}
class UINavBarButtonsHostingController<Buttons: View, Content: View>: UIViewController {
private let buttons: () -> Buttons
private let content: () -> Content
private lazy var navBarBlurView: UIVisualEffectView = {
let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .systemThinMaterial))
blurView.translatesAutoresizingMaskIntoConstraints = false
return blurView
}()
private lazy var contentView: UIHostingController<Content> = {
let contentView = UIHostingController(rootView: content())
contentView.view.translatesAutoresizingMaskIntoConstraints = false
contentView.view.backgroundColor = nil
return contentView
}()
private lazy var drawerButtonsView: UIHostingController<Buttons> = {
let drawerButtonsView = UIHostingController(rootView: buttons())
drawerButtonsView.view.translatesAutoresizingMaskIntoConstraints = false
drawerButtonsView.view.backgroundColor = nil
return drawerButtonsView
}()
init(
buttons: @escaping () -> Buttons,
content: @escaping () -> Content
) {
self.buttons = buttons
self.content = content
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = nil
addChild(contentView)
view.addSubview(contentView.view)
contentView.didMove(toParent: self)
view.addSubview(navBarBlurView)
addChild(drawerButtonsView)
view.addSubview(drawerButtonsView.view)
drawerButtonsView.didMove(toParent: self)
NSLayoutConstraint.activate([
drawerButtonsView.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -40),
drawerButtonsView.view.heightAnchor.constraint(equalToConstant: 40),
drawerButtonsView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
drawerButtonsView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
NSLayoutConstraint.activate([
navBarBlurView.topAnchor.constraint(equalTo: view.topAnchor),
navBarBlurView.bottomAnchor.constraint(equalTo: drawerButtonsView.view.bottomAnchor),
navBarBlurView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
navBarBlurView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
NSLayoutConstraint.activate([
contentView.view.topAnchor.constraint(equalTo: view.topAnchor),
contentView.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
contentView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
contentView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.shadowImage = nil
}
override var additionalSafeAreaInsets: UIEdgeInsets {
get {
.init(top: 40, left: 0, bottom: 0, right: 0)
}
set {
super.additionalSafeAreaInsets = .init(top: 40, left: 0, bottom: 0, right: 0)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment