PreviewProvider เป็นโพรโทคอล SwiftUI ที่กำหนดจุดเริ่มต้นสำหรับสร้างพรีวิวใน Xcode Canvas การใช้งานโพรโทคอลช่วยให้นักพัฒนาเห็นอินเทอร์เฟซโดยไม่ต้องเปิดเครื่องจำลอง ช่วยเร่งการทำงานในขั้นตอนการจัดวาง ตามเอกสาร Apple Developer Documentation (2026) PreviewProvider เป็นสิ่งจำเป็นสำหรับ SwiftUI View ทั้งหมดหากโปรเจกต์ใช้ Canvas — หากไม่มี Canvas จะไม่แสดงอินเทอร์เฟซผู้ใช้ เรียนรู้เพิ่มเติมในบทความเกี่ยวกับ SwiftUI
หลักสำคัญ
PreviewProvider เป็นโพรโทคอล SwiftUI ที่กำหนดสัญญาสำหรับสร้างเนื้อหาพรีวิวใน Xcode Canvas โพรโทคอลมีคุณสมบัติที่จำเป็นหนึ่งอย่าง: previews ชนิด some View ค่าใดๆ ที่ previews ส่งคืนจะแสดงใน Canvas เป็นพรีวิวเชิงโต้ตอบ PreviewProvider ไม่ต้องการการสืบทอด — แค่การใช้งานแบบสแตติกใน extension ก็เพียงพอ
ในเชิงสถาปัตยกรรม PreviewProvider ไม่ได้เป็นส่วนหนึ่งของรันไทม์ SwiftUI — เป็นเพียงเครื่องมือสำหรับนักพัฒนาเท่านั้น โพรโทคอลถูกระบุด้วยแอตทริบิวต์ @available(iOS 13.0, *) และไม่ถูกคอมไพล์ในบิลด์รีลีส เนื่องจาก Xcode ใช้การคอมไพล์แบบมีเงื่อนไขเพื่อแยกโค้ดพรีวิวออกจากการผลิต ซึ่งหมายความว่า PreviewProvider ไม่ส่งผลกระทบต่อขนาดไบนารีหรือประสิทธิภาพของแอปพลิเคชัน
คุณสมบัติ previews เป็นข้อกำหนดเดียวของ PreviewProvider โดยต้องส่งคืน View ใดๆ ก็ได้: จาก Text ธรรมดาไปจนถึงลำดับชั้นที่ซับซ้อนกับ Group และ ForEach Xcode เรนเดอร์ View ที่ส่งคืนใน Canvas โดยใช้การตั้งค่าระบบ (ธีม ขนาด ฟอนต์)
import SwiftUI
struct GreetingView: View {
let name: String
var body: some View {
Text("Hello, \(name)!")
.padding()
}
}
// PreviewProvider — static implementation
struct GreetingView_Previews: PreviewProvider {
static var previews: some View {
GreetingView(name: "World")
}
}
ธรรมเนียมการตั้งชื่อ: Apple แนะนำให้ตั้งชื่อโครงสร้างพรีวิวเป็น {ViewName}_Previews ซึ่งไม่ใช่ข้อกำหนดของคอมไพเลอร์ แต่ช่วยเพิ่มความสามารถในการอ่านและการนำทางในโปรเจกต์ Xcode จะแทรกเทมเพลตนี้โดยอัตโนมัติเมื่อสร้างไฟล์ SwiftUI ใหม่
กลไกการทำงานของ PreviewProvider ขึ้นอยู่กับการจัดส่งแบบสแตติก: Xcode คอมไพล์ extension ของ PreviewProvider เฉพาะสำหรับการกำหนดค่า Debug และเรียก previews ในกระบวนการสร้าง Canvas ทุกครั้งที่โค้ดเปลี่ยนแปลง Xcode จะคอมไพล์เฉพาะ PreviewProvider ที่ถูกแก้ไขเท่านั้น ทำให้มั่นใจได้ว่าการอัปเดตพรีวิวเกือบจะทันที
SwiftUI ไม่รับประกันความตรงกันที่แน่นอนระหว่างพรีวิวและอินเทอร์เฟซผู้ใช้สุดท้ายบนเครื่องจำลองหรืออุปกรณ์ — Canvas ใช้การเรนเดอร์แบบง่าย แอนิเมชันที่มีความล่าช้าอาจแสดงไม่ถูกต้อง และส่วนประกอบ UIKit บางอย่าง (MapKit, WebView) จะไม่เรนเดอร์ใน Canvas หากไม่มีการกำหนดค่าเพิ่มเติม
Group ช่วยให้แสดงหลายสถานะของ View เดียวกันพร้อมกัน ช่วยเร่งการทำงานเมื่อจัดวางการกำหนดค่าต่างๆ แต่ละพรีวิวภายใน Group จะเรนเดอร์อย่างอิสระ
struct ButtonView_Previews: PreviewProvider {
static var previews: some View {
Group {
ButtonView(title: "Primary", style: .primary)
.previewDisplayName("Primary")
ButtonView(title: "Disabled", style: .primary)
.disabled(true)
.previewDisplayName("Disabled")
ButtonView(title: "Secondary", style: .secondary)
.previewDisplayName("Secondary")
}
}
}
previewDisplayName เพิ่มป้ายกำกับให้แต่ละพรีวิวใน Canvas ซึ่งมีประโยชน์โดยเฉพาะเมื่อเปรียบเทียบหลายสถานะ จำนวนพรีวิวสูงสุดใน Group ไม่จำกัด แต่เกิน 6–8 จะทำให้ Canvas ช้าลง
Xcode มี ตัวปรับแต่งหลายตัวสำหรับกำหนดค่าการแสดงพรีวิว หลักๆ: previewDevice — จำลองอุปกรณ์เฉพาะ (iPhone 16 Pro, iPad Air, Apple Watch Ultra), previewLayout — กำหนดขนาด (device, fixed, sizeThatFits) การรวมกันของตัวปรับแต่งเหล่านี้ให้การควบคุมสภาพแวดล้อมพรีวิวอย่างสมบูรณ์
previewDevice รับสตริงที่มีชื่ออุปกรณ์ เช่น "iPhone 16 Pro" หรือ "iPad Pro 13-inch (M4)" รายการอุปกรณ์ที่มีขึ้นอยู่กับเครื่องจำลองที่ติดตั้งใน Xcode หากไม่พบอุปกรณ์ Canvas จะแสดงพรีวิวบนอุปกรณ์เริ่มต้นโดยไม่มีข้อผิดพลาด
| ตัวปรับแต่ง | คำอธิบาย | ตัวอย่าง |
|---|---|---|
| previewDevice | การจำลองอุปกรณ์ | .previewDevice("iPhone 16 Pro") |
| previewLayout | โหมดขนาด | .previewLayout(.sizeThatFits) |
| previewDisplayName | ป้ายกำกับพรีวิว | .previewDisplayName("Dark Mode") |
| preferredColorScheme | โทนสี | .preferredColorScheme(.dark) |
| dynamicTypeSize | ขนาดฟอนต์ | .dynamicTypeSize(.xxxLarge) |
แนวทางปฏิบัติทั่วไป คือการแสดง View เดียวกันบนหลายอุปกรณ์พร้อมกันเพื่อตรวจสอบความสามารถในการปรับเปลี่ยน โดยใช้ ForEach กับอาร์เรย์ชื่ออุปกรณ์
struct AdaptiveView_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE (3rd generation)", "iPhone 16 Pro Max", "iPad Pro 13-inch (M4)"], id: \.self) { device in
AdaptiveView()
.previewDevice(.previewDevice(device))
.previewDisplayName(device)
}
}
}
ตัวอย่างเชิงปฏิบัติ แสดงสถานการณ์การใช้งาน PreviewProvider ที่หลากหลาย: ตั้งแต่พรีวิวธรรมดาไปจนถึงการกำหนดค่าที่ซับซ้อนกับข้อมูลจริงและความเข้ากันได้กับ UIKit
ข้อมูลจำลอง เป็นรูปแบบมาตรฐานสำหรับพรีวิวเมื่อ View รับโมเดล แทนที่ API จริงด้วยข้อมูลทดสอบ ช่วยให้ตรวจสอบสถานะ UI ด้วยตาโดยไม่ต้องเปิดแอปพลิเคชัน
struct UserProfileView: View {
let user: User
var body: some View {
VStack {
AsyncImage(url: user.avatarURL)
.clipShape(Circle())
Text(user.name)
.font(.title)
Text(user.bio)
.font(.body)
.foregroundColor(.secondary)
}
}
}
struct UserProfileView_Previews: PreviewProvider {
static var previews: some View {
UserProfileView(user: .mock)
.previewDisplayName("Profile")
UserProfileView(user: .mockLongName)
.previewDisplayName("Long Name")
}
}
ความเข้ากันได้กับ UIKit — PreviewProvider ทำงานกับส่วนประกอบ UIKit ที่ห่อใน UIViewRepresentable ด้วย ซึ่งช่วยให้พรีวิว UIKit View ที่มีอยู่ใน SwiftUI Canvas โดยไม่ต้องย้ายทั้งโปรเจกต์
struct MapViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
MKMapView()
}
func updateUIView(_ uiView: MKMapView, context: Context) {
// Configure map
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapViewRepresentable()
}
}
Canvas เป็นตัวแก้ไขภาพของ Xcode ที่เรนเดอร์ผลลัพธ์ของ PreviewProvider แบบเรียลไทม์ หากไม่มีการใช้งาน PreviewProvider Canvas จะว่างเปล่า Canvas และ PreviewProvider ทำงานเป็นคู่: PreviewProvider กำหนดสิ่งที่แสดง Canvas กำหนดตำแหน่งและวิธีการ
สิ่งสำคัญคือต้องเข้าใจ: Canvas เป็นสภาพแวดล้อมการทำงานของพรีวิว ไม่ใช่ทางเลือกแทน PreviewProvider แม้ว่านักพัฒนาจะไม่เปิด Canvas ก็สามารถใช้ PreviewProvider เพื่อตรวจสอบโค้ดอย่างรวดเร็วผ่านพรีวิวป๊อปอัปเมื่อวางเมาส์เหนือไอคอน Canvas ตามข้อมูล WWDC 2024 Apple แนะนำให้เขียน PreviewProvider สำหรับทุก View เป็นมาตรฐานการพัฒนา คล้ายกับการเขียน unit test
| ส่วนประกอบ | บทบาท | ความจำเป็น |
|---|---|---|
| PreviewProvider | กำหนดเนื้อหาพรีวิว | จำเป็นสำหรับ Canvas |
| Canvas | เรนเดอร์พรีวิวในตัวแก้ไข | เลือกได้ (สามารถใช้ .preview) |
| SwiftUI View | ส่วนประกอบ UI | จำเป็น |
คำแนะนำ: เขียน PreviewProvider สำหรับทุก View สาธารณะในโปรเจกต์ ซึ่งช่วยเร่งการเริ่มต้นของนักพัฒนาใหม่ ทำให้การตรวจสอบโค้ดง่ายขึ้น และช่วยตรวจสอบการเปลี่ยนแปลงภาพได้อย่างรวดเร็วโดยไม่ต้องสร้างทั้งโปรเจกต์
ปัญหา 1: พรีวิวไม่อัปเดต หาก Canvas ไม่สะท้อนการเปลี่ยนแปลงโค้ด สาเหตุมักมาจากแคช DerivedData ล้าง DerivedData ผ่าน Product → Clean Build Folder (⇧⌘K) หรือลบโฟลเดอร์ ~/Library/Developer/Xcode/DerivedData ด้วยตนเอง หลังจากทำความสะอาด Canvas จะสร้างพรีวิวใหม่ทั้งหมด
ปัญหา 2: PreviewProvider ไม่เห็น @StateObject PreviewProvider สร้างอินสแตนซ์แบบสแตติกของ View ดังนั้นการพึ่งพาที่ต้องการการฉีด (ViewModels, บริการ) ต้องถูกส่งผ่านตัวเริ่มต้นหรือ @StateObject พร้อมค่าเริ่มต้น ใช้วัตถุจำลองแทนบริการจริงในพรีวิว
ปัญหา 3: แอนิเมชันไม่ทำงานใน Canvas Canvas ไม่รองรับแอนิเมชัน SwiftUI ทั้งหมด — โดยเฉพาะที่ขึ้นอยู่กับเวลา (withAnimation ที่มีความล่าช้า, .spring) สำหรับการทดสอบแอนิเมชัน ให้รันแอปพลิเคชันบนเครื่องจำลอง Canvas เหมาะสำหรับการตรวจสอบเลย์เอาต์แบบสแตติก
การฉีดการพึ่งพา เป็นวิธีที่ดีที่สุดในการทำให้ PreviewProvider ทำงานกับ ViewModels ที่ซับซ้อน สร้างอินสแตนซ์ ViewModel แยกต่างหากพร้อมข้อมูลทดสอบและส่งไปยังตัวเริ่มต้นของ View
struct DashboardView: View {
@StateObject var viewModel: DashboardViewModel
var body: some View {
List(viewModel.items) { item in
Text(item.title)
}
}
}
struct DashboardView_Previews: PreviewProvider {
static var previews: some View {
DashboardView(viewModel: DashboardViewModel.mock)
}
}
ส่วนขยายจำลอง: สร้าง extension สำหรับ ViewModel ที่ให้อินสแตนซ์ .mock แบบสแตติก ซึ่งเก็บข้อมูลทดสอบไว้ใกล้กับ ViewModel และทำให้ PreviewProvider อ่านง่าย
คำถามที่พบบ่อย
ในทางเทคนิคไม่จำเป็น — แอปพลิเคชันจะคอมไพล์โดยไม่มี PreviewProvider อย่างไรก็ตาม ในทางปฏิบัติ Apple และชุมชน SwiftUI แนะนำให้เขียนพรีวิวสำหรับทุก View สาธารณะ PreviewProvider ช่วยเร่งการพัฒนา ให้ตรวจสอบเลย์เอาต์บนอุปกรณ์ต่างๆ ได้อย่างรวดเร็ว และทำหน้าที่เป็นเอกสารภาพสำหรับทีม
PreviewProvider เพิ่มโค้ดเฉพาะในบิลด์ Debug ดังนั้นข้อผิดพลาดการคอมไพล์อาจเกิดขึ้นหากพรีวิวใช้ชนิดที่ไม่พร้อมใช้งานในการกำหนดค่ารีลีส ข้อผิดพลาดยังเกิดขึ้นเมื่อใช้ @available กับแพลตฟอร์มที่ไม่รองรับ Canvas หรือเมื่อเกินขีดจำกัดความซับซ้อนของพรีวิว
โดยตรง — ไม่สามารถทำได้ PreviewProvider ทำงานแบบแยกส่วน ใช้ข้อมูลจำลอง: สร้าง extension แบบสแตติกของโมเดลพร้อมอินสแตนซ์ .mock สำหรับ View ที่มี @StateObject ให้ส่ง ViewModel พร้อมข้อมูลทดสอบผ่านตัวเริ่มต้น ซึ่งจำลองข้อมูลจริงโดยไม่ต้องร้องขอเครือข่าย
ไม่ PreviewProvider ไม่ส่งผลต่อขนาดไบนารีรีลีส Xcode ใช้การคอมไพล์แบบมีเงื่อนไข (#if DEBUG / #if !RELEASE) เพื่อแยกโค้ดพรีวิวออกจากบิลด์รีลีส โค้ด PreviewProvider มีเฉพาะในการกำหนดค่า Debug และไม่เข้าไปในบิลด์ App Store
ได้ Xcode รองรับการดีบักพรีวิว ตั้ง breakpoint ภายใน previews หรือโค้ด View เองแล้วเลือก Product → Preview → Debug Preview breakpoint จะทำงานระหว่างการเรนเดอร์ Canvas ซึ่งมีประโยชน์สำหรับการวิเคราะห์ปัญหาเลย์เอาต์ที่มองเห็นได้เฉพาะในพรีวิว
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ