NavigationLink เป็นองค์ประกอบควบคุมใน SwiftUI ที่ออกแบบมาสำหรับการเปลี่ยนไปยังหน้าจออื่นใน NavigationStack หรือ NavigationView ตาม Apple Developer Documentation, 2024 NavigationLink สร้างปุ่มที่เมื่อกดแล้วจะวาง View เป้าหมายลงในสแต็กนำทาง ใน iOS 16+ แนะนำให้ใช้ NavigationLink ร่วมกับ value และ NavigationDestination แทนที่จะใช้ destination โดยตรงเพื่อหลีกเลี่ยงการเริ่มต้น View เป้าหมายก่อนเวลาอันควร
ประเด็นสำคัญ
NavigationLink คือ View ที่เริ่มต้นการเปลี่ยนเส้นทางนำทางเมื่อกด ภายใน NavigationStack การกด NavigationLink จะวางหน้าจอเป้าหมายลงในสแต็กและแสดงปุ่มย้อนกลับของระบบ NavigationLink มีมาตั้งแต่ iOS 13 และเป็นวิธีการนำทางหลักของผู้ใช้ใน SwiftUI
NavigationLink ไม่ได้สืบทอดจาก UIButton — มันเป็น SwiftUI View ที่ปรับตัวตามบริบทโดยอัตโนมัติ ภายใน List NavigationLink จะแสดงพร้อมกับตัวบ่งชี้การเปิดเผย นอกรายการ NavigationLink จะทำงานเหมือนปุ่มทั่วไปแต่มีพฤติกรรมการนำทาง
ตาม SwiftUI Lab (2024) NavigationLink เป็นหนึ่งใน Views ที่ใช้มากที่สุดในแอปพลิเคชัน SwiftUI รองจาก Text, Image และ VStack การเข้าใจความแตกต่างระหว่างรูปแบบการเริ่มต้นเป็นสิ่งสำคัญสำหรับประสิทธิภาพและพฤติกรรมการนำทางที่คาดเดาได้
เมื่อกด NavigationLink จะเพิ่มค่า (หรือ destination) ลงในสแต็กนำทางที่เชื่อมโยงกับ NavigationStack หรือ NavigationView ที่ใกล้ที่สุด SwiftUI ใช้ EnvironmentValue เพื่อส่งเส้นทางนำทางผ่านลำดับชั้นของ View NavigationLink อ่านเส้นทางนี้จาก Environment และแก้ไขเมื่อกด
NavigationLink มีสองรูปแบบหลัก: แบบ destination (ระบุ View เป้าหมายโดยตรง) และแบบ value (ค่าสำหรับ NavigationDestination) การเลือกรูปแบบขึ้นอยู่กับเวอร์ชัน iOS และสถาปัตยกรรมการนำทาง
| รูปแบบ | ตัวเริ่มต้น | iOS 13–15 | iOS 16+ |
|---|---|---|---|
| Destination | NavigationLink(destination:label:) | แนะนำ | ไม่แนะนำ |
| Value | NavigationLink(value:label:) | ไม่พร้อมใช้งาน | แนะนำ |
| IsActive | NavigationLink(isActive:destination:label:) | การนำทางแบบโปรแกรม | ไม่แนะนำ |
รูปแบบ destination (iOS 13+): NavigationLink(destination: DetailView(), label: { Text("Open") }) รูปแบบนี้สร้าง DetailView ทันทีเมื่อเรนเดอร์ NavigationLink แม้ว่าผู้ใช้จะยังไม่ได้คลิกลิงก์ก็ตาม สิ่งนี้นำไปสู่การเริ่มต้น View ก่อนเวลาอันควรและปัญหาด้านประสิทธิภาพที่อาจเกิดขึ้นหาก View เป้าหมายดำเนินการหนักในตัวเริ่มต้น
รูปแบบ value (iOS 16+): NavigationLink(value: "detail_42", label: { Text("Open") }) View เป้าหมายจะถูกสร้างขึ้นเมื่อกดลิงก์เท่านั้น เมื่อ SwiftUI พบ .navigationDestination ที่เกี่ยวข้อง ซึ่งป้องกันการเริ่มต้นก่อนเวลาอันควรและทำให้การนำทางคาดเดาได้มากขึ้น
NavigationLink กับ NavigationStack ใน iOS 16+ ต้องเปลี่ยนไปใช้รูปแบบ value คุณกำหนดประเภทข้อมูลสำหรับการนำทาง (String, Int, enum Route) และลงทะเบียนปลายทางผ่าน .navigationDestination NavigationLink วางเพียงค่าในสแต็ก และ SwiftUI สร้าง View เป้าหมายเมื่อกด
struct CatalogView: View {
let categories: [String]
var body: some View {
List(categories, id: \.self) { category in
NavigationLink(value: category) {
Text(category)
}
}
.navigationDestination(for: String.self) { category in
CategoryView(name: category)
}
}
}
// Programmatic navigation:
struct DeepLinkView: View {
@State private var path: [AppRoute] = []
var body: some View {
NavigationStack(path: $path) {
HomeView()
.navigationDestination(for: AppRoute.self) { route in
switch route {
case .detail(let id): DetailView(id: id)
case .settings: SettingsView()
}
}
.toolbar {
Button("Open Settings") {
path.append(AppRoute.settings)
}
}
}
}
}
การนำทางแบบโปรแกรม: การเพิ่มค่าลงในเส้นทาง (ผ่าน path.append) เทียบเท่ากับการกด NavigationLink ด้วยค่าเดียวกัน ซึ่งช่วยให้สามารถนำทางการนำทางจาก ViewModel, Coordinator หรือตอบสนองต่อการแจ้งเตือนแบบพุช
รูปแบบ IsActive (NavigationLink(isActive:destination:label:)) พร้อมใช้งานสำหรับความเข้ากันได้ แต่ไม่แนะนำใน iOS 16+ ใช้รูปแบบ value พร้อม Binding กับอาร์เรย์เส้นทางหรือ NavigationPath
NavigationLink ใน List แสดงตัวบ่งชี้การเปิดเผย (chevron) ทางด้านขวาของแถวโดยอัตโนมัติ เพื่อส่งสัญญาณให้ผู้ใช้ทราบว่าการกดจะนำไปยังหน้าจออื่น List จัดการการแสดงลูกศรโดยอัตโนมัติ — ต่างจาก NavigationLink ทั่วไปภายนอกรายการที่ไม่มีลูกศร
กับ iOS 16 List ที่มี NavigationLink จะใช้รูปแบบ value โดยอัตโนมัติภายใน List(data:rowContent:) เมื่อใช้ ForEach ภายใน List ตัวบ่งชี้การเปิดเผยจะถูกเพิ่มโดยอัตโนมัติเช่นกัน พฤติกรรมนี้ไม่สามารถปิดใช้งานผ่านตัวปรับแต่ง — การแทนที่ NavigationLink ด้วย Button เท่านั้นที่สามารถลบลูกศรได้
ปัญหากับรูปแบบ destination ใน List: หากคุณใช้ NavigationLink(destination:label:) ภายใน List View ปลายทางทั้งหมดจะถูกสร้างขึ้นทันทีเมื่อโหลดรายการ ไม่ว่าผู้ใช้จะคลิกลิงก์หรือไม่ก็ตาม สำหรับรายการที่มีจำนวนแถวมาก สิ่งนี้อาจทำให้การโหลดเริ่มต้นช้าลงอย่างมากและเพิ่มการใช้หน่วยความจำ รูปแบบ value กับ NavigationStack แก้ปัญหานี้
ตาม WWDC 2022 (Session 10054) Apple แนะนำให้ใช้ NavigationStack และรูปแบบ value ของ NavigationLink สำหรับโปรเจกต์ใหม่ ซึ่งสำคัญโดยเฉพาะอย่างยิ่งสำหรับ List ที่มีข้อมูลไดนามิกที่จำนวนแถวอาจมีมาก
รูปแบบ 1: ลักษณะที่กำหนดเองของ NavigationLink NavigationLink ยอมรับ View ใด ๆ เป็น label ทำให้สามารถสร้างการออกแบบที่กำหนดเองสำหรับลิงก์ ภายใน List สะดวกเป็นพิเศษ — คุณจะได้รับตัวบ่งชี้การเปิดเผยอัตโนมัติเมื่อใช้ NavigationLink
NavigationLink(value: ProductRoute.detail(product)) {
HStack {
AsyncImage(url: product.imageURL)
.frame(width: 60, height: 60)
VStack(alignment: .leading) {
Text(product.name).font(.headline)
Text(product.price) .foregroundColor(.secondary)
}
}
.padding(8)
}
รูปแบบ 2: NavigationLink ไม่มีลูกศร (ปุ่มที่กำหนดเอง) หากคุณไม่ต้องการตัวบ่งชี้การเปิดเผย ให้ใช้ Button สำหรับการนำทางแบบโปรแกรม: path.append(value) ซึ่งมีประโยชน์สำหรับองค์ประกอบอินเทอร์เฟซที่กำหนดเองที่ NavigationLink ดูไม่เป็นธรรมชาติ
รูปแบบ 3: การนำทางแบบมีเงื่อนไข คุณสามารถบล็อก NavigationLink โดยใช้ destination ว่างหรือไม่เพิ่ม .navigationDestination สำหรับค่าบางค่า การนำทางแบบโปรแกรมผ่านเส้นทางช่วยให้ตรวจสอบเงื่อนไขก่อนเพิ่มค่า
ตาม Hacking with Swift (2024) ปัญหาส่วนใหญ่กับ NavigationLink เกี่ยวข้องกับการใช้รูปแบบ destination ในโปรเจกต์เก่า เมื่อโยกย้ายไปยัง NavigationStack ให้แทนที่ NavigationLink(destination:label:) ทั้งหมดด้วย NavigationLink(value:label:) และเพิ่ม .navigationDestination ที่ระดับราก
คำถามที่พบบ่อย
NavigationLink คือ View สำหรับเปลี่ยนไปยังหน้าจออื่นใน SwiftUI เมื่อกดจะวางหน้าจอเป้าหมายลงในสแต็กนำทาง NavigationStack หรือ NavigationView รองรับสองรูปแบบ: แบบ destination (View เป้าหมาย) และแบบ value (ค่าสำหรับเส้นทาง)
รูปแบบ value (iOS 16+) ดีกว่า: View เป้าหมายจะถูกสร้างขึ้นเมื่อกดเท่านั้น ไม่ใช่เมื่อเรนเดอร์ลิงก์ รูปแบบ destination สร้าง View ทันทีซึ่งอาจทำให้เกิดปัญหาด้านประสิทธิภาพ สำหรับโปรเจกต์ iOS 16+ ให้ใช้ value + NavigationDestination
SwiftUI เพิ่ม ตัวบ่งชี้การเปิดเผย (ลูกศร) ให้กับ NavigationLink ภายใน List โดยอัตโนมัติ เพื่อส่งสัญญาณถึงความเป็นไปได้ในการนำทาง พฤติกรรมนี้ไม่สามารถปิดใช้งานได้ หากไม่ต้องการลูกศร ให้ใช้ Button ที่มีการนำทางแบบโปรแกรมผ่าน path.append()
ใช้ NavigationStack พร้อม Binding เส้นทาง และเพิ่มค่าผ่าน path.append(value) ซึ่งเทียบเท่ากับการกด NavigationLink ด้วย value เดียวกัน การนำทางแบบโปรแกรมช่วยให้สามารถimplement ดีพลิงก์ การแจ้งเตือนแบบพุช และรูปแบบ Coordinator
รูปแบบ destination อาจส่งผลต่อประสิทธิภาพหาก View เป้าหมายดำเนินการที่ หนัก ในตัวเริ่มต้น — ปลายทางทั้งหมดจะถูกสร้างขึ้นเมื่อเรนเดอร์รายการ รูปแบบ value กับ NavigationStack แก้ปัญหานี้โดยสร้าง View เฉพาะเมื่อกด สำหรับรายการที่มี 50+ แถว ความแตกต่างมีนัยสำคัญ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ