Terjemahan artikel ini disiapkan pada malam peluncuran kursus lanjutan "Pengembang iOS" .
Halo dan selamat datang di tutorial kami! Dalam seri ini, kita berbicara tentang cara menavigasi antara tampilan di SwiftUI (tanpa menggunakan tampilan navigasi!). Meskipun ide ini mungkin tampak sepele, tetapi dengan memahaminya sedikit lebih dalam, kita dapat belajar banyak tentang konsep aliran data yang digunakan dalam SwiftUI.Pada bagian sebelumnya, kami belajar cara menerapkan ini menggunakan @ObservableObject
. Pada bagian ini, kita akan melihat bagaimana melakukan hal yang sama, tetapi lebih efisien menggunakan @EnvironmentObject. Kami juga akan menambahkan animasi transisi kecil.Inilah yang akan kita capai:Apa yang kita miliki
Jadi, kami baru tahu cara menavigasi antara tampilan yang berbeda menggunakan ObservableObject. Singkatnya, kami membuat ViewRouter dan mengaitkannya dengan Tampilan Ibu dan Tampilan Konten kami. Selanjutnya, kita cukup memanipulasi properti CurrentRage ViewRouter dengan mengklik tombol Content View. Setelah itu, MotherView diperbarui untuk menampilkan Tampilan Konten yang sesuai!Tetapi ada cara kedua yang lebih efisien untuk mencapai fungsi ini: gunakan @EnvironmentObject
!Petunjuk: Anda dapat mengunduh perkembangan terbaru di sini (ini adalah folder "NavigateInSwiftUIComplete") : GitHubMengapa menggunakan ObservableObject
bukanlah solusi terbaik
Anda mungkin bertanya-tanya: mengapa kita harus menerapkan ini dengan cara lain, ketika kita sudah memiliki solusi yang berfungsi? Nah, jika Anda melihat logika hierarki aplikasi kami, maka itu akan menjadi jelas bagi Anda. MotherView kami adalah tampilan root yang menginisialisasi instance ViewRouter. Dalam MotherView, kami juga menginisialisasi ContentViewA dan ContentViewB, melewati mereka contoh ViewRouter sebagai BindableObject.Seperti yang Anda lihat, kita harus mengikuti hierarki ketat yang melewati hilir ObservableOb yang diinisialisasi ke semua subview. Sekarang ini tidak begitu penting, tetapi bayangkan aplikasi yang lebih kompleks dengan banyak pandangan. Kita selalu perlu melacak transmisi tampilan root yang dapat diobservasi yang diinisialisasi ke semua subview dan semua subview subview, dll., Yang pada akhirnya bisa menjadi tugas yang agak membosankan.
Untuk meringkas: menggunakan clean ObservableObject
bisa menjadi masalah ketika datang ke hierarki aplikasi yang lebih kompleks.Sebagai gantinya, kita dapat menginisialisasi ViewRouter ketika aplikasi dimulai sehingga semua tampilan dapat terhubung langsung ke instance ini, atau, lebih tepatnya, menontonnya, terlepas dari hierarki aplikasi. Dalam hal ini, instance ViewRouter akan terlihat seperti awan yang terbang di atas kode aplikasi kita, yang semua akses secara otomatis mengakses tanpa khawatir tentang rantai inisialisasi yang benar di hierarki tampilan.Ini hanya pekerjaan EnvironmentObject
!Apa EnvironmentObject
?
EnvironmentObject
Adalah model data yang, setelah inisialisasi, dapat bertukar data dengan semua representasi aplikasi Anda. Apa yang sangat baik adalah apa yang EnvironmentObject
diciptakan dengan menyediakan ObservableObject
, sehingga kita dapat menggunakan milik kita ViewRouter
untuk membuat EnvironmentObject
!Segera setelah kami menyatakan milik kami ViewRouter
sebagai EnvironmentObject
, semua representasi dapat dilampirkan padanya dengan cara yang sama seperti yang biasa ObservableObject
, tetapi tanpa perlu rantai inisialisasi ke hierarki aplikasi!Seperti yang telah disebutkan, ini EnvironmentObject
harus sudah diinisialisasi saat pertama kali diakses. Karena properti kita MotherView
, sebagai tampilan root, akan melihat properti CurrentPage
ViewRouter
, kita harus menginisialisasi EnvironmentObject
ketika aplikasi dimulai. Kemudian kita dapat secara otomatis mengubah Halaman saat iniEnvironmentObject
dari ContentView
, yang kemudian memanggil MotherView
rendering ulang.
Implementasi ViewRouter
sebagaiEnvironmentObject
Jadi, mari perbarui kode aplikasi kita!Pertama, ubah pembungkus properti viewRouter
di dalamnya MotherView
dari @ObservableObject
menjadi @EnvironmentObject
.import SwiftUI
struct MotherView : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
}
}
Properti viewRouter
sekarang mencari ViewRouter-EnvironmentObject
. Karena itu, kita perlu menyediakan struktur kita MotherView_Previews
dengan contoh yang sesuai:#if DEBUG
struct MotherView_Previews : PreviewProvider {
static var previews: some View {
MotherView().environmentObject(ViewRouter())
}
}
#endif
Seperti disebutkan di atas - ketika memulai aplikasi kita, itu harus segera disediakan dengan contoh ViewRouter
dalam kualitas EnvironmentObject
, karena MotherView
sekarang disebut sebagai representasi root EnvironmentObject
. Oleh karena itu, perbarui fungsi adegan di dalam file SceneDelegage.swift
sebagai berikut:func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: MotherView().environmentObject(ViewRouter()))
self.window = window
window.makeKeyAndVisible()
}
}
Hebat, sekarang ketika Anda memulai aplikasi, SwiftUI membuat instance ViewRouter
dalam kualitas EnvironmentObject
, yang mana semua tampilan aplikasi kita sekarang dapat dilampirkan.Selanjutnya, mari perbarui kami ContentViewA
. Ubah viewRouter
propertinya ke EnvironmentObject
dan juga perbarui struktur ContentViewA_Previews
.import SwiftUI
struct ContentViewA : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
}
}
#if DEBUG
struct ContentViewA_Previews : PreviewProvider {
static var previews: some View {
ContentViewA().environmentObject(ViewRouter())
}
}
#endif
Petunjuk: Sekali lagi, struktur ContentViewsA_Previews
memiliki turunannya sendiri ViewRouter
, tetapi ContentViewA
dikaitkan dengan turunan yang dibuat ketika aplikasi diluncurkan!Mari kita ulangi ini untuk ContentViewB
:import SwiftUI
struct ContentViewB : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
}
}
#if DEBUG
struct ContentViewB_Previews : PreviewProvider {
static var previews: some View {
ContentViewB().environmentObject(ViewRouter())
}
}
#endif
Karena properti viewRouter
kami ContentView
sekarang terkait langsung dengan / mengamati instance awal ViewRouter
sebagai EnvironmentObject
, kita tidak perlu lagi menginisialisasi mereka di properti kita MotherView
. Jadi, mari perbarui MotherView
:struct MotherView : View {
@EnvironmentObject var viewRouter: ViewRouter
var body: some View {
VStack {
if viewRouter.currentPage == "page1" {
ContentViewA()
} else if viewRouter.currentPage == "page2" {
ContentViewB()
}
}
}
}
Ini luar biasa: kita tidak perlu lagi menginisialisasi ViewRouter
di dalam milik kita MotherView
dan meneruskannya ke ContentView, yang bisa sangat efisien, terutama untuk hierarki yang lebih kompleks.Luar biasa, mari kita jalankan aplikasi kita dan melihat cara kerjanya. Hebat, kita masih bisa bergerak di antara pandangan kita!Menambahkan animasi transisi
Sebagai bonus, mari kita lihat bagaimana menambahkan animasi transisi ketika beralih dari "page1" ke "page2".Di SwiftUI, ini cukup sederhana.Lihatlah willChange
metode yang kami sebut file ViewRouter.swift
ketika CurrentPage
diperbarui. Seperti yang sudah Anda ketahui, ini menyebabkan pengikatan MotherView
untuk menampilkan kembali tubuh Anda, akhirnya menunjukkan yang lain ContentView
, yang berarti pindah ke yang lain ContentView
. Kami dapat menambahkan animasi dengan hanya membungkus metode willChange
dalam suatu fungsi withAnimation
:var currentPage: String = "page1" {
didSet {
withAnimation() {
willChange.send(self)
}
}
}
Sekarang kita dapat menambahkan animasi transisi saat menampilkan yang lain Content View
.“WithAnimation (_: _ :) - mengembalikan hasil penghitungan ulang tampilan tubuh dengan animasi yang disediakan”
Apple
Kami ingin memberikan transisi pop-up aplikasi saat menavigasi dari ContentViewA
ke ContentViewB
. Untuk melakukan ini, buka file MotherView.swift
dan tambahkan pengubah transisi saat dipanggil ContentViewB
. Anda dapat memilih salah satu dari beberapa jenis transisi yang telah ditentukan atau bahkan membuat sendiri (tetapi ini adalah topik untuk artikel lain). Untuk menambahkan transisi pop-up, kami memilih jenis .scale
.var body: some View {
VStack {
if viewRouter.currentPage == "page1" {
ContentViewA()
} else if viewRouter.currentPage == "page2" {
ContentViewB()
.transition(.scale)
}
}
}
Untuk melihat cara kerjanya, jalankan aplikasi Anda dalam simulator biasa: Keren, kami menambahkan animasi transisi yang bagus ke aplikasi kami hanya dalam beberapa baris kode!Anda dapat mengunduh semua kode sumber di sini !Kesimpulan
Itu saja! Kami belajar mengapa lebih baik digunakan EnvironmentObject
untuk menavigasi antara tampilan di SwiftUI, dan bagaimana menerapkannya. Kami juga belajar cara menambahkan animasi transisi ke navigasi. Jika Anda ingin tahu lebih banyak, ikuti kami di Instagram dan berlangganan buletin kami agar tidak ketinggalan pembaruan, tutorial, dan tips tentang SwiftUI dan banyak lagi!
Pelajaran gratis: “Mempercepat aplikasi iOS dengan instrumen”