Search code examples
swiftswiftuiios13uitoolbaruiviewrepresentable

UIToolbar in iOS 13 SwiftUI?


I'm attempting to adapt UIToolbar to UIViewRepresentable to use it within SwiftUI. I'm required to support iOS 13, otherwise I would be using Apple's new toolbar in iOS 14.

So far I have code that displays the toolbar on the screen, however it doesn't extend to the safe area at the bottom of the screen for devices with no home button.

Does anyone have any suggestions or references for complete UIToolbar implementations in SwiftUI?

Image:

https://i.sstatic.net/Weutp.png

My code:

// TestView.swift
var body: some View {
  VStack {
    Toolbar(items: [
      UIBarButtonItem(
         title: "Done",
         style: .plain,
         target: nil,
         action: nil
    ])
  }
}

// Toolbar.swift
import SwiftUI
import UIKit
import Foundation

struct Toolbar: UIViewRepresentable {
    typealias UIViewType = UIToolbar
    var items: [UIBarButtonItem]
    var toolbar: UIToolbar
    
    init(items: [UIBarButtonItem]) {
        self.toolbar = UIToolbar()
        self.items = items
    }

    func makeUIView(context: UIViewRepresentableContext<Toolbar>) -> UIToolbar {
        toolbar.setItems(self.items, animated: true)
        toolbar.barStyle = UIBarStyle.default
        toolbar.sizeToFit()
        return toolbar
    }
    
    func updateUIView(_ uiView: UIToolbar, context: UIViewRepresentableContext<Toolbar>) {
    }
    
    func makeCoordinator() -> Toolbar.Coordinator {
        Coordinator(self)
    }
    
    final class Coordinator: NSObject, UIToolbarDelegate, UIBarPositioning {
        var toolbar: Toolbar
        var barPosition: UIBarPosition
        
        init(_ toolbar: Toolbar) {
            self.toolbar = toolbar
            self.barPosition = .bottom
        }
        
        private func position(for: UIToolbar) -> UIBarPosition {
            return .bottom
        }
    }
}

Solution

  • Any UIViewRepresentable in context of SwiftUI view hierarchy is just a view, so it should be layout by SwiftUI instruments

    Here is fixed part (w/o changes in your representable)

    Tested with Xcode 11.4 / iOS 13.4

    demo

    struct DemoToolbarView: View {
        var body: some View {
            VStack {
                Toolbar(items: [
                    UIBarButtonItem(
                        title: "Done",
                        style: .plain,
                        target: nil,
                        action: nil)
                ])
            }.frame(maxHeight: .infinity, alignment: .bottom)
            .edgesIgnoringSafeArea(.bottom)
        }
    }