Je tente de créer une vue Paramètres pour ma barre d'état Macos Swiftui. Ma mise en œuvre jusqu'à présent utilise un NavigationView
et NavigationLink
, mais cette solution produit une demi-vue à mesure que la vue Paramètres appuie la vue parent sur le côté. Screenshot et exemple de code ci-dessous.
Barre latérale de la navigation
struct ContentView: View {
var body: some View {
VStack{
NavigationView{
NavigationLink(destination: SecondView()){
Text("Go to next view")
}}
}.frame(width: 800, height: 600, alignment: .center)}
}
struct SecondView: View {
var body: some View {
VStack{
Text("This is the second view")
}.frame(width: 800, height: 600, alignment: .center)
}
}
Les petites informations que je peux trouver suggèrent que cela est inévitable à l'aide de SWIFTUI sur MacOS, car l'écran complet 'NavigationView
sur iOS (StackNavigationViewStyle
) n'est pas disponible sur MacOS.
Existe-t-il un moyen simple ou même complexe d'implémenter une transition vers une vue de contexte qui prend tout le cadre à Swiftui pour MacOS? Et sinon, est-il possible d'utiliser AppKit
pour appeler un objet de vision écrit à Swiftui?
Aussi a Swift Newbie - s'il vous plaît soyez doux.
J'ai élargi Asperi Great Suggestion et créé un générique, réutilisable StackNavigationView
pour MacOS (ou même iOS, si vous le souhaitez). Quelques points forts:
SWIFT V5.2:
struct StackNavigationView<RootContent, SubviewContent>: View where RootContent: View, SubviewContent: View {
@Binding var currentSubviewIndex: Int
@Binding var showingSubview: Bool
let subviewByIndex: (Int) -> SubviewContent
let rootView: () -> RootContent
var body: some View {
VStack {
VStack{
if !showingSubview { // Root view
rootView()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.transition(AnyTransition.move(Edge: .leading)).animation(.default)
}
if showingSubview { // Correct subview for current index
StackNavigationSubview(isVisible: self.$showingSubview) {
self.subviewByIndex(self.currentSubviewIndex)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.transition(AnyTransition.move(Edge: .trailing)).animation(.default)
}
}
}
}
init(currentSubviewIndex: Binding<Int>, showingSubview: Binding<Bool>, @ViewBuilder subviewByIndex: @escaping (Int) -> SubviewContent, @ViewBuilder rootView: @escaping () -> RootContent) {
self._currentSubviewIndex = currentSubviewIndex
self._showingSubview = showingSubview
self.subviewByIndex = subviewByIndex
self.rootView = rootView
}
private struct StackNavigationSubview<Content>: View where Content: View {
@Binding var isVisible: Bool
let contentView: () -> Content
var body: some View {
VStack {
HStack { // Back button
Button(action: {
self.isVisible = false
}) {
Text("< Back")
}.buttonStyle(BorderlessButtonStyle())
Spacer()
}
.padding(.horizontal).padding(.vertical, 4)
contentView() // Main view content
}
}
}
}
Plus d'infos sur @ViewBuilder
et les génériques utilisés peuvent être trouvés ici .
Voici un exemple de base de celui-ci en cours d'utilisation. La vue parent suit la sélection actuelle et l'état d'affichage (à l'aide de @State
), permettant à quoi que ce soit dans ses sous-espèces de déclencher des changements d'état.
struct ExampleView: View {
@State private var currentSubviewIndex = 0
@State private var showingSubview = false
var body: some View {
StackNavigationView(
currentSubviewIndex: self.$currentSubviewIndex,
showingSubview: self.$showingSubview,
subviewByIndex: { index in
self.subView(forIndex: index)
}
) {
VStack {
Button(action: { self.showSubview(withIndex: 0) }) {
Text("Show View 1")
}
Button(action: { self.showSubview(withIndex: 1) }) {
Text("Show View 2")
}
Button(action: { self.showSubview(withIndex: 2) }) {
Text("Show View 3")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.blue)
}
}
private func subView(forIndex index: Int) -> AnyView {
switch index {
case 0: return AnyView(Text("I'm View One").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.green))
case 1: return AnyView(Text("I'm View Two").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.yellow))
case 2: return AnyView(VStack {
Text("And I'm...")
Text("View Three")
}.frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.orange))
default: return AnyView(Text("Inavlid Selection").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red))
}
}
private func showSubview(withIndex index: Int) {
currentSubviewIndex = index
showingSubview = true
}
}
Remarque: Les génériques comme celui-ci nécessitent que toutes les sous-étapes soient du même type. Si ce n'est pas le cas, vous pouvez les envelopper AnyView
, comme je l'ai fait ici. Le wrapper AnyView
n'est pas nécessaire si vous utilisez un type cohérent pour toutes les sous-espions (le type de la vue racine n'a pas besoin de correspondre).
Vous pouvez obtenir une navigation en plein écran avec
.navigationViewStyle(StackNavigationViewStyle())