iOS:如何使用侧边菜单切换视图,SwitTui

iOS:如何使用侧边菜单切换视图,SwitTui,ios,swift,xcode,swiftui,Ios,Swift,Xcode,Swiftui,首先,我对iOS开发和Swift非常陌生(从PHP开始,我在这里待了两周:) 我正在尝试构建一个带有侧菜单的iOS应用程序。我的意图是,当我点击菜单中的一个项目时,新的视图将出现在屏幕上,如“HomeViewController”,对于每个后续项目,如示例1、2等(注意,我将很快添加顶部导航栏以打开菜单,以代替菜单按钮) 我想知道我怎样才能完成这个功能 谢谢 ContentView.swift import SwiftUI struct MenuItem: Identifiable {

首先,我对iOS开发和Swift非常陌生(从PHP开始,我在这里待了两周:)

我正在尝试构建一个带有侧菜单的iOS应用程序。我的意图是,当我点击菜单中的一个项目时,新的视图将出现在屏幕上,如“HomeViewController”,对于每个后续项目,如示例1、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()
    }
}
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))
    }
}


您需要一些配料:

  • 存储当前活动视图状态的方法
  • 在菜单和主内容视图之间传递状态的方法
对于第一个,我创建了一个枚举,列出了不同类型的视图(
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) {
        
    }
}
结构菜单项:可识别{ var id=UUID() 让文本:字符串 let viewType:viewType } 枚举视图类型{ 案例之家,示例1,示例2,示例3 } 结构菜单内容:视图{ @绑定变量activeView:ViewType 让项目:[MenuItem]=[ 菜单项(文本:“主页”,视图类型:。主页), MenuItem(文本:“Example1”,视图类型:。Example1), MenuItem(文本:“Example2”,视图类型:。Example2), 菜单项(文本:“Example3”,视图类型:。Example3) ] var body:一些观点{ ZStack{ 颜色(UIColor(红色:33/255.0,绿色:33/255.0,蓝色:33/255.0,alpha:1)) VStack(对齐:。前导,间距:0){ ForEach(items){item in HStack{ 文本(item.Text) .bold() .font(.system(大小:20)) .multilitextalignment(.leading) .foregroundColor(颜色.白色) 垫片() } .ontapsigne{ activeView=item.viewType } .padding() 分隔器() } 垫片() } .padding(.top,40) } } } 结构侧菜单:视图{ 让宽度:CGFloat 让美诺彭:布尔 让我们切换菜单:()->Void @绑定变量activeView:ViewType var body:一些观点{ ZStack{ //暗淡的背景 GeometryReader{uu}in EmptyView() } .背景(颜色.灰色.不透明度(0.15)) .不透明度(self.menuOpen?1:0) .animation(animation.easeIn.delay(0.25)) .ontapsigne{ self.toggleMenu() } //菜单内容 HStack{ 菜单内容(activeView:$activeView) .框架(宽度:宽度) .偏移量(x:menuOpen?0:-宽度) .animation(.default) 垫片() } } } } 结构ContentView:View{ @国家私有变量menuOpen=false @状态私有变量activeView:ViewType=.home var body:一些观点{ 让drag=DragGesture() .ONENED{ 如果$0.5,则宽度<-100{ 如果Menoopen{ 动画片{ 打印(“左”) menuOpen.toggle() } } } 如果$0.translation.width>-100{ 如果!美诺朋{ 动画片{ 打印(“右”) menuOpen.toggle() } } } } ZStack{ VStack{ 如果!美诺朋{ 按钮(操作:{ self.menuOpen.toggle() },标签:{ 文本(“打开菜单”) .bold() .foregroundColor(颜色.白色) .框架(宽:200,高:50,对齐:。中心) .背景(颜色(.systemBlue)) }) } 切换activeView{ 案例.家庭: HomeViewControllerRepresented() 案例1: 文本(“示例1”) 案例2: 文本(“示例2”) 案例3: 文本(“示例3”) } } 侧菜单(宽度:UIScreen.main.bounds.width/1.6, menuOpen:menuOpen, 切换菜单:切换菜单, activeView:$activeView) .edgesIgnoringSafeArea(.all) } .手势(拖动) } 功能切换菜单(){ menuOpen.toggle() } } 结构HomeViewControllerRepresented:UIViewControllerRepresentable{ func makeUIViewController(上下文:context)->HomeViewController{ HomeViewController() } func updateUIViewController(uUIViewController:HomeViewController,上下文:上下文){ } }
嘿,谢谢你的快速回复。我试图实现您的解释,但我得到错误“引用静态方法”buildory(first:)“on”\u ConditionalContent”要求“HomeViewController”符合“视图”我在ThanksAh上面附加了一个屏幕截图——我没有注意到它是一个
UIViewController
。做
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) {
        
    }
}