Cara Menerapkan Kartu Gesekan Tinder di SwiftUI

Pada bulan Juni, kami mendengar tentang SwiftUI untuk pertama kalinya - cara yang sama sekali baru untuk membuat dan bekerja dengan elemen UI di iOS dan aplikasi macOS (juga iPadOS). Rasanya seperti Natal di musim panas. Ini baru, deklaratif, seksi! Dan sekarang, hanya beberapa minggu setelah iOS 13 dirilis, kita dapat mulai menggunakan SwiftUI di semua proyek kami. Mari kita belajar cara menggunakan alat luar biasa yang diberikan Apple kepada kami, untuk membuat Kartu Gesek Tinder-esque klasik.

Pada artikel ini, saya ingin menunjukkan kepada Anda cara mencapai tampilan dan perilaku kartu seperti Tinder (gesek ke tindakan), hanya dengan beberapa baris kode.

Untuk mencapai ini, kita perlu melakukan hal-hal berikut, agar:

  • Buat UserView
  • Buat tampilan navigasi
  • Buat BottomBarView
  • Buat swipeview
  • Satukan semua ini di dalam ContentView

Jadi mari kita mulai.

tinder swiftui

Userview


UserView dibangun dari dua subview, satu adalah NameView yang berisi nama pengguna, usia, dan hobi, dan tampilan kedua hanyalah tampilan avatar yang menampilkan gambar profil pengguna.

struct NameView: View { let name: String let age: Int let hobby: String var body: some View { VStack(alignment: .leading) { Spacer() Text("\(name), \(age)") .font(.title) .fontWeight(.semibold) .foregroundColor(.white) Text(hobby) .font(.system(size: 16)) .fontWeight(.regular) .foregroundColor(.white) } .padding() } } 

Pertama, kita perlu mendefinisikan NameView , ini akan mewakili nama pengguna, usia, dan hobi. NameView sesuai dengan protokol View , yang digunakan untuk mendefinisikan tampilan kustom di SwiftUI. Protokol tampilan hanya memiliki satu persyaratan dan itu mendefinisikan properti tubuh yang harus mengembalikan struktur tampilan dan menjelaskan perilakunya. Anda dapat memeriksa lebih lanjut tentang protokol Tampilan dalam dokumentasi resmi Apple .

Mari kita jabarkan objek yang kita gunakan untuk mendefinisikan Tampilan ini:

  • VStack yang bertindak seperti wadah untuk semua objek yang meluruskannya secara vertikal
  • Spacer yang memberi tahu SwiftUI bahwa tampilan ini harus disejajarkan di bagian bawah
  • Teks yang mewakili label dengan nama & usia, dengan properti berikut:
  • Objek Teks Kedua yang memiliki properti serupa dan menampilkan hobi pengguna

Harap perhatikan bahwa kami tidak menggunakan pernyataan pengembalian di sini, di dalam properti body, tetapi sebaliknya kami mengembalikan VStack. SwiftUI menggunakan proposal omit-return yang diterapkan di Swift 5.0. Anda dapat memeriksa lebih lanjut tentang ini di sini .

Avatarview


Inilah bagaimana AvatarView didefinisikan:

 struct AvatarView: View { let image: UIImage var body: some View { Image(uiImage: image) .resizable() .overlay( Rectangle() .fill(LinearGradient(gradient: Gradient(colors: [.clear, .black]), startPoint: .center, endPoint: .bottom)) .clipped() ) .cornerRadius(12.0) } } 

Mari selami komponen yang membuat unit avatar ini:

  • Gambar - yang menampilkan gambar pengguna
  • resizable - metode ini menentukan bahwa gambar harus diubah ukurannya agar sesuai dengan tempat tertanamnya
  • overlay (Rectangle) - di sini kita mendefinisikan gradien yang akan menjadi latar belakang yang bagus untuk NameView, gradien ini dimulai di pusat gambar dan selesai di bagian bawah, memiliki warna yang jelas di awal dan hitam di bagian bawah
  • cornerRadius - gambar akan memiliki radius terpojok

Dan sekarang mari kita tanamkan dua tampilan ini ke dalam tampilan wadah tunggal, bernama UserView .

Userview


 struct UserView: View { let userModel: UserModel var body: some View { ZStack(alignment: .leading) { AvatarView(image: userModel.image) NameView(name: userModel.name, age: userModel.age, hobby: userModel.hobby) } .shadow(radius: 12.0) .cornerRadius(12.0) } } 

Inilah yang terjadi:

  • ZStack - Ini adalah tampilan tumpukan yang akan menyelaraskan anak-anaknya pada sumbu yang sama. Anda dapat membaca lebih lanjut tentang ZStack di sini
  • AvatarView - Tampilan avatar kami yang berisi gambar yang disediakan melalui UserModel
  • NameView - Tampilan nama kami menampilkan nama berdasarkan model pengguna

Setelah semua langkah ini, jalankan aplikasi. Anda akan mendapatkan layar berikut:

avatar tinder

Mari kita tambahkan metode pembantu kecil sekarang. Sebelum saya menunjukkan kepada Anda bagaimana Navigasi didefinisikan, mari kita buat metode pembantu, yang terlihat seperti ini:

 struct ViewFactory { static func button(_ name: String, renderingMode: Image.TemplateRenderingMode = .original) -> some View { Button(action: {}) { Image(name) .renderingMode(renderingMode) } } } 

Di sini, kami telah menetapkan metode pabrik tombol, yang membuat tombol baru dari gambar yang diberikan dan mode rendering. Tidak ada pengendali tindakan, karena itu berada di luar ruang lingkup untuk artikel ini.

Tampilan Navigasi


 struct NavigationView: View { var body: some View { HStack { ViewFactory.button("profile_icon") Spacer() ViewFactory.button("fire_icon") .scaleEffect(2) Spacer() ViewFactory.button("chat_icon") } } } 

SwiftUI akan secara otomatis membuat Spacer dengan lebar yang sama, dan itu akan memberi kita tampilan navigasi berikut:

tampilan navigasi

Bottombarview


 struct BottomBarView: View { var body: some View { HStack { ViewFactory.button("back_icon", renderingMode: .template) .foregroundColor(.orange) .background( GeometryReader { geometry in Circle() .offset(x: 2.5) .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 1.5, height: geometry.size.height * 1.5) } ) Spacer() ... } 

Dalam cuplikan kode di atas, kami telah menentukan tombol pertama dari tampilan bilah kami. Inilah yang terjadi:

  • ViewFactory.button - di sini kita menggunakan metode pembantu kami untuk menentukan tombol dengan gambar dengan renderingMode .template yang memungkinkan Anda untuk menempatkan warna khusus untuk gambar ini
  • .foregroundColor - mendefinisikan warna tampilan kami
  • .background - metode ini mendefinisikan tampilan latar belakang objek yang diberikan
  • GeometryReader - tampilan wadah yang mendefinisikan kontennya sebagai fungsi dari ukurannya sendiri dan mengoordinasikan ruang. Kami menggunakan ini untuk mendapatkan ukuran tombol saat ini dan menentukan lingkaran latar belakang dengan bingkai yang diberikan. Pelajari lebih lanjut tentang Pembaca Geometri di sini .
  • Lingkaran - mendefinisikan bentuk latar belakang
  • .offset - lingkaran offset sumbu x
  • .foregroundColor - warna lingkaran warna
  • .shadow - lingkaran shadow
  • .frame - mendefinisikan bingkai lingkaran menggunakan ukuran pembaca geometri (di sini kita mendefinisikan lingkaran latar belakang, 1,5x lebih besar dari tombol saat ini)

Sekarang mari kita terapkan sisa tombol:

 struct BottomBarView: View { var body: some View { HStack { ViewFactory.button("back_icon", renderingMode: .template) .foregroundColor(.orange) .background( GeometryReader { geometry in Circle() .offset(x: 2.5) .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 1.5, height: geometry.size.height * 1.5) } ) Spacer() ViewFactory.button("close_icon", renderingMode: .template) .foregroundColor(.red) .background( GeometryReader { geometry in Circle().foregroundColor(.white) .frame(width: geometry.size.width * 2, height: geometry.size.height * 2) .shadow(color: .gray, radius: 12) } ) Spacer() ViewFactory.button("approve_icon", renderingMode: .template) .foregroundColor(.green) .background( GeometryReader { geometry in Circle() .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 2, height: geometry.size.height * 2) } ) Spacer() ViewFactory.button("boost_icon", renderingMode: .template) .foregroundColor(.purple) .background( GeometryReader { geometry in Circle() .foregroundColor(.white) .shadow(color: .gray, radius: 12) .frame(width: geometry.size.width * 1.5, height: geometry.size.height * 1.5) } ) } .padding([.leading, .trailing]) } } 

Dan sebagai hasilnya kita sekarang memiliki pemandangan yang indah ini:

tampilan kencan tab bar

Swipeview


Bagian ini untuk SwiftUI lebih lanjut. Di sinilah segalanya menjadi menarik. Kami ingin menerapkan gerakan gesek pada tampilan tindakan. Perilaku ini adalah kasus penggunaan yang bagus untuk PageViewController, tetapi pengontrol tampilan ini akan segera menjadi sejarah, jadi ini adalah tempat kami dapat menunjukkan kekuatan nyata SwiftUI.

Jadi mari kita lihat bagaimana SwipeView diimplementasikan:

 struct SwipeView: View { @State private var offset: CGFloat = 0 @State private var index = 0 let users = [...] let spacing: CGFloat = 10 var body: some View { GeometryReader { geometry in return ScrollView(.horizontal, showsIndicators: true) { HStack(spacing: self.spacing) { ForEach(self.users) { user in UserView(userModel: user) .frame(width: geometry.size.width) } } } .content.offset(x: self.offset) .frame(width: geometry.size.width, alignment: .leading) .gesture( DragGesture() .onChanged({ value in self.offset = value.translation.width - geometry.size.width * CGFloat(self.index) }) .onEnded({ value in if -value.predictedEndTranslation.width > geometry.size.width / 2, self.index < self.users.count - 1 { self.index += 1 } if value.predictedEndTranslation.width > geometry.size.width / 2, self.index > 0 { self.index -= 1 } withAnimation { self.offset = -(geometry.size.width + self.spacing) * CGFloat(self.index) } }) ) } } } 

Di sini kami telah menggunakan beberapa konsep SwiftUI baru yang menarik:

  • @ Status - Nilai persisten dari jenis yang diberikan, di mana tampilan membaca dan memantau nilai, yang berarti bahwa setiap kali properti ini akan berubah, tampilan akan dimuat ulang untuk menyesuaikan dengan pembaruan status yang diberikan. Anda dapat memeriksa lebih lanjut tentang Negara di sini .
  • DragGesture - objek ini akan digunakan untuk mengenali setiap gesekan yang dilakukan pengguna di layar. Anda dapat membaca lebih lanjut tentang ini di sini: developer.apple.com/documentation/swiftui/draggesture
  • @ Offset var pribadi negara: CGFloat = 0 - properti ini akan digunakan untuk menentukan offset tampilan gulir saat ini ketika pengguna menggeser layar
  • @ State private var index = 0 - properti ini menentukan tampilan pengguna mana yang sedang ditampilkan di layar
  • ScrollView - tampilan gulir horizontal tanpa indikator, yang akan menjadi wadah untuk tampilan pengguna kami
  • HStack - tampilan tumpukan horizontal yang berisi semua tampilan pengguna
  • content.offset (self.offset) - ini menciptakan koneksi antara keadaan offset dan offset tampilan konten gulir. Ini berarti bahwa setiap kali properti offset akan berubah, offset tampilan gulir juga akan diperbarui

Kami menghitung lebih dari pengguna yang ada dengan membuat UserView untuk setiap elemen:

  • .frame - di sini kita mendefinisikan bingkai tampilan gulir yang harus sesuai dengan lebar layar, dan harus disejajarkan dengan benar ke wadahnya.
  • .ureure - di sini kita menambahkan objek DragGesture kita

DragGesture sedikit rumit, tetapi bagaimanapun, ia menambahkan semua logika pagination hanya dalam beberapa baris kode. Mari kita hancurkan DragGesture :
  • onChanged () - blok ini dipanggil setiap kali pengguna mulai dan berada di saat gerakan seret, di sini kami menghitung offset tampilan pengguna saat ini yang mengikuti jari pengguna
  • onEnded () - di sini kita diberitahu ketika gerakan isyarat berakhir, di sini kita perlu menghitung apakah pengguna ingin menggesek tampilan ini (kiri atau kanan), atau mungkin gerakan ini ditandai, dan pengguna ingin tetap berada di layar ini
  • withAnimation - penutupan ini dipanggil dengan animasi, dan memungkinkan untuk mengganti offset dengan smothly

Contentview


 struct ContentView: View { var body: some View { VStack { NavigationView() .padding(.bottom) SwipeView() .padding(.bottom) BottomBarView() } .padding() } } 

Tampilan konten kami sangat sederhana pada saat ini - konten ini membentuk semua tampilan yang kami buat sebelumnya, di dalam tumpukan vertikal ( VStack ). Untuk NavigationView dan SwipeView kami telah menambahkan beberapa padding default di bagian bawah, dan seluruh VStack memiliki paddings ditambahkan ke semua tepi.

Itu dia. Selesai Seperti inilah tampilan aplikasi kami sekarang:

tinder swiftui

Pikiran terakhir


Seperti yang dapat kita lihat SwiftUI adalah alat yang sangat kuat, SwiftUI memberi kita cara mudah untuk mendefinisikan dan memanipulasi UI dalam kode pendek deklaratif. Bereaksi pengembang asli akan mengenali paradigma deklaratif ini segera.

Tapi ingat: SwiftUI masih dalam pengembangan dan bisa sangat tidak stabil untuk saat ini. Jika Anda ingin memeriksa semua basis kode untuk proyek ini, Anda dapat menemukannya di Github .

Jika Anda memiliki pemikiran atau pertanyaan tentang SwiftUI, silakan bagikan dalam komentar. Juga, jika Anda menikmati artikel ini, silakan bagikan dengan komunitas Anda untuk membantu kami menyebarkan berita!

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


All Articles