1

In SwiftUI I have a simple custom toolbar with a Text:

import SwiftUI

struct ContentView: View {

    var body: some View {
        NavigationStack {
            VStack {
                Text("Hi")
            }
            .toolbar {
                ToolbarItem(placement: .principal) {
                    HStack {
                        Text("My Toolbar")
                            .border(.red)
                        Spacer()
                    }
                }

            }
        }
    }
}

When I run in portrait the text in the toolbar is shown correctly. When I rotate to landscape the text view is displaced:

Toolbar correctly rendered Displaced text in toolbar
enter image description here enter image description here

However when I run the app in landscape the UI renders correctly in both orientations.

enter image description here

What can I do to avoid a custom toolbar (not just a single string) breaking the layout when rotating from portrait to landscape?

0

1 Answer 1

0

If you want the toolbar item to be positioned on the left, the simplest workaround is to use placement .topBarLeading instead of .principal. Then you don't need the Spacer either, nor the HStack for that matter:

ToolbarItem(placement: .topBarLeading) {
    Text("My Toolbar")
        .border(.red)
}

However, if this simple workaround is not suitable for your purposes then you will need to force a rebuild when the orientation changes. The answers to SwiftUI Repaint View Components on Device Rotation describe various ways of doing this.

I find that wrapping the content in a GeometryReader is usually a pretty reliable technique. It works with iPad split screen too, which not all the answers to the other post will do. However, the change in geometry must cause a state change that necessitates a display refresh, otherwise SwiftUI will detect that there are no visible changes and there will be no refresh.

So here is a rather convoluted example that updates a counter when the geometry changes. The counter is then used to determine the spacing between the text and the Spacer:

struct ContentView: View {
    @State private var counter = 0

    var body: some View {
        GeometryReader { proxy in
            NavigationStack {
                VStack {
                    Text("Hi")
                }
                .toolbar {
                    ToolbarItem(placement: .principal) {
                        HStack(spacing: CGFloat(counter % 2)) {
                            Text("My Toolbar")
                                .border(.red)
                            Spacer()
                        }
                    }
                }
            }
            .onChange(of: proxy.size) {
                counter += 1
            }
        }
    }
}

If the orientation change will cause other display changes then it probably won't be so difficult to get the display to refresh.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.