1️⃣ Preview란?
- Previews in Xcode 공식문서
- PreviewProvider 공식문서
- Mastering Xcode Previews - WWDC 2019
- Structure your app for SwiftUI previews - WWDC 2020
Xcode에서는 실제 기기 및 시뮬레이터를 사용하지 않고 최신 상태의 뷰 콘텐츠를 표시할 수 있는 Preview 기능이 있습니다. 해당 기능을 사용하면 화면개발을 할 때 시간을 단축할 수 있도록 도움을 줍니다.
1-1. Preview의 동작원리
기본적으로 SwiftUI 프로젝트를 생성하면 하단의 Preview를 표시하는 코드가 생성됩니다.
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
- 현재 소스 에디터에 PreviewProvider프로토콜을 준수하는 타입이 존재하는지 확인
- PreviewProivder프로토콜의 필수 구현 사항인 previews 타입 프로퍼티에서 뷰 생성
- 액티브 스킬의 목적지로 선택한 시뮬레이터 또는 맥에 연결한 기기의 형태로 preview container 렌더링
- 리뷰 컨테이너를 직접 지정해 줄 경우 3번 에서 선택한 기기를 무시하고 해당 기기 형태로 렌더링
Preview는 수정결과가 자동으로 반영이 되지만 일부 수정결과에 대해서는 수동으로 빌드를 해야하는 경우가 있습니다.
- 수동으로 빌드해야하는 경우
- 프로퍼티와 메서드를 추가 / 제거 / 수정하는 경우
- 저장 프로퍼티의 값 변경
- 뷰의 타입 이름을 변경하거나 또 다른 뷰를 추가할 때
- 앱을 수동으로 빌드하는 경우
1-2. Preview의 수식어
Preview에서는 수정자를 활용하여 여러가지 옵션을 설정할 수 있습니다.
.preferredColorScheme(.dark) | 다크모드 설정하기 |
.previewDevice(PreviewDevice(rawValue: "iPhone 12 Pro Max")) | preview device변경 |
.previewDevice("iPhone 12") | 위의 수정자와 동일한 기능 |
.previewLayout(.fixed(width: 400, height: 700)) | 너비 400, 높이 700인 preview 표시 |
.previewLayout(.sizeThatFits) | size 만큼만 preview 표시 |
2️⃣ UIKit에서 Preview 사용하는 방법
UIKit에서 Preview를 사용하기 위해서는 Xcode 11이상, macOS Catalina이상, iOS13이상이여야 기능을 사용할 수 있다.
2-1. 환경 설정
- iOS 13이상에서 SwiftUI프레임워크, Debug모드에서만 동작하도록 설정합니다.
#if canImport(SwiftUI) && DEBUG
import SwiftUI
@available(iOS 13.0, *)
#endif
2-2. UIViewRepresentable 준수하는 View 생성
💡 UIView를 사용하는 경우 UIViewRepresentable을 채택하고, UIViewController를 사용하는 경우 UIViewControllerRepresentable을 채택합니다
- UIView를 생성한 후 UIViewRepresentable프로토콜을 준수하는 ViewRepresentable구조체 생성
2-3. PreviewProvider 생성
생성한 ViewRepresentable구조체를 Preview에서 생성
2-4. Extension으로 활용
UIViewController+Extension.swift
더보기
#if DEBUG
import SwiftUI
extension UIViewController {
/// PreView 동작하도로 도와 주는 구조체
struct Preview: UIViewControllerRepresentable {
let viewController: UIViewController
func makeUIViewController(context: Context) -> UIViewController {
return viewController
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
func toPreview() -> some View {
Preview(viewController: self)
}
}
/// 프리뷰 생성 도와주는 프로토콜
protocol PreviewSupporter {
associatedtype UIKitView: View
static func makeAllDeviceXcode14(storyboardName: String, identifierName: String, device: Xcode14Device) -> UIKitView
}
extension PreviewSupporter {
static func makeAllDeviceXcode14(storyboardName: String, identifierName: String, device: Xcode14Device) -> some View {
UIStoryboard(name: storyboardName, bundle: nil).instantiateViewController(identifier: identifierName).toPreview()
.previewDevice(PreviewDevice(rawValue: device.rawValue))
.previewDisplayName(device.rawValue)
}
}
/// 자동 생성은 Xcode메뉴에서 Editor -> Create Preview
/// 프리뷰 사용 예시 - NewLoginHomeViewController 온보딩 로그인화면 예시
struct ExamplePreView: PreviewProvider, PreviewSupporter {
static var previews: some View {
makeAllDeviceXcode14(storyboardName: "NewLoginHomeViewController", identifierName: "NewLoginHomeViewController", device: .iPhone14)
makeAllDeviceXcode14(storyboardName: "NewLoginHomeViewController", identifierName: "NewLoginHomeViewController", device: .iPhone14Pro)
makeAllDeviceXcode14(storyboardName: "NewLoginHomeViewController", identifierName: "NewLoginHomeViewController", device: .iPhone14Plus)
makeAllDeviceXcode14(storyboardName: "NewLoginHomeViewController", identifierName: "NewLoginHomeViewController", device: .iPadPro12)
makeAllDeviceXcode14(storyboardName: "NewLoginHomeViewController", identifierName: "NewLoginHomeViewController", device: .iPhoneSE3)
}
}
/// Xcode14에 내장된 기기 목록
enum Xcode14Device: String {
case iPhone14 = "iPhone 14"
case iPhone14Pro = "iPhone 14 Pro"
case iPhone14Plus = "iPhone 14 Plus"
case iPhoneSE3 = "iPhone SE (3rd generation)"
case iPadPro12 = "iPad Pro (12.9-inch) (6th generation)"
case iPadPro11 = "iPad Pro (11-inch) (4th generation)"
case iPadMini6 = "iPad mini (6th generation)"
case iPad10 = "iPad (10th generation)"
case iPadAir5 = "iPad Air (5th generation)"
}
#endif
3️⃣ Swift매크로 활용 (iOS17이상)
iOS 17이상 Xcode 15이상에서 기존의 Preview방식을 더욱 간단하게 사용하기 위해 매크로를 활용할 수 있습니다.
3-1. 활용 방법
SwiftUI
#Preview {
ContentView()
}
// name파라미터를 전달하여 Preview의 displayname을 전달할 수 있습니다.
#Preview("Sample") {
ContentView()
}
UIKIt
#Preview {
let vc = ViewController()
return vc
}
// name파라미터를 전달하여 Preview의 displayname을 전달할 수 있습니다.
#Preview("Sample") {
let vc = ViewController()
return vc
}
// Storyboard
#Preview("Sample") {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vc = storyboard.instantiateViewController(withIdentifier: "ViewController")
return controller
}
3-2. 응용
// 2개의 Preview 생성
#Preview("Article List View") {
ArticleListView()
}
#Preview("Article View") {
ArticleView()
}
// traits 활용 - landscape 모드 설정
#Preview("Article List View", traits: .landscapeLeft) {
ArticleListView()
}
// traits 활용 - 레이아웃 설정
#Preview("Article List View", traits: .fixedLayout(width: 300, height: 300)) {
ArticleListView()
}
#Preview("Article List View", traits: .sizeThatFitsLayout) {
ArticleListView()
}
4️⃣ Preview 에러 및 Tip
4-1. Preview is missing EnvironmentObject
에러 사항 : EnvironmentObject를 선언하고 Preview에서 인스턴스 생성해주지 않으면 발생하는 이슈
해결
struct RideRequestView: View {
@State private var selectedRideType: RideType = .uberX
@EnvironmentObject var locationViewModel: LocationSearchViewModel
...
}
struct RideRequestView_Previews: PreviewProvider {
static var previews: some View {
RideRequestView()
.environmentObject(LocationSearchViewModel())
}
}
- .environmentObject안에 인스턴스 생성을 하면 해결됩니다.
4-2. Canvas 창 표시방법
🔗 참고링크
'iOS > iOS (기본)' 카테고리의 다른 글
[iOS] iOS 14이상에서 UICollectionView 사용하기 (1) | 2024.04.18 |
---|