SwiftUI侧边栏菜单:实现WebView与自定义视图跳转切换
解决SwiftUI侧边栏同时支持WebView和自定义视图跳转的问题
核心思路
通过枚举统一管理网页视图、自定义视图两种跳转类型,利用NavigationLink根据选中的目标动态加载对应视图,替代原有的单一网页跳转逻辑。
修改后的完整代码
import SwiftUI import WebKit // 定义所有可能的跳转目标类型 enum Destination { case web(URL) case about } struct ContentView: View { @State private var isSideMenuOpen = true @State private var selectedDestination: Destination? // 替换原有的webViewURL var body: some View { NavigationView { GeometryReader { geometry in ZStack { // 主内容区域(默认空白,可替换为你的初始视图) Color.white // 侧边栏遮罩层 if isSideMenuOpen { Color.black.opacity(0.5).edgesIgnoringSafeArea(.all) .onTapGesture { withAnimation { isSideMenuOpen.toggle() } } } // 侧边栏菜单 VStack { if isSideMenuOpen || geometry.size.width > 800 { SideMenuView(isOpen: $isSideMenuOpen, didSelectDestination: { destination in selectedDestination = destination // 非宽屏模式下选中后关闭侧边栏 if geometry.size.width <= 800 { withAnimation { isSideMenuOpen = false } } }) .transition(.move(edge: .leading)) } Spacer() } } .navigationBarTitle(Text("App")) } .background( // 根据选中的目标加载对应视图 NavigationLink( destination: destinationView, isActive: Binding<Bool>( get: { selectedDestination != nil }, set: { _ in selectedDestination = nil } ), label: EmptyView.init ) ) } } // 根据目标类型返回对应的视图 private var destinationView: some View { switch selectedDestination { case .web(let url): return AnyView(WebView(url: url)) case .about: return AnyView(AboutView()) case nil: return AnyView(EmptyView()) } } } struct SideMenuView: View { @Binding var isOpen: Bool var didSelectDestination: (Destination) -> Void // 更新闭包参数类型 var body: some View { VStack(alignment: .leading, spacing: 10) { Button(action: { if let url = URL(string: "https://www.example.com") { didSelectDestination(.web(url)) } }) { Text("page 1") } Button(action: { if let url = URL(string: "https://www.example.com/page2") { didSelectDestination(.web(url)) } }) { Text("page 2") } Button(action: { didSelectDestination(.about) // 触发自定义视图跳转 }) { Text("About") } // 可添加更多菜单项 } .padding() .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) .background(Color.white) .transition(.move(edge: .leading)) } } struct WebView: UIViewRepresentable { let url: URL func makeUIView(context: Context) -> WKWebView { return WKWebView() } func updateUIView(_ uiView: WKWebView, context: Context) { let request = URLRequest(url: url) uiView.load(request) } } // 自定义About视图(需确保你已定义该视图) struct AboutView: View { var body: some View { Text("About This App") .navigationBarTitle("About") } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
关键修改点
- 新增
Destination枚举:统一管理网页和自定义视图两种跳转类型,避免单独维护多个状态变量。 - 替换状态变量:用
selectedDestination替代原有的webViewURL,支持多种目标类型。 - 更新侧边栏闭包:
SideMenuView的回调改为传递Destination类型,让主视图统一处理跳转逻辑。 - 动态生成目标视图:通过
destinationView计算属性,根据选中的目标返回对应的视图(使用AnyView实现类型擦除)。 - 优化侧边栏交互:非宽屏模式下选中菜单项后自动关闭侧边栏,提升用户体验。
内容的提问来源于stack exchange,提问作者RGS
相关产品推荐
相关产品推荐

