在 SwiftUI 中动态更改和更新导航栏的颜色
Dynamically change and update color of Navigation Bar in SwiftUI
我正在尝试更改 SwiftUI 中的 NavigationBar
背景颜色,这是我使用以下代码完成的。但是,我还没有弄清楚如何动态更改和更新导航栏的背景颜色。
struct ContentView: View {
@State var color: Color = .red
init() {
let navbarAppearance = UINavigationBarAppearance()
navbarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.backgroundColor = UIColor(color)
UINavigationBar.appearance().standardAppearance = navbarAppearance
UINavigationBar.appearance().compactAppearance = navbarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navbarAppearance
}
var body: some View {
NavigationView {
VStack(spacing: 20) {
Button(action: { color = .blue }) {
Text("Blue")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.blue)
.cornerRadius(15)
}
Button(action: { color = .red }) {
Text("Red")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.red)
.cornerRadius(15)
}
}
.offset(y: -50)
.navigationTitle("My Navigation")
}
}
}
这段代码给出了正确的结果,但是点击其中一个按钮来更改 Color
变量不会更新 NavigationBar
的颜色。这是因为在初始化时,导航栏保留了它的所有特性,所以我需要找到一种方法来改变这些,如果可能的话,在改变颜色之间制作这种过渡动画。感谢您的帮助!
是的,外观应用于在 外观本身之后创建的所有视图。所以我们需要重置外观,然后在颜色变化时再次创建 NavigationView
。
这是一个可能的方法演示(使用 Xcode 13 / iOS 15 测试)
struct ContentView: View {
@State var color: Color = .red
var body: some View {
MainNavView(barColor: $color)
.id(color) // << re-creates !!
}
}
struct MainNavView: View {
@Binding var color: Color
init(barColor: Binding<Color>) {
self._color = barColor
let navbarAppearance = UINavigationBarAppearance()
navbarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.backgroundColor = UIColor(color)
UINavigationBar.appearance().standardAppearance = navbarAppearance
UINavigationBar.appearance().compactAppearance = navbarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navbarAppearance
}
var body: some View {
NavigationView {
VStack(spacing: 20) {
Button(action: { color = .blue }) {
Text("Blue")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.blue)
.cornerRadius(15)
}
Button(action: { color = .red }) {
Text("Red")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.red)
.cornerRadius(15)
}
}
.offset(y: -50)
.navigationTitle("My Navigation")
}
}
}
您可以使用SwiftUI-Introspect,所以您只是更改此NavigationView
的导航栏。它不会影响任何其他实例。
您也不会使用 .id(...)
,这可能很糟糕,因为当视图更改标识时,它可能会破坏动画、不必要地重新初始化视图、破坏视图生命周期等。
在我的示例中,您保存 UINavigationController
的当前实例。当color
的值改变时,重新设置导航栏的外观。
内省示例:
import Introspect
/* ... */
struct ContentView: View {
@State private var color: Color = .red
@State private var nav: UINavigationController?
var body: some View {
NavigationView {
VStack(spacing: 20) {
Button(action: { color = .blue }) {
Text("Blue")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.blue)
.cornerRadius(15)
}
Button(action: { color = .red }) {
Text("Red")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.red)
.cornerRadius(15)
}
}
.offset(y: -50)
.navigationTitle("My Navigation")
}
.introspectNavigationController { nav in
self.nav = nav
updateNavBar()
}
.onChange(of: color) { _ in
updateNavBar()
}
}
private func updateNavBar() {
guard let nav = nav else { return }
let navbarAppearance = UINavigationBarAppearance()
navbarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.backgroundColor = UIColor(color)
nav.navigationBar.standardAppearance = navbarAppearance
nav.navigationBar.compactAppearance = navbarAppearance
nav.navigationBar.scrollEdgeAppearance = navbarAppearance
}
}
结果:
我正在尝试更改 SwiftUI 中的 NavigationBar
背景颜色,这是我使用以下代码完成的。但是,我还没有弄清楚如何动态更改和更新导航栏的背景颜色。
struct ContentView: View {
@State var color: Color = .red
init() {
let navbarAppearance = UINavigationBarAppearance()
navbarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.backgroundColor = UIColor(color)
UINavigationBar.appearance().standardAppearance = navbarAppearance
UINavigationBar.appearance().compactAppearance = navbarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navbarAppearance
}
var body: some View {
NavigationView {
VStack(spacing: 20) {
Button(action: { color = .blue }) {
Text("Blue")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.blue)
.cornerRadius(15)
}
Button(action: { color = .red }) {
Text("Red")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.red)
.cornerRadius(15)
}
}
.offset(y: -50)
.navigationTitle("My Navigation")
}
}
}
Color
变量不会更新 NavigationBar
的颜色。这是因为在初始化时,导航栏保留了它的所有特性,所以我需要找到一种方法来改变这些,如果可能的话,在改变颜色之间制作这种过渡动画。感谢您的帮助!
是的,外观应用于在 外观本身之后创建的所有视图。所以我们需要重置外观,然后在颜色变化时再次创建 NavigationView
。
这是一个可能的方法演示(使用 Xcode 13 / iOS 15 测试)
struct ContentView: View {
@State var color: Color = .red
var body: some View {
MainNavView(barColor: $color)
.id(color) // << re-creates !!
}
}
struct MainNavView: View {
@Binding var color: Color
init(barColor: Binding<Color>) {
self._color = barColor
let navbarAppearance = UINavigationBarAppearance()
navbarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.backgroundColor = UIColor(color)
UINavigationBar.appearance().standardAppearance = navbarAppearance
UINavigationBar.appearance().compactAppearance = navbarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navbarAppearance
}
var body: some View {
NavigationView {
VStack(spacing: 20) {
Button(action: { color = .blue }) {
Text("Blue")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.blue)
.cornerRadius(15)
}
Button(action: { color = .red }) {
Text("Red")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.red)
.cornerRadius(15)
}
}
.offset(y: -50)
.navigationTitle("My Navigation")
}
}
}
您可以使用SwiftUI-Introspect,所以您只是更改此NavigationView
的导航栏。它不会影响任何其他实例。
您也不会使用 .id(...)
,这可能很糟糕,因为当视图更改标识时,它可能会破坏动画、不必要地重新初始化视图、破坏视图生命周期等。
在我的示例中,您保存 UINavigationController
的当前实例。当color
的值改变时,重新设置导航栏的外观。
内省示例:
import Introspect
/* ... */
struct ContentView: View {
@State private var color: Color = .red
@State private var nav: UINavigationController?
var body: some View {
NavigationView {
VStack(spacing: 20) {
Button(action: { color = .blue }) {
Text("Blue")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.blue)
.cornerRadius(15)
}
Button(action: { color = .red }) {
Text("Red")
.font(.title)
.bold()
.foregroundColor(.white)
.frame(width: 100)
.padding()
.background(Color.red)
.cornerRadius(15)
}
}
.offset(y: -50)
.navigationTitle("My Navigation")
}
.introspectNavigationController { nav in
self.nav = nav
updateNavBar()
}
.onChange(of: color) { _ in
updateNavBar()
}
}
private func updateNavBar() {
guard let nav = nav else { return }
let navbarAppearance = UINavigationBarAppearance()
navbarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navbarAppearance.backgroundColor = UIColor(color)
nav.navigationBar.standardAppearance = navbarAppearance
nav.navigationBar.compactAppearance = navbarAppearance
nav.navigationBar.scrollEdgeAppearance = navbarAppearance
}
}
结果: