SwiftUI 在详细视图中覆盖导航栏外观

Ker*_*rrM 6 swiftui uinavigationbarappearance swiftui-navigationlink

我有一个超级简单的 SwiftUI 主从应用程序:

import SwiftUI

struct ContentView: View {
    @State private var imageNames = [String]()

    var body: some View {
        NavigationView {
            MasterView(imageNames: $imageNames)
                .navigationBarTitle(Text("Master"))
                .navigationBarItems(
                    leading: EditButton(),
                    trailing: Button(
                        action: {
                            withAnimation {
                                // simplified for example
                                self.imageNames.insert("image", at: 0)
                            }
                        }
                    ) {
                        Image(systemName: "plus")
                    }
                )
        }
    }
}

struct MasterView: View {
    @Binding var imageNames: [String]

    var body: some View {
        List {
            ForEach(imageNames, id: \.self) { imageName in
                NavigationLink(
                    destination: DetailView(selectedImageName: imageName)
                ) {
                    Text(imageName)
                }
            }
        }
    }
}

struct DetailView: View {

    var selectedImageName: String

    var body: some View {
        Image(selectedImageName)
    }
}

Run Code Online (Sandbox Code Playgroud)

我还在 SceneDelegate 上为导航栏的颜色设置外观代理”

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.shadowColor = UIColor.systemYellow
        navBarAppearance.backgroundColor = UIColor.systemYellow
        navBarAppearance.shadowImage = UIImage()
        UINavigationBar.appearance().standardAppearance = navBarAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance

        // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView()

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,我想要做的是在详细视图出现时将导航栏的背景颜色更改为清除。我仍然想要那个视图中的后退按钮,所以隐藏导航栏并不是一个理想的解决方案。我还希望更改仅适用于 Detail 视图,因此当我弹出该视图时,外观代理应该接管,如果我推送到另一个控制器,则外观代理也应该接管。

我一直在尝试各种各样的事情: - 更改外观代理didAppear - 将细节视图包装在一个UIViewControllerRepresentable(有限的成功,我可以进入导航栏并更改其颜色但由于某种原因有不止一个导航控制器)

在 SwiftUI 中是否有一种直接的方法可以做到这一点?

use*_*832 8

我更喜欢为此使用 ViewModifer。下面是我的自定义 ViewModifier

struct NavigationBarModifier: ViewModifier {

var backgroundColor: UIColor?

init(backgroundColor: UIColor?) {
    self.backgroundColor = backgroundColor

    let coloredAppearance = UINavigationBarAppearance()
    coloredAppearance.configureWithTransparentBackground()
    coloredAppearance.backgroundColor = backgroundColor
    coloredAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]

    UINavigationBar.appearance().standardAppearance = coloredAppearance
    UINavigationBar.appearance().compactAppearance = coloredAppearance
    UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
    UINavigationBar.appearance().tintColor = .white
}

func body(content: Content) -> some View {
    ZStack{
        content
        VStack {
            GeometryReader { geometry in
                Color(self.backgroundColor ?? .clear)
                    .frame(height: geometry.safeAreaInsets.top)
                    .edgesIgnoringSafeArea(.top)
                Spacer()
            }
        }
    }
}}
Run Code Online (Sandbox Code Playgroud)

您还可以使用不同的文本颜色和色调来初始化它,我现在已经添加了静态颜色。

您可以从任何调用此修饰符。在你的情况下

    NavigationLink(
destination: DetailView(selectedImageName: imageName)
    .modifier(NavigationBarModifier(backgroundColor: .green))
Run Code Online (Sandbox Code Playgroud)

)

下面是截图。 带绿色导航栏的详细视图