0

I'm integrating SwiftUI into UINavigationController and encounter weird issue when pushing a UIHostingController containing a long Image or AsyncImage. I want the image to occupy the whole screen width so I use

      Image("picsum-237-1900x400") 
        .resizable()
        .scaledToFill()
        .frame(height: 200)
        .frame(maxWidth: .infinity)

This display normally with the usual NavigationStack and NavigationLink. But when I use it with NavigationWrapper, the image overflows from the screen.

struct NavigationWrapper<Content: View>: UIViewControllerRepresentable {
  @ViewBuilder let rootView: () -> Content
  
  func makeUIViewController(context: Context) -> UINavigationController {
    let navController = UINavigationController()
    let hostingController = UIHostingController(
      rootView: rootView().environment(\.navigationController, navController)
    )
    navController.pushViewController(hostingController, animated: false)
    return navController
  }
  
  func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
}

Usage:

@main
struct MainApp: App {
  var body: some Scene {
    WindowGroup {
      NavigationWrapper(rootView: { ProductView() })
    }
  }
}

struct ProductView: View {
  @Environment(\.navigationController) private var navigationController
  
  var body: some View {
    VStack {
      Button("Go to Product Details") {
        let hostingVC = UIHostingController(rootView: ProductDetailsScreen())
        navigationController?.pushViewController(hostingVC, animated: true)
      }
    }
    .navigationTitle("Products")
  }
}

struct ProductDetailsScreen: View {
  var body: some View {
    VStack {
      Image("picsum-237-1900x400")
        .resizable()
        .scaledToFill()
        .frame(height: 200)
        .frame(maxWidth: .infinity)
      Spacer()
      Text("Product Details")
      Spacer()
    }
    .navigationTitle("Details")
  }
}

struct NavigationControllerKey: EnvironmentKey {
  static let defaultValue: UINavigationController? = nil
}

extension EnvironmentValues {
  var navigationController: UINavigationController? {
    get { self[NavigationControllerKey.self] }
    set { self[NavigationControllerKey.self] = newValue }
  }
}

To simplify the demonstration, I downloaded a similar sized image and use Image instead of AsyncImage:

long image from picsum

Are there some concepts that I'm missing about bridging SwiftUI and UIKit, or is this a bug in SwiftUI and is there any workaround for it?

1 Answer 1

0

I think maybe the view cannot get the right width anchor when using UINavigationController. This code is supposed to help.

struct ProductDetailsScreen: View {
  var body: some View {
      GeometryReader { proxy in
          VStack {
              Image("picsum-237-1900x400")
                  .resizable()
                  .scaledToFill()
                  .frame(height: 200)
                  .frame(maxWidth: proxy.size.width)
                  .clipped()
              Spacer()
              Text("Product Details")
              Spacer()
          }
          .navigationTitle("Details")
      }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.