SwiftUI implements Side Menu
The effect
code
There are comments in the code
Source making links: gist.github.com/RandyWei/05…
//
// ContentView.swift
// SiderMenuDemo01
//
// Created by RandyWei on 2021/9/7.
//
import SwiftUI
struct ContentView: View {
// Scratch offset
@GestureState var offset:CGFloat = 0
// The slide should stay at a certain point
// Stop point: 3/5 of the screen width
let maxOffset:CGFloat = UIScreen.main.bounds.width * 3 / 5
// Offset after sliding expansion
@State var expandOffset:CGFloat = 0
// Rebound point: maximum stop point /2
private var springOffset:CGFloat{
maxOffset / 2
}
// Scale, default is 1
@State private var scaleRatio:CGFloat = 1
// Minimum scalable value
let minScale:CGFloat = 0.9
private var dragGesture: some Gesture {
DragGesture()
.updating($offset, body: { value, out, _ in
// Determine whether to reverse slide. If it is expanded, reverse slide is required
if value.translation.width > = 0 || expandOffset ! = 0 {
out = value.translation.width
}
})
.onChanged { value in
// Add transition to zoom for smoothness
if value.translation.width > = 0 {
// Calculate the scaling ratio: scaling value = scaling ratio * scaling value (1-minscale)
// Since it is scaled down, it is 1- scaled
scaleRatio = 1 - (value.translation.width / maxOffset) * (1 - minScale)
} else {
// Reverse value.translation.width is negative, so +maxOffset becomes positive
scaleRatio = 1 - ((maxOffset + value.translation.width) / maxOffset) * (1 - minScale)
}
}
.onEnded { value in
// It is necessary to determine whether the slide exceeds a certain point to determine whether to reset or stay
if value.translation.width > = springOffset {
expandOffset = maxOffset
// When stopped, shrink to 0.9
scaleRatio = minScale
} else {
expandOffset = 0
scaleRatio = 1}}}var body: some View {
ZStack{
// Side menu layer
SideMenuView(a)// Function area
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("Functional area")
.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(a)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){
// Family portrait
Image("avatar")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100, alignment: .center)
.clipShape(Circle())
Text("Sir William.")
.font(.title)
Text("This man is lazy and has nothing left.")
/ / the menu
HStack{
Image(systemName: "archivebox")
Text("Menu one")
}
.padding(.top)
HStack{
Image(systemName: "note.text")
Text("Menu two")
}
.padding(.top)
HStack{
Image(systemName: "gearshape")
Text("Personal Settings")
}
.padding(.top)
Spacer(a)HStack{
Image(systemName: "signature")
Text("Log out")
}
.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()}}Copy the code
Related video
Swift UI Side Menu- Bilibilii