본문 바로가기
iOS/SwiftUI

#12 Conditional Views

by HaningYa 2020. 10. 23.
728x90

이전 챕터에서는 대표적인 navigation을 연습해봤다.
이번장에서는 특정 조건에서만 보여지는 view (conditional view) 에 대해서 배워본다.
conditional view 는 특히 사용자의 현재 상황에서 다음 상황으로 넘어가기 전 중요한 메시지를 보여주거나 사용자로 응답을 받아야 하는 경우에서 유용하게 쓰인다.

navigation stack 외부에서 view 를 보여주는 것은 사용자는 해당 view의 작업에 집중할 수 있다.
또한 필수적인 정보를 보여주거나 필요한 정보를 요청하는 방법을 제공한다.

starter 프로젝트는 tab-navigation 으로 구성된 구조가 있다.
이 구조에서 SwiftUI 가 제공하는 여러 conditional view 를 사용해 볼 것 이다.

Displaying a modal sheet

modal sheet를 사용해 사용자에게 정보를 제공해볼 것 이다.
Modal sheet은 현재 view 에 대한 사용자의 집중이 필요할 때 유용하게 쓰인다.

지금 할 일은 fight detail 에 관한 view 를 navigation stack 이 아닌 modal sheet 로 바꿔볼 것 이다.

model sheet는 현재 화면 위로 올라온다.
sheet 은 view 계층에 있을 필요가 없으므로 rows는 NavigationLinks 로 wrap 될 필요가 없다.

FlightBoard.swift 에서 List 를 수정한다.

원래는 NavigationLink 로 wrapp 되있다.

SwiftUI는 @State 변수를 기반으로 모달을 표시하는 두 가지 방법을 제공한다.
첫 번째 방법은 시트가 표시되어야 할 때 true로 설정 한 Bool 변수를 사용하고
두 번째 방법은 변수가 nil이 아닐 때 표시되는 optional 을 사용한다.
이 모달에는 Bool 방법을 사용할 것 이다.

*optional 을 사용하는 modal 은 뒤에서 써본다.

FlightRow.Swift 에서 언제 modal sheet 를 보여줘야하는지 나타내는 @State 변수를 선언한다.

    @State private var isPresented = false

  • HStack 을 Button 으로 감싸서 row 자체에 대한 tap 이 가능하게 한다. Button action 은 isPresented state를 toggle 한다.\
  • SwiftUI 에게 sheet(isPresented:onDismiss:content:)를 통해 어떤 화면을 Modal로 띄우고 싶은지 정해준다.
    isPresented state 변수를 전달해 해당 변수가 true 가 될 때 modal 을 보여주라고 말하고 있다.
    사용자가 modal 을 닫으면 SwiftUI 는 isPresented 변수를 false 로 바꾼다.
  • optional onDismiss는 사용자가 modal 을 닫은 이후 실행되는 클로져를 포함한다. 여기서 state variable 이 false 로 바뀌는걸 확인하는 메시지를 출력한다.
  • sheet(isPresented:onDismiss:content:)의 클로저에 modal 로 띄우고 싶은 view 를 제공한다.

Programmatically dismissing a modal

modal 을 띄우면 navigation view 가 사라지는걸 볼 수 있다.
왜냐하면 modal sheet은 전체 스크린을 차지하고 또 navigation view 로 wrap 되지 않았기 때문이다.
새로운 navigation view 를 modal 에 만들 수 있지만 그렇게 되면 기존에 있는것 과는 다른 새로운 view stack을 만들게 된다.

카탈리스트 앱과 다른 플랫폼에서 swipe 제스쳐를 지원하지 않기 때문에 modal 을 닫는 버튼이 필요하다.
FlightBoardInformation.swift에서 화면이 표시되었는지에 대한 flag 를 FlightRow 에서 가져오기 위한 @Binding 변수가 필요하다.

  • showModal @Binding 변수 선언

  • modal sheet 를 끄는 버튼 생성

  • preview 에서 showModal .constant(true)

  • FlightBoardInformation을 띄우는 FlightRow 에서 Binding 값에 isPresented 연결


FlightRow 에서 isPresented state variable 은 modal 을 표시 상태를 나타낸다.
이 상태변수를 FlightBoardInformation의 showModal 파라미터로 바인딩 시켜주고
FlightBoardInformation 내부에서는 showModal binding 변수로 해당 값을 연결해놓는다.
modal 내부의 done 버튼을 누르게 되면 FlightBoardInformation의 showModal 이 false 가 되고 그럼 바인딩 되어있던 FlightRow의 상태변수인 isPresented 를 false 로 만들어 주어 FlightRow 에서 .sheet(isPresented 를 trigger 하여 dismiss 된다.


modal 은 사용자의 view 에 대한 집중도를 올리고 싶을 때 사용할 수 있는 방법이다.
제대로만 사용한다면 사용자에게 정보에 집중하게 해 UX를 높일 수 있다

하지만 modal 은 앱 경험을 방해하는 요소가 될 수 도 있기 때문에 적절하게 꼭 필요한 곳에서만 사용해라
SwiftUI 는 3가지 modal 타입을 제공한다.

  • alerts
  • action sheet
  • popovers

Creating an alert

Alert는
문제에 대한 경고나
여러 단계를 거친 요청에 대한 마지막 확인 용도로
사용자에게 중요한 정보를 전달할때 사용한다.

취소된 비행편에 대해서 새로운 비행편을 예약하는 버튼을 만들고 버튼을 눌렀을 때 항공사에 문의하라는 alert 를 띄워보자

FlightBoardInformation.swift 에서 modal 과 비슷하게 alert 로 state 변수를 통해 표시할 수 있다.

  • @state rebookAlert 표시
  • rebook 버튼 생성
  • rebook 버튼에  .alert 로 Alert() view 생성

  • view는 비행편의 상태가 .cancelled 일 때만 화면에 표시된다.
  • button 이 tap 되었을 때 rebookAlert를 true 로 만든다.
  • alert(isPresented:content:) 를 만들어 언제 alert 를 띄울지를 rebookAlert @Binding 변수를 통해 정해준다. rebookAlert가 true 가 될 때 나타나게 된다.
  • alert의 클로져 안에 Alert로 어떤 메시지를 전달할지 작성한다. 사용자는 dismiss를 위한 OK 버튼만 필요하기 때문에 추가적인 버튼은 만들지 않는다.

iOS 와 iPadOS 에 익숙하다면 SwiftUI 에 있는 Alert는 몇가지 한계점이 있다는 알게 될 것 이다.
방금 써본 alert는 iOS 에 있는 UIAlertController 처럼 text field를 추가할 수 없다.
SwiftUI 에서 text를 입력받고 싶으면 modal sheet 을 만들어야 한다.

여러 alert를 view 에 붙일 수 있다. 
각각의 alert는 다른 trigger를 가져야 되는데 그렇지 않으면 제일 마지막에 뜬 alert 만 보여지게 된다.

modal sheet 와 같이 alert 또한 optional 변수에 binding 해서 trigger 로 사용할 수 있다.
다음장에서 이 방법으로 action sheet 을 사용해본다.

Adding an action sheet

action sheet 은 사용자 작업에 대한 응답으로 나타나야하며 사용자는 이를 예상할 수 있어야 된다.
예를 들어 작업에 대해 확인하거나 여러 옵션 중에서 하나를 선택할 수 있도록 할 때 사용한다.

이번에는 사용자가 비행편을 예약하고 요청에 대한 확인을 받는 action sheet를 만들어 본다.

Bool state 변수 대신 optional 변수를 사용해본다. 
optional 변수를 사용하는 주된 이유는 바로 enclosure 내부에서 optional 변수에 접근 가능하기 때문이다.
변수는 무조건 Identifiable protocol 을 준수해야 한다.

다음 단계로 action sheet 에 대해 Identifiable 을 준수하게 만든다.

Identifiable 을 준수하기 위해 id 변수를 넣어줬다.

UUID는 Hashable unique value를 만든다. 그리고 message 를 담을 airline 과 flight 문자열을 추가한다.

FlightBoardInformation 에서 CheckInInfo 정보를 담을 @State변수를 선언한다.

  • 예약 가능한 비행편 일때만 버튼을 보여준다. (onTime 인 경우)
  • 버튼 action에서 checkInFlight라는 CheckInInfo 인스턴스를 생성한다. (그래야 nil 이 아니라 present 가 됨)
  • alert 와 마찬가지로 actionSheet을 버튼에 추가한다.
    actionSheet(isPresetned<Bool> :content:) 가 아닌 actionSheet(item<Identifiable>:content:)를 사용한다.
    optional 변수를 전달해서 변수가 nil 이 아닐 때 trigger 가 된다.
    SwiftUI 가 sheet를 보여줄 때 이 optional 변수인 파라미터는 값의 내용을 포함하고 있다.
  • 전달받은 변수를 통해 비행편의 이름을 action sheet 에 표시한다.
  • alert 는 제한적인 피드백 요청을 할 수 있다.
    만약 하나 이상의 조건을 주고 싶다면 (조건은 모두 버튼이여야 한다.)
    ActionSheet.Button 의 배열을 buttons 파라미터에 전달하면 된다.
  • .cancel 버튼은 취소 버튼으로 선택되었을 때 어떠한 action 도 필요없다.
  • .destructive type 메서드는 파괴적이거나 위험한 행동에 대한 메서드 이다. SwiftUI는 해당 버튼의 텍스트를 빨강으로 강조해서 위험한 동작이라는 걸 표시한다.
    action 에는 선택에 따른 로직을 구현한다. 
  • .default는 기본 버튼이다.

Showing a popover

action sheet 과 비슷하게 popover또한 사용자의 작업에 대한 반응으로 나타난다.
popover는 iPad 나 Mac 과 같이 큰 화면을 가진 디바이스에서 적합하다.
작은 스크린애서는 Modal sheet을 쓰는게 좋다. 만약 화면이 작으면 SwiftUI 는 popover 를 modal sheet 로 대체한다.

popover 언제든지 dismiss 될 수 있기 때문에 사용자에게 표시될 때 바로바로 상태가 저장되야 한다.
popover 도 마찬가지로 Boolean 이나 optional 타입의 변수를 통해 visibility 를 조절할 수 있다.
이번 예시에는 Bool state 변수를 사용한다.

FlightTimeHistory view 에 popover를 만들어 본다.

    @State private var showFlightHistory  = false

alert를 사용하는 것과 비슷하다.
Alerts, action sheet, popover는 모두 같은 동작을 한다. -> 사용자에게 정보를 보여주고 응답을 받는 동작
popover(isPresented:arrowEdge:) 는 showFlightHistory state 변수를 통해 popover를 보여줄지 말지 결정한다.

popover는 전통적으로 popover를 만든 control 에게 화살표를 보여준다. 
arrowEdge로 정해주는데 지금은 .top을 사용해서 view 가 control 의 아래에 위치하도록 정해웠다.

Key points

  • modal sheet 는 view 의 제일 위에서 보여지며 Bool state 변수나 optional state 변수를 사용할 수 있다.
    사용하는 변수들은 Identifiable 프로토콜을 준수해야 한다.
  • alert, action sheet, popover는 정보를 표시하고 사용자의 피드백을 받는 일반적인 방법이다.
  • Alerts 는 대부분 예장치 못한 상황에 대한 정보나 여러단계를 거친 행동에 대한 confirm을 받을 때 쓴다.
  • Action sheet과 popover 는 사용자 작업에 대한 응답으로 보여지며 
    작은 화면에 대해서는 action sheet, 큰 화면에 대해서는 popover를 사용하면 된다.

링크

modality HIG

iOS

developer.apple.com/design/human-interface-guidelines/ios/overview/themes/

 

Themes - iOS - Human Interface Guidelines - Apple Developer

iOS Design Themes As an app designer, you have the opportunity to deliver an extraordinary product that rises to the top of the App Store charts. To do so, you'll need to meet high expectations for quality and functionality. Three primary themes differenti

developer.apple.com

 

macOS

developer.apple.com/design/human-interface-guidelines/macos/overview/themes/

 

Themes - macOS - Human Interface Guidelines - Apple Developer

macOS Design Themes Four primary themes differentiate macOS apps from iOS, tvOS, and watchOS apps. Keep these themes in mind as you imagine your app’s identity. Flexible People expect macOS apps to be intuitive, while simultaneously adaptable to their wo

developer.apple.com

watchOS

developer.apple.com/design/human-interface-guidelines/watchos/overview/getting-started/

 

Getting Started - watchOS - Human Interface Guidelines - Apple Developer

Getting Started The watchOS app experience differs from app experiences on other platforms in two primary ways: Apple Watch is designed to be worn, so the UI is attuned to wearers and gives them an experience that’s lightweight, responsive, and highly pe

developer.apple.com

WWDC 2019 SwiftUI Essentials

https://developer.apple.com/videos/play/wwdc2019/216/

 

SwiftUI Essentials - WWDC 2019 - Videos - Apple Developer

Take your first deep-dive into building an app with SwiftUI. Learn about Views and how they work. From basic controls to sophisticated...

developer.apple.com

 

728x90

'iOS > SwiftUI' 카테고리의 다른 글

SwiftUI size rendering algorithm  (0) 2020.10.26
#13 Drawing & Custom Graphics  (0) 2020.10.23
#11 Lists & Navigation  (0) 2020.10.22
#10 Gestures  (0) 2020.10.22
#9 State & Data Flow  (0) 2020.10.22

댓글