[iOS] 알럿 커스텀 하기

Jehyeon Lee·2023년 12월 7일
0

SwiftUI에서 알럿창을 커스텀하여 토스의 디자인대로 알럿을 만들어볼겁니다.

struct EasterEggAlert: View {
    @EnvironmentObject var homeStore: HomeStore
    @Binding var isPresented: Bool
    let title: String
    let primaryButtonTitle: String
    let primaryAction: () -> Void
    var body: some View {
        VStack(spacing: 22) {
            
            Image("\(homeStore.mungImage[homeStore.mungImageCount])")
                .resizable()
                .scaledToFit()
                .frame(width: 150)
            
            Text(title)
                .font(.title)
                .bold()
                .foregroundColor(.black)
            
            Divider()
            Button {
                primaryAction()
                isPresented = false
            } label: {
                Text(primaryButtonTitle)
                    .font(.title3)
                    .bold()
                    .padding(.vertical, 8)
                    .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
        }
        .padding(.horizontal, 24)
        .padding(.vertical, 18)
        .frame(width: 300)
        .background(
            RoundedRectangle(cornerRadius: 30)
                .stroke(.blue.opacity(0.5))
                .background(
                    RoundedRectangle(cornerRadius: 30)
                        .fill(.white)
                )
        )
    }
}

코드 설명

  • EasterEggAlert 즉 커스텀하는 알럿의 구조체를 만들었습니다.
  • 속성들은 알럿에 필요한 내용들이고, primaryAction은 추후 버튼에 액션을 추가해서 사용하시면됩니다.
  • body부분에는 이 알럿의 기본적인 틀을 제작해줬습니다.

알럿창이 닫기 버튼 뿐만 아니라 바탕화면을 터치하여도 알럿창이 닫히도록 코드를 작성했으며, 또한 알럿창이 아래로 내려가게끔 구현했습니다.

struct EasterEggModifier: ViewModifier {
    
    @Binding var isPresented: Bool
    let title: String
    let primaryButtonTitle: String
    let primaryAction: () -> Void
    
    func body(content: Content) -> some View {
        ZStack {
            content
            
            ZStack {
                if isPresented {
                    Rectangle()
                        .fill(.black.opacity(0.5))
                        .blur(radius: isPresented ? 2 : 0)
                        .ignoresSafeArea()
                        .onTapGesture {
                            self.isPresented = false // 외부 영역 터치 시 내려감
                        }
                    
                    EasterEggAlert(
                        isPresented: self.$isPresented,
                        title: self.title,
                        primaryButtonTitle: self.primaryButtonTitle,
                        primaryAction: self.primaryAction
                    )
                    .transition(.move(edge: .bottom).combined(with: .opacity))
                }
            }
            .animation(
                isPresented
                ? .spring(response: 0.3)
                : .none,
                value: isPresented
            )
        }
    }
}

코드 설명

  • body는 ViewModifier를 구현하기 위한 메서드입니다.
  • 기본 콘텐츠를 먼저 표시
  • 알럿이 나타날 때만 실행되는 ZStack
  • 외부 영역을 덮는 반투명한 배경
  • 외부 영역 터치 시 알럿 닫기
  • EasterEggAlert 뷰를 표시하고 애니메이션 적용
  • 알럿이 아래로 이동하는 트랜지션 효과 적용
  • 알럿 나타남/사라짐에 따라 스프링 애니메이션 적용

그 후 View를 확장하여 easterEgg라는 뷰를 리턴값으로 하는 메서드를 제작하였습니다.
이제 이 메서드를 호출하면 밑의 결과화면에 나오는 알럿 창이 나옵니다.

extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
        clipShape( RoundedCorner(radius: radius, corners: corners) )
    }
    func easterEgg(
        isPresented: Binding<Bool>,
        title: String,
        primaryButtonTitle: String,
        primaryAction: @escaping () -> Void
    ) -> some View {
        return modifier(
            EasterEggModifier(
                isPresented: isPresented,
                title: title,
                primaryButtonTitle: primaryButtonTitle,
                primaryAction: primaryAction
            )
        )
    }
}

결과화면

profile
공부한거 느낌대로 써내려갑니당

0개의 댓글

관련 채용 정보