【问题标题】:iOS: How to switch views with a Side Menu, SwitftUIiOS:如何使用侧边菜单、SwiftUI 切换视图
【发布时间】:2021-06-10 22:41:40
【问题描述】:

首先,我对 iOS 开发和 Swift 非常陌生(从 PHP 到这里需要 2 周 :))

我正在尝试构建一个带有侧边菜单的 iOS 应用程序。我的意图是,当我单击菜单中的一个项目时,新视图将出现在屏幕上,如“HomeViewController”以及每个后续项目,如 example1、2 等(代替菜单按钮,注意我将添加顶部导航栏即将打开菜单) 我想知道如何才能完成此功能?

谢谢

ContentView.swift

import SwiftUI

struct MenuItem: Identifiable {
    var id = UUID()
    let text: String
}

func controllView(clickedview:String) {
print(clickedview)
}

struct MenuContent: View{
    
    let items: [MenuItem] = [
    MenuItem(text: "Home"),
    MenuItem(text: "Example1"),
    MenuItem(text: "Example2"),
    MenuItem(text: "Example3")
    ]
    
    
    var body: some View {
        ZStack {
            Color(UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1))
            
            VStack(alignment: .leading, spacing: 0) {
                
                ForEach(items) {items in
                    HStack {
                        Text(items.text)
                            .bold()
                            .font(.system(size: 20))
                            .multilineTextAlignment(/*@START_MENU_TOKEN@*/.leading/*@END_MENU_TOKEN@*/)
                            .foregroundColor(Color.white)
                        Spacer()
                    }
                    .onTapGesture {
                        controllView(clickedview: items.text)
                    }
                    .padding()
                    
                    Divider()
                }
                
                Spacer()
                
            }
            .padding(.top, 40)
        }
    }
}

struct SideMenu: View {
    let width: CGFloat
    let menuOpen: Bool
    let toggleMenu: () -> Void
    
    var body: some View {
        ZStack {
            //Dimmed backgroud
            GeometryReader { _ in
                EmptyView()
            }
            .background(Color.gray.opacity(0.15))
            .opacity(self.menuOpen ? 1 : 0)
            .animation(Animation.easeIn.delay(0.25))
            .onTapGesture {
                self.toggleMenu()
            }
            
            //Menucontent
            HStack {
                MenuContent()
                    .frame(width: width)
                    .offset(x: menuOpen ? 0 : -width)
                    .animation(.default)
                
                Spacer()
            }
            
        }
    }
}

struct ContentView: View {
    @State var menuOpen = false
    
    var body: some View {
        
        let drag = DragGesture()
                    .onEnded {
                        if $0.translation.width < -100 {
                            if menuOpen {
                            withAnimation {
                                print("Left")
                                menuOpen.toggle()
                            }
                        }
                    }
                        if $0.translation.width > -100 {
                            if !menuOpen {
                            withAnimation {
                                print("Right")
                                menuOpen.toggle()
                            }
                        }
                    }
                }

        ZStack {
            if !menuOpen {
            Button(action: {
                self.menuOpen.toggle()
            }, label: {
                Text("Open Menu")
                    .bold()
                    .foregroundColor(Color.white)
                    .frame(width: 200, height: 50, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                    .background(Color(.systemBlue))
            })
            }
            SideMenu(width: UIScreen.main.bounds.width/1.6, menuOpen: menuOpen, toggleMenu: toggleMenu)
        }
        .edgesIgnoringSafeArea(.all)
        .gesture(drag)
    }
    
    func toggleMenu(){
        menuOpen.toggle()
    }

}




struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

上述代码中的点击命令:

.onTapGesture {
   controllView(clickedview: items.text)
}

HomeViewController.swift

import UIKit
import WebKit
class HomeViewController: UIViewController, WKNavigationDelegate {

    var webView: WKWebView!
    
    override func loadView() {
        webView = WKWebView()
        webView.navigationDelegate = self
        view = webView
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let url = URL(string: "https://developer.apple.com")!
        webView.load(URLRequest(url: url))
    }
}

【问题讨论】:

    标签: ios swift xcode swiftui


    【解决方案1】:

    你需要一些材料:

    • 一种存储当前活动视图状态的方法
    • 一种在菜单和主要内容视图之间传达状态的方法

    对于第一个,我创建了一个枚举,列出了不同类型的视图 (ViewType),并将其添加到您的 MenuItem 模型中。

    对于第二个,您可以通过 @Binding 将状态从父视图传递到子视图并备份链。

    struct MenuItem: Identifiable {
        var id = UUID()
        let text: String
        let viewType : ViewType
    }
    
    enum ViewType {
        case home, example1, example2, example3
    }
    
    struct MenuContent: View{
        @Binding var activeView : ViewType
        
        let items: [MenuItem] = [
            MenuItem(text: "Home", viewType: .home),
            MenuItem(text: "Example1", viewType: .example1),
            MenuItem(text: "Example2", viewType: .example2),
            MenuItem(text: "Example3", viewType: .example3)
        ]
        
        
        var body: some View {
            ZStack {
                Color(UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1))
                
                VStack(alignment: .leading, spacing: 0) {
                    
                    ForEach(items) { item in
                        HStack {
                            Text(item.text)
                                .bold()
                                .font(.system(size: 20))
                                .multilineTextAlignment(.leading)
                                .foregroundColor(Color.white)
                            Spacer()
                        }
                        .onTapGesture {
                            activeView = item.viewType
                        }
                        .padding()
                        
                        Divider()
                    }
                    
                    Spacer()
                    
                }
                .padding(.top, 40)
            }
        }
    }
    
    struct SideMenu: View {
        let width: CGFloat
        let menuOpen: Bool
        let toggleMenu: () -> Void
        @Binding var activeView : ViewType
        
        var body: some View {
            ZStack {
                //Dimmed backgroud
                GeometryReader { _ in
                    EmptyView()
                }
                .background(Color.gray.opacity(0.15))
                .opacity(self.menuOpen ? 1 : 0)
                .animation(Animation.easeIn.delay(0.25))
                .onTapGesture {
                    self.toggleMenu()
                }
                
                //Menucontent
                HStack {
                    MenuContent(activeView: $activeView)
                        .frame(width: width)
                        .offset(x: menuOpen ? 0 : -width)
                        .animation(.default)
                    
                    Spacer()
                }
                
            }
        }
    }
    
    struct ContentView: View {
        @State private var menuOpen = false
        @State private var activeView : ViewType = .home
        
        var body: some View {
            
            let drag = DragGesture()
                .onEnded {
                    if $0.translation.width < -100 {
                        if menuOpen {
                            withAnimation {
                                print("Left")
                                menuOpen.toggle()
                            }
                        }
                    }
                    if $0.translation.width > -100 {
                        if !menuOpen {
                            withAnimation {
                                print("Right")
                                menuOpen.toggle()
                            }
                        }
                    }
                }
            
            ZStack {
                
                VStack {
                    if !menuOpen {
                        Button(action: {
                            self.menuOpen.toggle()
                        }, label: {
                            Text("Open Menu")
                                .bold()
                                .foregroundColor(Color.white)
                                .frame(width: 200, height: 50, alignment: .center)
                                .background(Color(.systemBlue))
                        })
                    }
                    switch activeView {
                    case .home:
                        HomeViewControllerRepresented()
                    case .example1:
                        Text("Example1")
                    case .example2:
                        Text("Example2")
                    case .example3:
                        Text("Example3")
                    }
                }
                
                SideMenu(width: UIScreen.main.bounds.width/1.6,
                         menuOpen: menuOpen,
                         toggleMenu: toggleMenu,
                         activeView: $activeView)
                 .edgesIgnoringSafeArea(.all)
            }
            .gesture(drag)
        }
        
        func toggleMenu(){
            menuOpen.toggle()
        }
    }
    
    struct HomeViewControllerRepresented : UIViewControllerRepresentable {
        func makeUIViewController(context: Context) -> HomeViewController {
            HomeViewController()
        }
        
        func updateUIViewController(_ uiViewController: HomeViewController, context: Context) {
            
        }
    }
    

    【讨论】:

    • 您好,感谢您的快速回复。我正在尝试执行您的解释,但我收到错误“引用静态方法 'buildEither(first:)' on '_ConditionalContent' 要求 'HomeViewController' 符合 'View' 我在上面附上了一个屏幕截图谢谢
    • 啊——我没注意到这是UIViewController。你知道UIViewControllerRepresentable吗?
    • 不幸的是,我没有 :(,我边走边学
    • 好的,我现在已经为它加了一个垫片。您可能想对它进行一些研究,了解更多关于如何使用它以及与 SwiftUI 的互操作性。
    • 太好了,工作非常感谢,非常感谢您的帮助和建议 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-21
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多