SwiftUI View 4 (Alert, ConfirmationDialog, PresentationStyle)

Updated:

🔷Alert, ActionSheet

각각 알림창 및 액션 시트를 화면에 출력하는 컨테이너 객체 로써 UIkit 의 UIAlertController 를 그대로 활용하는데, 기존에는 UIAlertController 에서 parameter 로 UIAlertController.Style.action.Sheet 와 UIAlertController.Style.alert 이 각각 분리되서 사옫 됩니다.

👉 Alert

// Alert 출력 예시
struct AlertExample: View {
  @State private var showingAlert = false

  var body: some View {
    VStack(spacing: 20) {
      // Aler 버튼 1개
      Button(action: { self.showingAlert.toggle() }) {
        Text("버튼 1개 Alert").font(.title)
      }
      .alert("제목", isPresented: $showingAlert) {
        Button("확인", role: .none) {}
      } message: {
        Text("내용")
      }

      // Alert 버튼 2개
      Button(action: { self.showingAlert.toggle() }) {
        Text("버튼 2개 Alert").font(.title)
      }
      .alert("제목", isPresented: $showingAlert) {
        Button("삭제", role: .destructive) {}
        Button("취소", role: .cancel) {}
      } message: {
        Text("내용")
      }
    }
  }
}

스크린샷

👉 ConfirmationDialog

  • iOS 14 이전에는 .actionSheet(...) 으로 사용되었지만, iOS 15 부터는 .confirmationDialog() 라고 이름도 바뀌도 명렁어가 바뀌었습니다
// ios14 이전: .ActionSheet
// iOS15 부터 .confrmationDialog() 로 명칭이 바뀜
Button(action: { self.showingAlert.toggle()}) {
  Text("Show Action Sheet").font(.title)
}
.confirmationDialog(
  "Select",
  isPresented: $showingAlert,
  // title 은 기본적으로 .hidden 이라 .visible 로 해줘야 "Select" 라는 타이틀이 나타남
  titleVisibility: .visible,
  actions: {
    Button("1") {}
    Button("2") {}
    Button("Cancel", role: .cancel) {}
  }
)				// ios14 이전: .ActionSheet
// iOS15 부터 .confrmationDialog() 로 명칭이 바뀜
Button(action: { self.showingAlert.toggle()}) {
  Text("Show Action Sheet").font(.title)
}
.confirmationDialog(
  "Select",
  isPresented: $showingAlert,
  // title 은 기본적으로 .hidden 이라 .visible 로 해줘야 "Select" 라는 타이틀이 나타남
  titleVisibility: .visible,
  actions: {
    Button("1") {}
    Button("2") {}
    Button("Cancel", role: .cancel) {}
  }
)

스크린샷

🔷 PresentationStyle

UIKit 에서는 present(_:animated:completion:) 매서드를 사용해 새로운 뷰 컨트롤러로 전화하는 것과 더불어 프리젠테이션 스타일을 변경하여 화면에 표시되는 방식을 다르게 지정할 수 도 있습니다

// iOS 12 이하
modalPresentationStyle = .fullscreen // iOS 12 이하일 때 기본값

// iOS 13 이상
modalPresentationStyle = .automatic // iOS 13 이상일때 기본값
modalPresentationStyle = .pageSheet // automatic 일때 대부분 pageSheet 로 동작

SwiftUI 에서는 pageSheet 의 Sheet, popover 스타일 2가지의 스타일을 제공합니다

modalPresentationStyle = .pageSheet // Sheet
modalPresentationStyle = .popover // Popover

👉 Sheet

  • pageSheet 스타일로 새로운 뷰를 출력합니다.

  • Alert, ActionSheet 와 사용법이 비슷한데, isPresented / item 은 출력 조건을 전달하고 content 매개 변수에는 출력될 뷰를 정의며, onDismiss 매개 변수에는 화면이 닫히기 직전에 수행할 작업을 정의하면 됩니다

EnvironmentMode

// presentationMode를 이용한 dismiss 예시
struct PresentationMode: View {
  @State private var shoeingSheet = false

  var body: some View {
    Button(action: { self.shoeingSheet.toggle() }) {
      Text("Present").font(.title).foregroundColor(.blue)
    }
    .sheet(
      isPresented: $shoeingSheet,
      onDismiss: { print("Dismissed") }, // 화면이 닫히기 전 수행할 작업
      content: { Ch05_1_DataFlow.PresentedView() }) // 새로 출력될 화면
  }
}

struct PresentedView: View {
  // presentationMode 는 해당 뷰가 띄워져 있는 상태인지를 알려주는 isPresented 프로퍼티와
  // 화면을 닫는 dismiss 메서드 이렇게 2가지를 제공하는 환경 변수 입니다
  @Environment (\.presentationMode) var presentationMode

  var body: some View {
    Button(action: {
      // isPresented의 값을 가져와 현재 뷰의 출력 상태를 확인합니다
      if self.presentationMode.wrappedValue.isPresented {
        // Sheet 스타일을 사용하는 경우는 버튼을 눌러서 dismiss 메서드를 호출하는 방법뿐만 아니라,
        // 화면상단 부분을 잡아 아래 방향으로 끌어내리는 방법으로도 현재 화면을 닫을 수 있습니다
        // 화면이 닫히고 나면 sheet 수식어에 onDismiss 매개 변수에 정의했던 클로저가 불리게 됩니다
        self.presentationMode.wrappedValue.dismiss()
      }
    }) {
      Text("Tap to Dismiss").font(.title).foregroundColor(.red)
    }
  }
}

스크린샷

BindingMode

  • 위와 같이 presentationMode 환경 변수를 사용하지 않고 바인딩 프로퍼티를 사용하여 화면 닫기를 구현할 수 있습니다
// Binding 을 이용한 dismiss 예시
struct BindingMode: View {
  @State private var showingSheet = false

  var body: some View {
    Button(action: { self.showingSheet.toggle() }) {
      Text("BindingMode").font(.title).foregroundColor(.blue)
    }
    .sheet(isPresented: $showingSheet,
            onDismiss: { print("Dismissed") },
            content: {Ch05_1_DataFlow.PresentedViewWithBinding(isPresented: self.$showingSheet)

    })
  }
}

struct PresentedViewWithBinding: View {
  @Binding var isPresented: Bool

  var body: some View {
    Button(action: { self.isPresented.toggle() }) {
      Text("Tap to Dismiss").font(.title).foregroundColor(.red)
    }
  }
}

스크린샷

  • 바인딩 프로퍼티에 화면 출력 여부를 관장하는 프포퍼티와 연동하여, 버튼을 눌렀을 때 그 값을 비활성화시켜 주면 dismiss() 메서드를 호출한 것과 같은 효과가 나타압니다

👉 Popover

  • Popover 는 콘텐츠와 관련된 추가적인 정보를 제공하거나 설정을 변경할 수 있도록 현제 화면 위로 일시적인 뷰를 표시하는 방식으로 상대적으로 큰화면인 아이패드에 사용될때 만들어진 스타일 입니다.

  • Popover 는 HIG(Human Interface Guidelines) 에서도 아이패드에서 사용되길 권장되지만 아이폰에서 사용되면 자동으로 PageSheet 스타일로 적용됩니다

// Popover 구현 예시
struct popverExample: View {
  @State var showingPopover = false

  var body: some View {
    VStack {
      Button(action: { self.showingPopover.toggle() }) {
        Text("Popover Button").font(.largeTitle)
      }
    }
    .popover(isPresented: $showingPopover,
              // Popover 의 앵커로 사용할 영역 또는 위치를 결정 합니다
              attachmentAnchor: .point(.bottomTrailing),
              // popover 의 화살표가 어느 방향을 향할지 결정 합니다 기본값은 .top
              arrowEdge: .top,
              content: popoverContents)
  }

  // popover 에 표시될 콘텐츠
  private func popoverContents() -> some View {
    VStack(alignment: .leading) {
      HStack {
        Button(action: { self.showingPopover = false }) { // 팝오버 제거
          Text("Cancel").foregroundColor(.red)
        }
        Spacer()
        Text("New Event").font(.headline)
        Spacer()
        Button("Add(+)") {}
      }
      Divider().padding(.bottom, 8) // 구분선 추가

      Text("Title")
      TextField("제목", text: .constant(""))
      Text("Contents")
      TextField("내용", text: .constant(""))
      Spacer()
    }
    .padding()
  }
}

스크린샷

스크린샷


🔶 🔷 📌 🔑 👉

🗃 Reference

Apple developer official docs - https://developer.apple.com/documentation/swiftui/view/alert(_:ispresented:presenting:actions:message:)-8584l

SwiftUI로 액션시트 띄우기 (iOS 15, macOS Monterey) - https://seorenn.tistory.com/207

스윗한 SwiftUI - https://book.jacobko.info/#/book/1190014815

Categories:

Updated:

Leave a comment