SwiftUI: Kenalan

Dalam tutorial ini, kita akan belajar bagaimana merencanakan aplikasi UI menggunakan View dan belajar bagaimana menggunakan variabel State untuk memodifikasi UI.

Perkiraan waktu membaca: 25 menit.

SwiftUI memungkinkan kita untuk sepenuhnya melupakan Interface Builder (IB) dan storyboard. IB dan Xcode adalah aplikasi terpisah sebelum Xcode 4, tetapi "docking" di antara mereka masih terlihat ketika kami mengedit nama IBAction atau IBOutlet dan aplikasi kami macet, sehingga IB tidak tahu apa-apa tentang perubahan kode. Atau ketika kita menetapkan pengidentifikasi untuk segue atau untuk sel tabel, tetapi Xcode tidak dapat memeriksanya, karena mereka adalah string.

SwiftUI untuk menyelamatkan! Kami segera melihat perubahan dalam Tampilan segera setelah kami memasukkan kode. Perubahan di satu sisi menghasilkan pembaruan di sisi lain, sehingga selalu terkait. Tidak ada pengidentifikasi string yang bisa salah. Dan ini semua kode, tetapi jauh lebih kecil daripada jika kita menulisnya menggunakan UIKit, jadi lebih mudah untuk memahami, mengedit, dan men-debug-nya. Katakan padaku, bukankah itu luar biasa?

Ayo pergi


Mari kita mulai proyek baru di proyek Xcode ( Shift-Command-N ), pilih iOS ▸ Aplikasi Tampilan Tunggal , panggil RGBullsEye, dan pastikan untuk memilih SwiftUI sebagai antarmuka.

Sekarang AppDelegate.swift dibagi menjadi dua file: AppDelegate.swift dan SceneDelegate.swift , dan SceneDelegate berisi jendela:



SceneDelegate hampir tidak terkait dengan SwiftUI, dengan pengecualian pada baris ini:

window.rootViewController = UIHostingController(rootView: ContentView()) 

UIHostingController membuat pengendali tampilan untuk SwiftUI-view ContentView .
Catatan: UIHostingController memungkinkan kita untuk mengintegrasikan tampilan SwiftUI ke dalam aplikasi yang sudah ada. Tambahkan Pengendali Tampilan Hosting ke storyboard kami dan buatlah segue darinya dari UIViewController. Kemudian kita menggunakan Control-drag dengan segue pada kode pengontrol tampilan untuk membuat IBSegueAction , di mana kita mengatur pengontrol hosting ke rootView - SwiftUI-view.
Ketika aplikasi dimulai, jendela menampilkan instance dari ContentView , yang didefinisikan dalam file ContentView.swift . Ini adalah struct yang sesuai dengan protokol View :

 struct ContentView: View { var body: some View { Text("Hello World") } } 

Ini adalah deklarasi SwiftUI tentang konten ContentView ( tubuh ). Sekarang ada tampilan teks dengan teks Hello World.

Tepat di bawah ContentView_Previews mengembalikan instance dari ContentView.

 struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } 

Di sini kita dapat mengatur data uji untuk pratinjau. Tapi di mana tepatnya preview ini?

Segera setelah kode tersebut ada ruang kosong yang besar dengan ini di atas:



Klik Lanjutkan , tunggu sebentar dan ...



Buat sketsa UI kami


Sesuatu yang akrab tidak terlihat - ini adalah file Main.storyboard . Kita akan membuat UI kita menggunakan SwiftUI, tepat di kode, dalam proses melihat pratinjau: apa yang kita dapatkan di sana? Tapi jangan khawatir, kami tidak perlu menulis ratusan baris kode untuk membuat tampilan kami.

SwiftUI bersifat deklaratif: Anda menyatakan seperti apa tampilan UI Anda, dan SwiftUI mengonversi semua ini menjadi kode efisien yang melakukan semua pekerjaan. Apple memungkinkan Anda untuk membuat sebanyak mungkin tampilan yang diperlukan sehingga kodenya sederhana dan mudah. Tampilan yang dapat digunakan kembali dengan parameter sangat disarankan - ini mirip dengan mengalokasikan kode ke fungsi terpisah. Anda akan melakukannya sendiri nanti.

Aplikasi kita akan memiliki banyak tampilan, jadi untuk permulaan kita akan membuat sketsa tampilan teks sebagai bertopik.

Ganti Teks ("Hello World") dengan ini:

 Text("Target Color Block") 

Jika perlu, klik Lanjutkan untuk memperbarui pratinjau.

Sekarang lakukan Command-Click pada tampilan ini di preview , dan pilih Embed in HStack :



Harap perhatikan bahwa kode Anda juga telah berubah:

 HStack { Text("Target Color Block") } 

Salin dan tempel operator Teks, dan edit di dalam HStack kami. Harap dicatat: kami tidak memisahkan operator dengan koma, tetapi menulis masing-masing operator pada baris baru:

 HStack { Text("Target Color Block") Text("Guess Color Block") } 

Dan seperti yang terlihat di pratinjau:



Sekarang mari kita siapkan tempat untuk bertopik slider dengan menempatkan HStack di VStack . Kali ini kita akan melakukan Command-Click pada HStack dalam kode kita :



Pilih Sematkan di VStack ; kode baru akan muncul, tetapi pratinjau tidak akan berubah. Sebentar lagi kita akan menambahkan tampilan di bawah blok warna masa depan.

Tambahkan baris baru segera setelah HStack, klik + pada bilah alat untuk membuka perpustakaan dan seret Vertical Stack ke baris baru:



Seperti yang diharapkan, kode dan pratinjau telah berubah:



Selesaikan pekerjaan pada draft UI, sehingga semuanya terlihat seperti ini:

 VStack { HStack { Text("Target Color Block") Text("Guess Color Block") } Text("Hit me button") VStack { Text("Red slider") Text("Green slider") Text("Blue slider") } } 

Di VStack baru, tiga slider akan muncul sedikit kemudian, serta tombol antara slider dan blok warna.

Kami terus bekerja di UI


Sekarang mari kita berlatih di SwiftUI untuk mengisi HStack yang berisi blok berwarna:

 HStack { // Target color block VStack { Rectangle() Text("Match this color") } // Guess color block VStack { Rectangle() HStack { Text("R: xxx") Text("G: xxx") Text("B: xxx") } } } 

Setiap blok warna memiliki Rectangle. Blok warna Target (Target) memiliki satu tampilan Teks di bawah persegi panjang, dan yang dipilih (Tebak) memiliki tiga tampilan Teks. Beberapa saat kemudian kami akan mengganti 'xxx' dengan nilai sebenarnya dari bilah geser.

Menggunakan Variabel '@State'


Di SwiftUI, kita bisa menggunakan variabel reguler, tetapi jika kita ingin perubahan variabel memengaruhi UI, maka kita menandai variabel seperti '@State' . Dalam aplikasi kami, kami memilih warna, sehingga semua variabel yang memengaruhi warna yang dipilih adalah variabel '@State'.

Tambahkan baris ini di dalam struct ContentView , sebelum deklarasi body :

 let rTarget = Double.random(in: 0..<1) let gTarget = Double.random(in: 0..<1) let bTarget = Double.random(in: 0..<1) @State var rGuess: Double @State var gGuess: Double @State var bGuess: Double 

Nilai-nilai R, G dan B terletak di antara 0 dan 1. Kami menginisialisasi nilai yang diinginkan dengan nilai acak. Kami juga dapat menginisialisasi nilai yang dipilih ke 0,5, tetapi membiarkannya tidak diinisialisasi untuk saat ini untuk menunjukkan apa yang perlu dilakukan dalam kasus ini.

Mari kita sedikit lebih rendah ke struct ContentView_Previews , yang menginisialisasi instance ContentView untuk pratinjau . Sekarang penginisialisasi membutuhkan nilai awal dari nilai yang dipilih. Ubah ContentView () seperti ini:

 ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5) 

Saat kami membuat bilah geser, di pratinjau nilainya akan berada di tengah.

Kita juga harus memperbaiki initializer di SceneDelegate , dalam fungsi scene (_: willConnectTo: options :) - ganti ContentView () dengan yang berikut:

 window.rootViewController = UIHostingController(rootView: ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5)) 

Saat aplikasi dimuat, penggeser slider akan berada di tengah.

Sekarang tambahkan pengubah warna ke kotak target:

 Rectangle() .foregroundColor(Color(red: rTarget, green: gTarget, blue: bTarget, opacity: 1.0)) 

Pengubah .foregroundColor membuat tampilan Rectangle baru dengan warna yang ditentukan oleh nilai-nilai RGB yang dihasilkan secara acak.

Demikian pula, modifikasi kotak menebak:

 Rectangle() .foregroundColor(Color(red: rGuess, green: gGuess, blue: bGuess, opacity: 1.0)) 

Dengan nilai R, G dan B pada 0,5 kita mendapatkan warna abu-abu.

Klik Lanjutkan dan tunggu sebentar.



Membuat tampilan dapat digunakan kembali


Pertama, kita tidak akan memikirkan penggunaan kembali dan hanya membuat slider untuk warna merah. Di VStack untuk slider, ganti plug Text ("Red slider") dengan HStack ini:

 HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) } 

Kami membuat warna teks dalam tampilan teks merah. Dan mereka menambahkan Slider dengan nilai default. Rentang default slider adalah dari 0 hingga 1, ini adalah sesuatu yang sangat cocok untuk kita.
Catatan: Kita tahu bahwa bilah geser bergerak dari 0 ke 1, dan label teks adalah '255' untuk kenyamanan pengguna yang digunakan untuk mewakili nilai RGB dalam kisaran dari 0 hingga 255.
Tapi $ ikon apa yang dimiliki variabel? Apakah kita tahu ? dan! ketika bekerja dengan opsional , dan sekarang juga $ ?

Terlepas dari kenyataan bahwa dia sangat kecil dan tidak mencolok, dia sangat penting. RGuess sendiri hanya berupa nilai baca-saja . Tetapi $ rGuess mengikat , kita membutuhkannya untuk memperbarui segi empat warna yang dipilih ketika pengguna memindahkan slider.

Untuk memahami perbedaannya, atur nilai untuk tiga tampilan teks di bawah kotak yang dapat diprediksi:

 HStack { Text("R: \(Int(rGuess * 255.0))") Text("G: \(Int(gGuess * 255.0))") Text("B: \(Int(bGuess * 255.0))") } 

Di sini kita hanya menggunakan nilai, jangan mengubahnya, jadi kita tidak perlu awalan $.

Tunggu pembaruan pratinjau:



Kotak berwarna agak menyusut agar pas dengan slider. Tetapi label teks dari slider terlihat berantakan - terlalu ditekan ke tepinya. Mari tambahkan pengubah lain ke HStack - padding:

 HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) } .padding() 

Sekarang jauh lebih baik!



Buat Command-Click pada slider merah HStack, dan pilih Extract Subview :



Ini berfungsi sama dengan Refactor ▸ Extract to Function , tetapi untuk tampilan SwiftUI.

Pada titik ini, beberapa pesan kesalahan akan muncul, jangan khawatir, sekarang kami akan memperbaikinya.

Beri nama tampilan yang dihasilkan ColorSlider dan tambahkan kode ini di bagian atas, di depan badan tampilan baru kami:

 @Binding var value: Double var textColor: Color 

Sekarang ganti $ rGuess dengan $ value, dan .red dengan textColor :

 Text("0") .foregroundColor(textColor) Slider(value: $value) Text("255") .foregroundColor(textColor) 

Mari kita kembali ke definisi ColorSlider () di VStack dan tambahkan parameter kami:

 ColorSlider(value: $rGuess, textColor: .red) 

Pastikan pratinjau OK dengan slider merah dan ganti tulisan bertopik tulisan dengan slider hijau dan biru. Jangan lupa untuk memasukkan parameter yang benar di sana:

 ColorSlider(value: $gGuess, textColor: .green) ColorSlider(value: $bGuess, textColor: .blue) 

Klik Lanjutkan untuk memperbarui pratinjau:


Catatan: Anda mungkin memperhatikan bahwa Anda sering harus mengklik Lanjutkan . Jika Anda menyukai pintasan, Anda mungkin akan menyukai Option-Command-P .
Dan sekarang sesuatu yang bagus! Di sudut kanan bawah pratinjau, klik tombol pratinjau langsung :



Pratinjau langsung memungkinkan kita untuk berinteraksi dengan pratinjau seolah-olah aplikasi sedang berjalan di simulator!

Coba pindahkan slider:



Hebat! Kami lolos ke tahap akhir. Lagi pula, kami ingin tahu seberapa baik kami memilih warna?

Tampilkan Peringatan


Setelah mengatur slider ke posisi yang diinginkan, pengguna menekan tombol Hit Me , setelah itu Pemberitahuan muncul dengan peringkat.

Pertama, tambahkan metode ke ContentView untuk menghitung skor. Antara variabel @State dan
tubuh tambahkan metode ini:

 func computeScore() -> Int { let rDiff = rGuess - rTarget let gDiff = gGuess - gTarget let bDiff = bGuess - bTarget let diff = sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff) return Int((1.0 - diff) * 100.0 + 0.5) } 

Nilai diff hanyalah jarak antara dua titik dalam ruang tiga dimensi, yaitu nilai kesalahan pengguna. Untuk mendapatkan estimasi, kurangi diff dari 1, dan kemudian kurangi nilainya ke kisaran 0 - 100. Semakin kecil diff, semakin tinggi estimasi.

Kemudian ganti tulisan rintisan Teks ("Tekan tombol" ") dengan kode ini:

 Button(action: { }) { Text("Hit Me!") } 

Tombol memiliki aksi dan label, seperti UIButton. Kami ingin tindakan memicu tampilan Lansiran. Tetapi, jika kita membuat Lansiran di tombol aksi, maka tidak ada yang akan terjadi.

Sebagai gantinya, kami akan menjadikan Alert bagian dari ContentView, dan menambahkan variabel '@State' dari tipe Bool. Lalu kami mengatur variabel ini menjadi true, di tempat kami ingin Lansiran kami muncul di tombol aksi. Nilai akan disetel ulang ke false - untuk menyembunyikan lansiran - saat pengguna menyembunyikan Lansiran.

Tambahkan variabel '@State' ini:

 @State var showAlert = false 

Kemudian tambahkan kode ini sebagai tombol aksi:

 self.showAlert = true 

diri diperlukan untuk kita, karena showAlert ada di dalam penutupan.

Terakhir, tambahkan pengubah lansiran ke tombol, jadi tombol kami benar-benar terlihat seperti ini:

 Button(action: { self.showAlert = true }) { Text("Hit Me!") } .alert(isPresented: $showAlert) { Alert(title: Text("Your Score"), message: Text("\(computeScore())")) } 

Kami melewati $ showAlert sebagai pengikat, karena nilai variabel ini akan berubah saat pengguna menyembunyikan peringatan, dan perubahan ini akan menyebabkan tampilan diperbarui.

SwiftUI memiliki penginisialisasi sederhana untuk tampilan Alert. Ini memiliki tombol OK secara default, jadi kami bahkan tidak perlu mengaturnya sebagai parameter.

Aktifkan pratinjau langsung, pindahkan slider dan tekan tombol Hit me. Voila!



Sekarang dengan pratinjau langsung, Anda tidak lagi membutuhkan simulator iOS. Meskipun dengan itu Anda dapat menguji aplikasi Anda secara horizontal:



Kesimpulan


Di sini Anda dapat mengunduh draft publikasi yang sudah selesai.

Tutorial ini hanya sedikit membahas SwiftUI, tetapi sekarang Anda memiliki kesan fitur Xcode baru untuk membuat UI dan pratinjau, dan cara menggunakan variabel '@State' untuk memperbarui UI Anda.

Untuk kesederhanaan, kami tidak membuat model data untuk RGB. Tetapi sebagian besar aplikasi membuat model data mereka menggunakan struktur atau kelas. Jika Anda ingin melacak perubahan dalam model di SwiftUI, maka itu harus mematuhi protokol ObservableObject dan mengimplementasikan properti willChange , yang memberi tahu Anda tentang perubahan. Lihat contoh Apple dan terutama Data Flow Through SwiftUI .

Untuk membuat SwiftUI lebih mudah dipahami, Anda dapat menambahkan tampilan SwiftUI ke aplikasi yang sudah ada. Lihat contoh cara melakukan ini dengan cepat dan mudah.

Lihat publikasi saya tentang implementasi daftar lipat / turun menggunakan SwiftUI.

Akhirnya, pelajari dokumentasi untuk SwiftUI , dan benar-benar ada banyak hal berguna!

Source: https://habr.com/ru/post/id471918/


All Articles