Je veux ajouter un bouton de navigation personnalisé qui ressemblera un peu à ceci:
Maintenant, j'ai écrit une vue BackButton
personnalisée pour cela. Lors de l'application de cette vue en tant qu'élément de barre de navigation principale, procédez comme suit:
.navigationBarItems(leading: BackButton())
... la vue de navigation ressemble à ceci:
J'ai joué avec des modificateurs comme:
.navigationBarItem(title: Text(""), titleDisplayMode: .automatic, hidesBackButton: true)
sans aucune chance.
Comment puis-je...
.navigationBarHidden(true)
Utilisez ceci pour faire la transition vers votre vue:
NavigationLink(destination: SampleDetails()) {}
Ajoutez ceci à la vue elle-même:
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
Ensuite, dans une action de bouton ou quelque chose, fermez la vue:
presentationMode.wrappedValue.dismiss()
Depuis un parent, naviguez à l'aide de NavigationLink
NavigationLink(destination: SampleDetails()) {}
Dans DetailsView hide navigationBarBackButton
et définissez le bouton de retour personnalisé au début navigationBatItem
,
struct SampleDetails: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var btnBack : some View { Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Image("ic_back") // set image here
.aspectRatio(contentMode: .fit)
.foregroundColor(.white)
Text("Go back")
}
}
}
var body: some View {
List {
Text("sample code")
}
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: btnBack)
}
}
Il semble que vous pouvez maintenant combiner les navigationBarBackButtonHidden
et .navigationBarItems
pour obtenir l'effet que vous essayez d'obtenir.
struct Navigation_CustomBackButton_Detail: View {
@Environment(\.presentationMode) var presentationMode
var body: some View {
ZStack {
Color("Theme3BackgroundColor")
VStack(spacing: 25) {
Image(systemName: "globe").font(.largeTitle)
Text("NavigationView").font(.largeTitle)
Text("Custom Back Button").foregroundColor(.gray)
HStack {
Image("NavBarBackButtonHidden")
Image(systemName: "plus")
Image("NavBarItems")
}
Text("Hide the system back button and then use the navigation bar items modifier to add your own.")
.frame(maxWidth: .infinity)
.padding()
.background(Color("Theme3ForegroundColor"))
.foregroundColor(Color("Theme3BackgroundColor"))
Spacer()
}
.font(.title)
.padding(.top, 50)
}
.navigationBarTitle(Text("Detail View"), displayMode: .inline)
.edgesIgnoringSafeArea(.bottom)
// Hide the system back button
.navigationBarBackButtonHidden(true)
// Add your custom back button here
.navigationBarItems(leading:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Image(systemName: "arrow.left.circle")
Text("Go Back")
}
})
}
}
Voici à quoi ça ressemble (extrait du livre "SwiftUI Views"):
Basé sur d'autres réponses ici, ceci est une réponse simplifiée pour l'option 2 fonctionnant pour moi dans XCode 11.0:
struct DetailView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "gobackward").padding()
}
.navigationBarHidden(true)
}
}
Remarque: Pour que la barre de navigation soit masquée, j'ai également dû définir, puis masquer la barre de navigation dans ContentView.
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView()) {
Text("Link").padding()
}
} // Main VStack
.navigationBarTitle("Home")
.navigationBarHidden(true)
} //NavigationView
}
}
Je suppose que vous souhaitez utiliser le bouton de retour personnalisé dans tous les écrans navigables, j'ai donc écrit un wrapper personnalisé basé sur la réponse @Ashish.
struct NavigationItemContainer<Content>: View where Content: View {
private let content: () -> Content
@Environment(\.presentationMode) var presentationMode
private var btnBack : some View { Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Image("back_icon") // set image here
.aspectRatio(contentMode: .fit)
.foregroundColor(.black)
Text("Go back")
}
}
}
var body: some View {
content()
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: btnBack)
}
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
}
Envelopper le contenu de l'écran dans NavigationItemContainer:
tilisation:
struct CreateAccountScreenView: View {
var body: some View {
NavigationItemContainer {
VStack(spacing: 21) {
AppLogoView()
//...
}
}
}
}
Toutes les solutions que je vois ici semblent désactiver la fonctionnalité de balayage pour revenir à la page précédente, donc j'ai partagé une solution qui maintient cette fonctionnalité. Vous pouvez créer une extension de votre vue racine et remplacer votre style de navigation et appeler la fonction dans l'initialiseur de vue.
Exemple de vue
struct SampleRootView: View {
init() {
overrideNavigationAppearance()
}
var body: some View {
Text("Hello, World!")
}
}
Extension
extension SampleRootView {
func overrideNavigationAppearance() {
let navigationBarAppearance = UINavigationBarAppearance()
let barAppearace = UINavigationBar.appearance()
barAppearace.tintColor = *desired UIColor for icon*
barAppearace.barTintColor = *desired UIColor for icon*
navigationBarAppearance.setBackIndicatorImage(*desired UIImage for custom icon*, transitionMaskImage: *desired UIImage for custom icon*)
UINavigationBar.appearance().standardAppearance = navigationBarAppearance
UINavigationBar.appearance().compactAppearance = navigationBarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance
}
}
Le seul inconvénient de cette approche est que je n'ai pas trouvé de moyen de supprimer/modifier le texte associé au bouton de retour personnalisé.
Le balayage n'est pas désactivé de cette façon.
Travaille pour moi. XCode 11.3.1
Mettez ceci dans votre ViewController racine
init() {
UINavigationBar.appearance().isUserInteractionEnabled = false
UINavigationBar.appearance().backgroundColor = .clear
UINavigationBar.appearance().barTintColor = .clear
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().tintColor = .clear
}
Et cela dans votre ViewController enfant
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
Button(action: {self.presentationMode.wrappedValue.dismiss()}) {
Image(systemName: "gobackward")
}
J'ai trouvé ceci: https://ryanashcraft.me/swiftui-programmatic-navigation/
Cela fonctionne, et cela peut jeter les bases d'une machine d'état pour contrôler ce qui est affiché, mais ce n'est pas aussi simple qu'avant.
import Combine
import SwiftUI
struct DetailView: View {
var onDismiss: () -> Void
var body: some View {
Button(
"Here are details. Tap to go back.",
action: self.onDismiss
)
}
}
struct RootView: View {
var link: NavigationDestinationLink<DetailView>
var publisher: AnyPublisher<Void, Never>
init() {
let publisher = PassthroughSubject<Void, Never>()
self.link = NavigationDestinationLink(
DetailView(onDismiss: { publisher.send() }),
isDetail: false
)
self.publisher = publisher.eraseToAnyPublisher()
}
var body: some View {
VStack {
Button("I am root. Tap for more details.", action: {
self.link.presented?.value = true
})
}
.onReceive(publisher, perform: { _ in
self.link.presented?.value = false
})
}
}
struct ContentView: View {
var body: some View {
NavigationView {
RootView()
}
}
}
If you want to hide the button then you can replace the DetailView with this:
struct LocalDetailView: View {
var onDismiss: () -> Void
var body: some View {
Button(
"Here are details. Tap to go back.",
action: self.onDismiss
)
.navigationBarItems(leading: Text(""))
}
}