SwiftUI로 사이드 메뉴 구현
드래그 또는 탭으로 표시하거나 숨길 수 있습니다.
환경
이미지
핑크 메뉴
파랑 홈
검은 테두리가 보이는 곳
드래그에 맞게 메뉴와 홈 오프셋을 모두 이동합니다.
코드 전문
import SwiftUI
struct HomeView: View {
@State var showMenu: Bool = false
let menuWidth = UIScreen.main.bounds.width * 0.7
/// homeのx座標(青いやつ)
@State var xPosition: CGFloat = 0
@State var isDrag: Bool = false
var drag: some Gesture {
DragGesture()
.onChanged{ value in
isDrag = true
// value.location.x - value.startLocation.x がドラッグしている距離
// 移動させすぎないようにmaxとminで最大値と最小値の設定
if showMenu {
xPosition = max(min(menuWidth + value.location.x - value.startLocation.x, menuWidth), 0)
} else {
xPosition = max(min(value.location.x - value.startLocation.x, menuWidth), 0)
}
}
.onEnded{ value in
// Dragが終了したタイミングで開くか、閉じるかを判定したい
if value.location.x - value.startLocation.x >= menuWidth / 3 {
showMenu = true
} else if -(value.location.x - value.startLocation.x) >= menuWidth / 3 {
showMenu = false
}
isDrag = false
}
}
var body: some View {
GeometryReader { geometry in
VStack {
HStack(spacing: 60) {
AvatarView(showMenu: $showMenu)
Spacer()
}
.padding(EdgeInsets.init(top: 8, leading: 8, bottom: 8, trailing: 8))
Spacer()
}
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(x: isDrag ? xPosition : (showMenu ? menuWidth : 0))
.animation(.easeInOut(duration: 0.2))
.background(Color.blue)
.onTapGesture {
if showMenu {
showMenu.toggle()
}
}
.gesture(drag)
SlideMenuView(showMenu: $showMenu)
.frame(width: menuWidth, height: geometry.size.height)
.offset(x: isDrag ? -menuWidth + xPosition : (showMenu ? 0 : -menuWidth))
.animation(.easeInOut(duration: 0.2))
.gesture(drag)
}
}
}
struct AvatarView: View {
@Binding var showMenu: Bool
var body: some View {
Button(action: {
self.showMenu.toggle()
}) {
Color.yellow
.frame(width: 44, height: 44)
.clipShape(Circle())
}
}
}
struct SlideMenuView: View {
@Binding var showMenu: Bool
var body: some View {
VStack(spacing: 16) {
Spacer()
MenuRow(showMenu: $showMenu, title: "Account", icon: "gear")
MenuRow(showMenu: $showMenu, title: "Billing", icon: "creditcard")
MenuRow(showMenu: $showMenu, title: "Sign out", icon: "person.crop.circle")
Spacer()
}
.background(Color.white)
}
}
struct MenuRow: View {
@Binding var showMenu: Bool
var title: String
var icon: String
var body: some View {
Button(action: {
self.showMenu.toggle()
}) {
HStack(spacing: 16) {
Image(systemName: icon)
.font(.system(size: 20, weight: .light))
.imageScale(.large)
.frame(width: 32, height: 32)
Text(title)
.font(.system(size: 20, weight: .bold, design: .default))
.frame(width: 120, alignment: .leading)
Spacer()
}
.padding(.horizontal, 30)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
감상
좀 더 깨끗한 구현이 있었을지도. . .
그렇다고해도 SwiftUI는 쓰기 쉽네요.
Reference
이 문제에 관하여(SwiftUI로 사이드 메뉴 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/mass_ssa/items/8f0f75b688819d6838f1
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import SwiftUI
struct HomeView: View {
@State var showMenu: Bool = false
let menuWidth = UIScreen.main.bounds.width * 0.7
/// homeのx座標(青いやつ)
@State var xPosition: CGFloat = 0
@State var isDrag: Bool = false
var drag: some Gesture {
DragGesture()
.onChanged{ value in
isDrag = true
// value.location.x - value.startLocation.x がドラッグしている距離
// 移動させすぎないようにmaxとminで最大値と最小値の設定
if showMenu {
xPosition = max(min(menuWidth + value.location.x - value.startLocation.x, menuWidth), 0)
} else {
xPosition = max(min(value.location.x - value.startLocation.x, menuWidth), 0)
}
}
.onEnded{ value in
// Dragが終了したタイミングで開くか、閉じるかを判定したい
if value.location.x - value.startLocation.x >= menuWidth / 3 {
showMenu = true
} else if -(value.location.x - value.startLocation.x) >= menuWidth / 3 {
showMenu = false
}
isDrag = false
}
}
var body: some View {
GeometryReader { geometry in
VStack {
HStack(spacing: 60) {
AvatarView(showMenu: $showMenu)
Spacer()
}
.padding(EdgeInsets.init(top: 8, leading: 8, bottom: 8, trailing: 8))
Spacer()
}
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(x: isDrag ? xPosition : (showMenu ? menuWidth : 0))
.animation(.easeInOut(duration: 0.2))
.background(Color.blue)
.onTapGesture {
if showMenu {
showMenu.toggle()
}
}
.gesture(drag)
SlideMenuView(showMenu: $showMenu)
.frame(width: menuWidth, height: geometry.size.height)
.offset(x: isDrag ? -menuWidth + xPosition : (showMenu ? 0 : -menuWidth))
.animation(.easeInOut(duration: 0.2))
.gesture(drag)
}
}
}
struct AvatarView: View {
@Binding var showMenu: Bool
var body: some View {
Button(action: {
self.showMenu.toggle()
}) {
Color.yellow
.frame(width: 44, height: 44)
.clipShape(Circle())
}
}
}
struct SlideMenuView: View {
@Binding var showMenu: Bool
var body: some View {
VStack(spacing: 16) {
Spacer()
MenuRow(showMenu: $showMenu, title: "Account", icon: "gear")
MenuRow(showMenu: $showMenu, title: "Billing", icon: "creditcard")
MenuRow(showMenu: $showMenu, title: "Sign out", icon: "person.crop.circle")
Spacer()
}
.background(Color.white)
}
}
struct MenuRow: View {
@Binding var showMenu: Bool
var title: String
var icon: String
var body: some View {
Button(action: {
self.showMenu.toggle()
}) {
HStack(spacing: 16) {
Image(systemName: icon)
.font(.system(size: 20, weight: .light))
.imageScale(.large)
.frame(width: 32, height: 32)
Text(title)
.font(.system(size: 20, weight: .bold, design: .default))
.frame(width: 120, alignment: .leading)
Spacer()
}
.padding(.horizontal, 30)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
감상
좀 더 깨끗한 구현이 있었을지도. . .
그렇다고해도 SwiftUI는 쓰기 쉽네요.
Reference
이 문제에 관하여(SwiftUI로 사이드 메뉴 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/mass_ssa/items/8f0f75b688819d6838f1
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(SwiftUI로 사이드 메뉴 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/mass_ssa/items/8f0f75b688819d6838f1텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)