SideView (SlideView)

Little_Machine_Human_·2025년 1월 8일

SwiftUI에서 옆에서 등장하면서 화면을 반만가리고,
뒷배경은 조금 어둡게 하는 기능을 구현해야했다.

위 뷰를 뭐라고하는지 따로 정의가 되어있지 않아서,
그냥 나는 사이드 뷰 또는 슬라이드 뷰라고 부르겠다.

위와 같은 느낌이다.

기본적으로 ZStack을 기반으로한다.

  1. 메뉴콘텐츠 만들기
struct MenuContent: View {
    var body: some View {
        List {
            Text("My Profile").onTapGesture {
                print("My Profile")
            }
            Text("Posts").onTapGesture {
                print("Posts")
            }
            Text("Logout").onTapGesture {
                print("Logout")
            }
        }
    }
}
  1. 사이드 메뉴 만들기
struct SideMenu: View {
    let width: CGFloat
    let isOpen: Bool
    let menuClose: () -> Void
    
    var body: some View {
        // Code here
    }
}
  1. 배경 뷰 만들기
struct SideMenu: View {
    let width: CGFloat
    let isOpen: Bool
    let menuClose: () -> Void
    
    var body: some View {
        ZStack {
       	    // Code here
        }
    }
}
  1. 애니메이션 추가 뒷배경 추가
GeometryReader { _ in
    EmptyView()
}
.background(Color.gray.opacity(0.3))
.opacity(self.isOpen ? 1.0 : 0.0)
.animation(Animation.easeIn.delay(0.25))
.onTapGesture {
    self.menuClose()
}
  1. 메뉴 컨텐츠 추가하기
HStack {
    MenuContent()
        .frame(width: self.width)
        .background(Color.white)
        .offset(x: self.isOpen ? 0 : -self.width)
        .animation(.default)

    Spacer()
}
  1. ContentView에 메뉴 및 열기 버튼 추가
struct ContentView: View {
    @State var menuOpen: Bool = false
    
    var body: some View {
        // Code here
    }
    
    func openMenu() {
        self.menuOpen.toggle()
    }
}
ZStack {
    if !self.menuOpen {
        Button(action: {
            self.openMenu()
        }, label: {
            Text("Open")
        })
    }

    SideMenu(width: 270,
             isOpen: self.menuOpen,
             menuClose: self.openMenu)
}

최종코드

import SwiftUI

struct MenuContent: View {
    var body: some View {
        List {
            Text("My Profile").onTapGesture {
                print("My Profile")
            }
            Text("Posts").onTapGesture {
                print("Posts")
            }
            Text("Logout").onTapGesture {
                print("Logout")
            }
        }
    }
}

struct SideMenu: View {
    let width: CGFloat
    let isOpen: Bool
    let menuClose: () -> Void
    
    var body: some View {
        ZStack {
            GeometryReader { _ in
                EmptyView()
            }
            .background(Color.gray.opacity(0.3))
            .opacity(self.isOpen ? 1.0 : 0.0)
            .animation(Animation.easeIn.delay(0.25))
            .onTapGesture {
                self.menuClose()
            }
            
            HStack {
                MenuContent()
                    .frame(width: self.width)
                    .background(Color.white)
                    .offset(x: self.isOpen ? 0 : -self.width)
                    .animation(.default)
                
                Spacer()
            }
        }
    }
}

struct ContentView: View {
    @State var menuOpen: Bool = false
    
    var body: some View {
        ZStack {
            if !self.menuOpen {
                Button(action: {
                    self.openMenu()
                }, label: {
                    Text("Open")
                })
            }
            
            SideMenu(width: 270,
                     isOpen: self.menuOpen,
                     menuClose: self.openMenu)
        }
    }
    
    func openMenu() {
        self.menuOpen.toggle()
    }
}

간단한 예제로 구현해보았다.

profile
while(true){ 가족(); 건강(); 자기개발(); }

0개의 댓글