美文网首页SwiftUI
SwiftUI 实现侧滑菜单 Side Menu

SwiftUI 实现侧滑菜单 Side Menu

作者: 韦爵爷2018 | 来源:发表于2021-09-08 09:50 被阅读0次

    SwiftUI 实现侧滑菜单 Side Menu

    效果

    iShot2021-09-08 09.43.45.gif

    代码

    代码里都有相关注释

    源码 github 链接:https://gist.github.com/RandyWei/05261947fcf7493d9edd4b58bdb43cbe

    
    //
    //  ContentView.swift
    //  SiderMenuDemo01
    //
    //  Created by RandyWei on 2021/9/7.
    //
    
    import SwiftUI
    
    struct ContentView: View {
       
       //划动偏移量
       @GestureState var offset:CGFloat = 0
       
       //滑动应该停留在某个点
       //停留点: 屏幕宽度的3/5
       let maxOffset:CGFloat = UIScreen.main.bounds.width * 3 / 5
       
       //滑动展开之后的 offset
       @State var expandOffset:CGFloat = 0
       
       //回弹点:最大停留点/2
       private var springOffset:CGFloat{
           maxOffset / 2
       }
       //缩放比例,默认是1
       @State private var scaleRatio:CGFloat = 1
       
       //最小 可缩放值
       let minScale:CGFloat = 0.9
       
       
       private var dragGesture: some Gesture {
           DragGesture()
               .updating($offset, body: { value, out, _ in
                   //判断是否反向滑动,如果是展开状态需要反向滑动
                   if value.translation.width >= 0 || expandOffset != 0 {
                       out = value.translation.width
                   }
               })
               .onChanged { value in
                   //为了顺畅给缩放增加过渡
                   if value.translation.width >= 0 {
                       //对缩放比例进行计算:缩放值 = 划动比例 * 可缩放值(1-minScale)
                       //因为是往小了缩,所以是1-缩放值
                       scaleRatio = 1 - (value.translation.width / maxOffset) * (1 - minScale)
                   } else {
                       //反向value.translation.width是负数 ,所以+maxOffset变为正值
                       scaleRatio = 1 - ((maxOffset + value.translation.width) / maxOffset) * (1 - minScale)
                   }
               }
               .onEnded { value in
                   //需要判断滑动是否超过某个点来决定是重置还是停留
                   if value.translation.width >= springOffset {
                       expandOffset = maxOffset
                       //停止后,缩小 到0.9
                       scaleRatio = minScale
                   } else {
                       expandOffset = 0
                       scaleRatio = 1
                   }
               }
       }
       
       var body: some View {
           
           ZStack{
               
               //侧边菜单层
               SideMenuView()
               
               //功能区域
               FeatureView()
                   .offset(x: offset + expandOffset)
                   .scaleEffect(scaleRatio)
                   .animation(.easeInOut(duration: 0.05))
                   .gesture(dragGesture)
                   
               
           }
           
       }
    }
    
    struct FeatureView:View {
       
       var body: some View{
           
           GeometryReader{proxy in
               VStack{
                   HStack{
                       Image(systemName: "list.dash")
                           .resizable()
                           .frame(width: 20, height: 20, alignment: .center)
                       
                       Text("功能区域")
                           .font(.title)
                       
                       Spacer()
                   }
                   
                   ScrollView(.vertical, showsIndicators: false, content: {
                       
                       VStack{
                           
                           ForEach(0..<50){_ in
                               
                               HStack{
                                   
                                   Image(systemName: "person")
                                       .resizable()
                                       .frame(width: 80, height: 80, alignment: .center)
                                   
                                   VStack(alignment: .leading){
                                       Text("titletitletitletitletitle")
                                           .font(.title)
                                       
                                       Spacer()
                                       
                                       Text("bodybodybodybodybodybody")
                                           .font(.body)
                                   }
                                   
                               }
                               
                           }.redacted(reason: .placeholder)
                       }
                       
                   })
               }
               .padding(.horizontal)
               .padding(.top, 8 + proxy.safeAreaInsets.top)
               .frame(maxWidth:.infinity,maxHeight: .infinity,alignment: .topLeading)
               .background(Color.white)
               .cornerRadius(30)
               .shadow(radius: 10)
               .ignoresSafeArea()
           }
           
       }
    }
    
    struct SideMenuView:View {
       var body: some View{
           
           GeometryReader{proxy in
               VStack(alignment:.leading){
                   //祖传头像
                   Image("avatar")
                       .resizable()
                       .aspectRatio(contentMode: .fill)
                       .frame(width: 100, height: 100, alignment: .center)
                       .clipShape(Circle())
                   
                   Text("韦爵爷")
                       .font(.title)
                   
                   Text("这个人很懒,什么都没留下")
                   
                   //菜单
                   
                   HStack{
                       Image(systemName: "archivebox")
                       Text("菜单一")
                   }
                   .padding(.top)
                   
                   HStack{
                       Image(systemName: "note.text")
                       Text("菜单二")
                   }
                   .padding(.top)
                   
                   
                   HStack{
                       Image(systemName: "gearshape")
                       Text("个人设置")
                   }
                   .padding(.top)
                   
                   Spacer()
                   
                   HStack{
                       Image(systemName: "signature")
                       Text("退出登录")
                   }
                   .padding(.top)
                   
               }
               .foregroundColor(.white)
               .padding(.horizontal)
               .padding(.top, 8 + proxy.safeAreaInsets.top)
               .padding(.bottom, 8 + proxy.safeAreaInsets.bottom)
               .frame(maxWidth:.infinity,maxHeight: .infinity,alignment: .topLeading)
               .background(Color.orange)
               .ignoresSafeArea()
           }
           
       }
    }
    
    struct ContentView_Previews: PreviewProvider {
       static var previews: some View {
           ContentView()
       }
    }
    

    相关视频

    Swift UI侧滑菜单Side Menu-哔哩哔哩

    相关文章

      网友评论

        本文标题:SwiftUI 实现侧滑菜单 Side Menu

        本文链接:https://www.haomeiwen.com/subject/mytvwltx.html