SWIFTUI/Others

SwiftUI : Preview 레이아웃을 미리 보는방법

서근 2021. 4. 5. 17:39
반응형

Preview 에 대해 알아보도록 합시다.

 

Preview 동작 과정

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
  1. 현재 소스 에디터에 PreviewProvider프로토콜을 준수하는 타입이 존재하는지 확인.
  2. PreviewProivder프로토콜의 필수 구현 사항인 previews 타입 프로퍼티에서 뷰 생성.
  3. 액티브 스킬의 목적지로 선택한 시뮬레이터 또는 맥에 연결한 기기의 형태로 preview container 렌더링. 
  4. 리뷰 컨테이너를 직접 지정해 줄 경우 3번 에서 선택한 기기를 무시하고 해당 기기 형태로 렌더링.

따라서 가장 먼저 현재 소스 에디터 상에 띄워진 파일에 PreviewProvider 프로토콜을 준수하는 타입이 있어야 합니다. 기존 Swift에서 사용하던 시뮬레이터에 비해 Preview는 아주 빠르고 편하게 보여 줍니다.

자동 Privew 갱신

Preview를 활용하다 보면 언제든 빌드를 다시 하지 않아도 수정 결과가 자동으로 반영됩니다. 하지만 어떤 경우에는 수동으로 갱신해 주어야 하는 경우가 있죠

이 메세지를 읽어보면 자동 갱신 기능은 Preview의 대상이 되는 파일이 수정되어 모듈을 다시 빌드해야 하는 상황에서 중단된다고 나와있습니다. 그럼 이렇게 모듈을 다시 빌드해야 하는 상황은 언제일까요?

  • 프로퍼티와 메서드를 추가 / 제거 / 수정하는 경우
  • 저장 프로퍼티의 값 변경
  • 뷰의 타입 이름을 변경하거나 또 다른 뷰를 추가할 때
  • 앱을 수동으로 빌드하는 경우

위에 상황을 모두 기억할 수 없으니 좀 더 일반화하면 이렇습니다.

 

파일의 탑 레벨이나 구조체 / 클래스의 구현 범위에서는 키워드, 속성, 프리프로세서 구문에 대한 수정 같은 일부 예외를 제외하면 어떠한 작은 변화라도 일어나는 순간자동 갱신이 중단됩니다. 해당 범위 내에서는 한 글자라도 입력 / 삭제 하거나 개행 또는 공백을 추가하면 다시 빌드를 해야 하는 상황이 생깁니다.

Privew 수식어 살펴보기

XcodeSwiftUI Pireview를 사용하면 .previewDevice()수정자를 사용하여 동시에 여러 화면 크기로 디자인을 보여줄 수 있습니다. 

 

아이폰은 실제로 기기를 모두 보유하고 있지 않아도 다양한 환경에서 점검할 수 있도록 시뮬레이터를 제공하듯이, Preview에서도 마찬가지로 각 기기별로 preview container로 지정하여 확인할 수 있는 기능을 제공합니다. 

 

지원되는 장치 목록

<hide/>
    ///     "Mac"
    ///     "iPhone 7"
    ///     "iPhone 7 Plus"
    ///     "iPhone 8"
    ///     "iPhone 8 Plus"
    ///     "iPhone SE"
    ///     "iPhone X"
    ///     "iPhone Xs"
    ///     "iPhone Xs Max"
    ///     "iPhone Xʀ"
    ///     "iPad mini 4"
    ///     "iPad Air 2"
    ///     "iPad Pro (9.7-inch)"
    ///     "iPad Pro (12.9-inch)"
    ///     "iPad (5th generation)"
    ///     "iPad Pro (12.9-inch) (2nd generation)"
    ///     "iPad Pro (10.5-inch)"
    ///     "iPad (6th generation)"
    ///     "iPad Pro (11-inch)"
    ///     "iPad Pro (12.9-inch) (3rd generation)"
    ///     "iPad mini (5th generation)"
    ///     "iPad Air (3rd generation)"
    ///     "Apple TV"
    ///     "Apple TV 4K"
    ///     "Apple TV 4K (at 1080p)"
    ///     "Apple Watch Series 2 - 38mm"
    ///     "Apple Watch Series 2 - 42mm"
    ///     "Apple Watch Series 3 - 38mm"
    ///     "Apple Watch Series 3 - 42mm"
    ///     "Apple Watch Series 4 - 40mm"
    ///     "Apple Watch Series 4 - 44mm"

TIP
 
 

Xcode의 대상 메뉴에 표시되는 장치의 정확한 이름 (ex : "iPhone 12") 과 함께 제공되어야 합니다.

모델명 외에 모델 넘버를 이용해서 지정하는 것도 가능하며, 목록에 없는 최신모델도 문제없이 사용이 가능합니다.

ContentView()
    .previewDevice(PreviewDevice(rawValue: "iPhone 12 Pro Max"))

Preview 하기 위해 특정 장치를 사용할 때 .previewDisplayName() 수정자를 추가하는 것이 유용합니다. 그러면 미리 보기 창에서 장치 위에 어떤 기기로 미리보기 되고 있는지 볼 수 있습니다.

ContentView()
  .previewDevice(PreviewDevice(rawValue: "iPhone XS"))
  .previewDisplayName("iPhone XS")

기기를 지정하여 여러 디바이스 표시

Group을 사용하여 여러 기기를 Preview할 수 도 있습니다. 

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
                .previewDevice(PreviewDevice(rawValue: "iPhone XS"))
                .previewDisplayName("iPhone XS")
            
            ContentView()
                .previewDevice(PreviewDevice(rawValue: "iPhone 8"))
                .previewDisplayName("iPhone 8")
        }
    }
}

또, 뷰는 동일한 구성으로 하되 다양한 preview container를 사용해 동시에 출력하고 싶다면 ForEach를 이용하는것이 편리합니다.

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ForEach(["iPhone 12 Pro", "iPhone 8"], id: \.self) {
            ContentView()
                .previewDevice(PreviewDevice(rawValue: $0))
        }
    }
}

preview container마다 이름을 지정해줄 수 도 있습니다.

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ForEach(["iPhone 12 Pro", "iPhone 8"], id: \.self) {
            ContentView()
                .previewDevice(PreviewDevice(rawValue: $0))
                .previewDisplayName($0) //각 프리뷰 컨테이너 이름지정
        }
    }
}

레이아웃 변경하기

이번에는 아래 그림처럼 작은 크기의 뷰를 Preview로 확인해야 한다고 예를 들어보겠습니다.

이때는 실제 나타내어야 할 뷰보다 preview container의 크기가 많이 크기 때문에 뷰의 크기에 맞게 또는 특정 크기로 지정하여 보고 싶은 경우도 있죠? 그럼 previewLayout수식어를 이용해 preview container의 크기를 변경할 수 있습니다. 이 수식어는 previewLayout열거형 타입의 값을 전달받으며 이 타입은 현재 3가지 선택지를 제공하고 있습니다.

구분 설명
device 기본값. 컨테이너가 기기 본래의 크기와 형태로 나타납니다.
sizeThatFits 컨테이너를 프리뷰의 크기에 맞춰서 유동적으로 조절합니다.
fixed(width: height:) 지정한 너비와 높이에 맞춰서 컨테이너의 크기를 고정합니다.

기본값은 패스하고 sizeThatFitsfixed값을 지정해서 어떻게 변화하는지 살펴보겠습니다.

SizeThatFits

ContentView()
 .previewLayout(.sizeThatFits)
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ForEach(["iPhone 12 Pro", "iPhone 8"], id: \.self) {
            ContentView()
                .previewLayout(.sizeThatFits)
                
                .previewDevice(PreviewDevice(rawValue: $0))
                .previewDisplayName($0) //각 프리뷰 컨테이너 이름지정
        }
    }
}

sizeThatFits는 뷰가 가진 크기와 컨테이너 크기가 일치하는 것을 볼 수 있습니다. 이것은 단지 작게 보는 것뿐만 아니라 화면 크기를 넘어서는 큰 뷰를 만들 때도 활용 할 수 있는데, 뷰의 크기가 기기의 크기보다 크더라도 Preview가 그것에 맞게 늘어나 전체 모습을 보면서 작업할 수 있습니다.

Fixed

ContentView()
  .previewLayout(.fixed(width: 350, height: 250))
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ForEach(["iPhone 12 Pro", "iPhone 8"], id: \.self) {
            ContentView()
                .previewLayout(.fixed(width: 350, height: 250))
                
                .previewDevice(PreviewDevice(rawValue: $0))
                .previewDisplayName($0) //각 프리뷰 컨테이너 이름지정
        }
    }
}

fixedpreview container의 크기를 고정하고자 할 때 사용합니다. 결과 화면에서도 뷰의 크기와 무관하게 컨테이너의 크기가 지정한 값으로 고정된 것을 확인 할 수 있죠. 너무 크거나 작지 않게 일정 공간을 확보한 상태로 확인하고자 할 때 사용하기 좋습니다.

가로모드

또, 아직 Preview에서는 가로 모드를 별도로 지원하지 않지만, 세로 모드일때의 너비와 높이를 맛바꾸어 입력하게 되면 가로 모드로 뷰를 표현하는 것과 유사한 효과를 낼 수도 있습니다.

 

예를들어 iPhone 11 Pro Max의 크기는 414 x 896포인트 이므로 이것을 반대로 896 x 414로 지정해주는것이죠. 가로 모드를 지원하는 앱이라면 이런 방법을 많이 활용하게 될 것입니다. :)

 

 

ContentView()
  .previewLayout(.fixed(width: 896, height: 414))

 

읽어주셔서 감사합니다🤟