I've created a custom navigation bar modifier CustomNavigationBarModifier in SwiftUI, which implements the ViewModifier protocol to standardize the navigation bar style throughout the app. However, I've found that the init method of CustomNavigationBarModifier is being called unexpectedly multiple times, causing some unnecessary repetitive operations.
import SwiftUI
enum Decoration: String {
case Human
case Arc
}
enum DestinationType {
case view(() -> AnyView)
case action(() -> Void)
}
struct CustomNavigationBarModifier: ViewModifier {
@Environment(\.dismiss) private var dismiss
var destination: DestinationType?
var onButtonClick: (() -> Void)?
init(
destination: DestinationType? = nil,
onButtonClick: (() -> Void)? = nil
) {
self.destination = destination
self.onButtonClick = onButtonClick
print("Decoration / 28")
}
func body(content: Content) -> some View {
content
.background(Color.clear.ignoresSafeArea(.all))
.navigationBarBackButtonHidden(true)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: { dismiss() }) {
Image("Back_Arrow")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
.foregroundStyle(Color("252A3F_FCFCFC"))
}
}
}
.onAppear{
print("Decoration / 58")
}
}
}
extension View {
func applyCustomNavigationBar(
destination: DestinationType? = nil,
onButtonClick: (() -> Void)? = nil
) -> some View {
self.modifier(CustomNavigationBarModifier(destination: destination, onButtonClick: onButtonClick))
}
}
print:
Decoration / 28
Decoration / 58
Decoration / 28
Decoration / 28
My questions:
- Why is the init method of CustomNavigationBarModifier being called multiple times? Considering the way ViewModifier works, is this related to how SwiftUI handles view modifications?
- How can I avoid the init method being called multiple times to optimize performance? Is there a way to control the initialization timing of ViewModifier?
import SwiftUI
struct SkillsDashboard: View {
@State private var cardSize: CGSize = .zero
@State private var showSheet: Bool = false
let skills = ["Swift", "Objective-C", "Kotlin", "Java", "Python", "JavaScript", "Ruby", "C++"]
let columns = [
GridItem(.flexible(), spacing: 8),
GridItem(.flexible(), spacing: 8)
]
var body: some View {
ZStack {
ScrollView {
Prediction(
Button(action: {
showSheet.toggle()
},
label: {
Text("添加技能")
.multilineTextStyle(config: (.center, 20, .heavy, "252A3F_0F2534", 1))
})
)
.padding(.horizontal, 10)
LazyVGrid(columns: columns, spacing: 8) {
ForEach(skills, id: \.self) { _ in
skillCard()
}
}
}
}
.padding(.all, 8)
.background(Color("EFEFF4_0F2534"))
.sheet(isPresented: $showSheet) {
VStack(spacing: 0) {
HStack{}
.frame(height: 16)
.padding(0)
LazyVGrids()
HStack(alignment: .center, spacing: 0) {
Image("AngularBorder")
.resizable()
.aspectRatio(contentMode: .fill)
.foregroundColor(Color("FF5252_FCFCFC"))
.frame(width: 34, height: 92)
Spacer()
Image("AngularBorder")
.resizable()
.aspectRatio(contentMode: .fill)
.foregroundColor(Color("FF5252_FCFCFC"))
.frame(width: 34, height: 92)
.scaleEffect(x: -1, y: 1)
}
.overlay {
Button {
} label: {
RoundedRectangle(cornerRadius: 100)
.strokeBorder(Color("FF5252_FCFCFC"), lineWidth: 3, antialiased: true)
.frame(height: 60)
.background(Color("FFE30A_DBD5C9"))
}
.padding(.horizontal, 8)
}
.padding(.horizontal, 8)
.padding(.top, -3)
FormSheet()
.frame(maxWidth: .infinity, alignment: .top)
Spacer()
}
.frame(maxHeight: .infinity, alignment: .top)
.padding(0)
.presentationCornerRadius(25)
.background(Color("FFE30A_DBD5C9"))
}
.applyCustomNavigationBar()
}
}