在 SwiftUI 中,有没有办法像大多数 iOS 应用程序一样通过点击选项卡栏来弹出到根视图?
这是预期行为的示例。
我尝试使用simultaneousGesture
以下方式以编程方式弹出视图:
import SwiftUI
struct TabbedView: View {
@State var selection = 0
@Environment(\.presentationMode) var presentationMode
var body: some View {
TabView(selection: $selection) {
RootView()
.tabItem {
Image(systemName: "house")
.simultaneousGesture(TapGesture().onEnded{
self.presentationMode.wrappedValue.dismiss()
print("View popped")
})
}.tag(0)
Text("")
.tabItem {
Image(systemName: "line.horizontal.3")
}.tag(1)
}
}
}
struct RootView: View {
var body: some View{
NavigationView{
NavigationLink(destination:SecondView()){
Text("Go to second view")
}
}
}
}
struct SecondView: View {
var body: some View{
Text("Tapping the house icon should pop back to root view")
}
}
Run Code Online (Sandbox Code Playgroud)
但似乎这些手势被忽略了。
任何建议或解决方案将不胜感激
小智 9
我们可以使用标签栏选择绑定来获取选定的索引。在此绑定上,我们可以检查选项卡是否已被选中,然后弹出到根目录以便在选择时进行导航。
struct ContentView: View {
@State var showingDetail = false
@State var selectedIndex:Int = 0
var selectionBinding: Binding<Int> { Binding(
get: {
self.selectedIndex
},
set: {
if $0 == self.selectedIndex && $0 == 0 && showingDetail {
print("Pop to root view for first tab!!")
showingDetail = false
}
self.selectedIndex = $0
}
)}
var body: some View {
TabView(selection:selectionBinding) {
NavigationView {
VStack {
Text("First View")
NavigationLink(destination: DetailView(), isActive: $showingDetail) {
Text("Go to detail")
}
}
}
.tabItem { Text("First") }.tag(0)
Text("Second View")
.tabItem { Text("Second") }.tag(1)
}
}
}
struct DetailView: View {
var body: some View {
Text("Detail")
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我用这个搞乱了一段时间,效果很好。我结合了各地的答案,并添加了一些我自己的东西。我是 Swift 的初学者,所以请随时进行改进。
这是一个演示。
该视图有NavigationView。
import SwiftUI
struct AuthenticatedView: View {
@StateObject var tabState = TabState()
var body: some View {
TabView(selection: $tabState.selectedTab) {
NavigationView {
NavigationLink(destination: TestView(titleNum: 0), isActive: $tabState.showTabRoots[0]) {
Text("GOTO TestView #1")
.padding()
.foregroundColor(Color.white)
.frame(height:50)
.background(Color.purple)
.cornerRadius(8)
}
.navigationTitle("")
.navigationBarTitleDisplayMode(.inline)
}
.navigationViewStyle(.stack)
.onAppear(perform: {
tabState.lastSelectedTab = TabState.Tab.first
}).tabItem {
Label("First", systemImage: "list.dash")
}.tag(TabState.Tab.first)
NavigationView {
NavigationLink(destination: TestView(titleNum: 0), isActive: $tabState.showTabRoots[1]) {
Text("GOTO TestView #2")
.padding()
.foregroundColor(Color.white)
.frame(height:50)
.background(Color.purple)
.cornerRadius(8)
}.navigationTitle("")
.navigationBarTitleDisplayMode(.inline).navigationBarTitle(Text(""), displayMode: .inline)
}
.navigationViewStyle(.stack)
.onAppear(perform: {
tabState.lastSelectedTab = TabState.Tab.second
}).tabItem {
Label("Second", systemImage: "square.and.pencil")
}.tag(TabState.Tab.second)
}
.onReceive(tabState.$selectedTab) { selection in
if selection == tabState.lastSelectedTab {
tabState.showTabRoots[selection.rawValue] = false
}
}
}
}
struct AuthenticatedView_Previews: PreviewProvider {
static var previews: some View {
AuthenticatedView()
}
}
class TabState: ObservableObject {
enum Tab: Int, CaseIterable {
case first = 0
case second = 1
}
@Published var selectedTab: Tab = .first
@Published var lastSelectedTab: Tab = .first
@Published var showTabRoots = Tab.allCases.map { _ in
false
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的孩子视角
import SwiftUI
struct TestView: View {
let titleNum: Int
let title: String
init(titleNum: Int) {
self.titleNum = titleNum
self.title = "TestView #\(titleNum)"
}
var body: some View {
VStack {
Text(title)
NavigationLink(destination: TestView(titleNum: titleNum + 1)) {
Text("Goto View #\(titleNum + 1)")
.padding()
.foregroundColor(Color.white)
.frame(height:50)
.background(Color.purple)
.cornerRadius(8)
}
NavigationLink(destination: TestView(titleNum: titleNum + 100)) {
Text("Goto View #\(titleNum + 100)")
.padding()
.foregroundColor(Color.white)
.frame(height:50)
.background(Color.purple)
.cornerRadius(8)
}
.navigationTitle(title)
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView(titleNum: 0)
}
}
Run Code Online (Sandbox Code Playgroud)
在我自己的应用程序中,我使用更改最顶层视图上的 .id 修饰符的方法,这会导致 NavigationView 弹出到根目录。为了清楚起见,我还将这种导航弹出行为分解到它自己的包装视图“TabbedNavView”中,如下所示。
import SwiftUI
class TabMonitor: ObservableObject {
@Published var selectedTab = 1
}
struct ContentView: View {
@StateObject private var tabMonitor = TabMonitor()
var body: some View {
TabView(selection: $tabMonitor.selectedTab) {
TabbedNavView(tag: 1) {
DetailView(index: 1)
}
.tabItem { Label("Tab1", systemImage: "book") }
.tag(1)
TabbedNavView(tag: 2) {
DetailView(index: 10)
}
.tabItem { Label("Tab2", systemImage: "wrench") }
.tag(2)
} //TabView
.environmentObject(tabMonitor)
} //body
} //ContentView
struct DetailView: View {
var index: Int
var body: some View {
NavigationLink(
destination: DetailView(index: index + 1)
) {
Text("Detail \(index)")
}
} //body
} //DetailView
struct TabbedNavView: View {
@EnvironmentObject var tabMonitor: TabMonitor
private var tag: Int
private var content: AnyView
init(
tag: Int,
@ViewBuilder _ content: () -> any View
) {
self.tag = tag
self.content = AnyView(content())
} //init(tag:content:)
@State private var id = 1
@State private var selected = false
var body: some View {
NavigationView {
content
.id(id)
.onReceive(tabMonitor.$selectedTab) { selection in
if selection != tag {
selected = false
} else {
if selected {
id *= -1 //id change causes pop to root
}
selected = true
}
} //.onReceive
} //NavigationView
.navigationViewStyle(.stack)
} //body
} //TabbedNavView
Run Code Online (Sandbox Code Playgroud)
这种方法的好处是它可以处理任意数量的选项卡以及每个选项卡中任意数量的 NavigationLink。每个 TabbedNavView 都会跟踪自己是否是选定的选项卡,并且每当连续点击选项卡两次时,都会将 NavigationView 弹出到根(通过翻转根视图的 .id 修饰符的符号)。
编辑:适用于 iOS 15+。
归档时间: |
|
查看次数: |
889 次 |
最近记录: |