SwiftUI: Membuat Bagian yang Dapat Diperluas / Dilipat dalam Tampilan Daftar



Tugas umum dalam pengembangan iOS adalah bagian yang dapat diperluas / lipat dalam UITableView. Hari ini kami menyadari tugas ini menggunakan SwiftUI. Sebagai twist kecil, tambahkan segitiga animasi di bagian header dan buat sel-selnya juga mengembang.

Pengembangan berlangsung pada Xcode 11.2 untuk macOS Catalina 10.15.1

Mulai proyek


Luncurkan Xcode, File - Proyek Baru - Aplikasi Tampilan Tunggal. Di kotak dialog, tentukan bahasa pengembangan Swift, kami akan membentuk UI menggunakan SwiftUI.



Data


Sebagai data demonstrasi, kami akan menggunakan beberapa ekspresi bersayap lucu dalam bahasa Latin dengan terjemahannya ke dalam bahasa Rusia.

Tambahkan file Swift baru ke proyek, sebut saja Data.swift dan tulis yang berikut di sini:

struct QuoteDataModel : Identifiable { var id: String { return latin } var latin : String var russian : String var expanded = false } struct SectionDataModel : Identifiable { var id: Character { return letter } var letter : Character var quotes : [QuoteDataModel] var expanded = false } 

QuoteDataModel adalah model ekspresi tunggal, di masa depan itu akan menjadi konten setiap sel individu. Di dalamnya kita menyimpan teks asli ekspresi, terjemahannya dan tanda sel "diperluas" (secara default itu "diperkecil")

SectionDataModel adalah model dari masing-masing bagian yang terpisah, di sini kita menyimpan "surat" bagian tersebut, sebuah array kutipan yang dimulai dengan surat ini dan juga tanda bagian "diperluas" (secara default juga "runtuh")

Di masa mendatang, kami akan menampilkan semua ini dalam tampilan Daftar, yang mengharuskan data untuk itu mematuhi protokol yang Dapat Diidentifikasi . Untuk melakukan ini, kami mendefinisikan properti id , yang harus unik untuk setiap item dalam Daftar.

Selanjutnya, dalam file Data.swift yang sama, kami membentuk data kami:

 var latinities : [SectionDataModel] = [ SectionDataModel(letter: "C", quotes: [ QuoteDataModel(latin: "Calvitium non est vitium, sed prudentiae indicium.", russian: "  ,   ."), QuoteDataModel(latin: "Conjecturalem artem esse medicinam.", russian: "   ."), QuoteDataModel(latin: "Crede firmiter et pecca fortiter!", russian: "    !")]), SectionDataModel(letter: "H", quotes: [ QuoteDataModel(latin: "Homo sine religione sicut equus sine freno.", russian: "      ."), QuoteDataModel(latin: "Habet et musca splenem.", russian: "   .")]), SectionDataModel(letter: "M", quotes: [ QuoteDataModel(latin: "Malum est mulier, sed necessarium malum.", russian: "   ,   ."), QuoteDataModel(latin: "Mulierem ornat silentium.", russian: "  .")])] 

Mari kita berurusan dengan antarmuka


Sekarang kita akan menentukan bagaimana judul bagian dan setiap sel akan terlihat.

Pilih File - Baru - File - Tampilan SwiftUI dari menu. Beri nama file HeaderView.swift dan ganti isinya dengan yang berikut:

 import SwiftUI struct HeaderView : View { var section : SectionDataModel var body: some View { HStack() { Spacer() Text(String(section.letter)) .font(.largeTitle) .foregroundColor(Color.black) Spacer() } .background(Color.yellow) } } struct HeaderView_Previews: PreviewProvider { static var previews: some View { HeaderView(section: latinities[0]) } } 



Sekarang lagi File - Baru - File - Tampilan SwiftUI. Beri nama file QuoteView.swift dan ganti isinya dengan yang berikut:

 import SwiftUI struct QuoteView: View { var quote : QuoteDataModel var body: some View { VStack(alignment: .leading, spacing: 5) { Text(quote.latin) .font(.title) if quote.expanded { Group() { Divider() Text(quote.russian).font(.body) }.transition(.move(edge: .top)).animation(.default) } } } } struct QuoteView_Previews: PreviewProvider { static var previews: some View { QuoteView(quote: latinities[0].quotes[0]) } } 



Sekarang buka file ContentView.swift dan ubah struktur ContentView sebagai berikut:

 struct ContentView: View { var body: some View { List { ForEach(latinities) { section in Section(header: HeaderView(section: section), footer: EmptyView()) { if section.expanded { ForEach(section.quotes) { quote in QuoteView(quote: quote) } } } } } .listStyle(GroupedListStyle()) } } 

Selamat, Anda baru saja mengisi Daftar dengan data terbaru! Untuk setiap elemen array latinities, kami membuat bagian dengan header berdasarkan HeaderView dan dengan footer kosong. Jika bagian "diperluas", maka untuk setiap ekspresi dalam array kutipan kami membentuk sel berdasarkan pada QuoteView . Dalam data kami, semua bagian dan semua sel "diciutkan", jadi jika Anda membuat Canvas terlihat, Anda hanya akan melihat header bagian:



Seperti yang Anda pahami, sekarang aplikasi benar-benar "mati" dan masih jauh dari tujuan akhir kami. Tapi segera kami akan memperbaikinya!

Ubah sedikit bagian tajuk


Kembali ke file HeaderView.swift. Di dalam struktur HeaderView, segera setelah tubuh, tambahkan ini:

 struct Triangle : Shape { func path(in rect: CGRect) -> Path { var path = Path() path.move(to: CGPoint(x: 0, y: 0)) path.addLine(to: CGPoint(x: 0, y: rect.height - 1)) path.addLine(to: CGPoint(x: sqrt(3)*(rect.height)/2, y: rect.height/2)) path.closeSubpath() return path } } 

Struktur ini mengembalikan segitiga sama sisi. Sekarang tambahkan segitiga kami ke header. Di dalam HStack , sebelum Spacer pertama tambahkan ini:

 Triangle() .fill(Color.black) .overlay( Triangle() .stroke(Color.red, lineWidth: 5) ) .frame(width : 50, height : 50) .padding() .rotationEffect(.degrees(section.expanded ? 90 : 0), anchor: .init(x: 0.5, y: 0.5)).animation(.default)) 



Ubah data


Kembali ke data kami. Buka Data.swift dan Bungkus array latinities kami di kelas UserData baru, seperti ini:

 class UserData : ObservableObject { @Published var latinities : [SectionDataModel] = [ SectionDataModel(letter: "C", quotes: [ QuoteDataModel(latin: "Calvitium non est vitium, sed prudentiae indicium.", russian: "  ,   ."), QuoteDataModel(latin: "Conjecturalem artem esse medicinam.", russian: "   ."), QuoteDataModel(latin: "Crede firmiter et pecca fortiter!", russian: "    !")]), SectionDataModel(letter: "H", quotes: [ QuoteDataModel(latin: "Homo sine religione sicut equus sine freno.", russian: "      ."), QuoteDataModel(latin: "Habet et musca splenem.", russian: "   .")]), SectionDataModel(letter: "M", quotes: [ QuoteDataModel(latin: "Malum est mulier, sed necessarium malum.", russian: "   ,   ."), QuoteDataModel(latin: "Mulierem ornat silentium.", russian: "  .")])] } 

Ingatlah untuk juga menandai latinities sebagai @Diterbitkan .

Apa yang telah kita lakukan
ObservableObject adalah objek khusus untuk data kami yang dapat "terikat" ke beberapa Tampilan. SwiftUI "memantau" semua perubahan yang dapat memengaruhi Tampilan dan, setelah data berubah, mengubah Tampilan.

Setelah "membungkus" bahasa latin, kami memiliki banyak kesalahan, kami akan memperbaikinya. Buka HeaderView.swift dan koreksi struktur HeaderView_Preview sebagai berikut:

 struct HeaderView_Previews: PreviewProvider { static var previews: some View { HeaderView(section: UserData().latinities[0]) } } 

Sekarang buat perubahan serupa dengan QuoteView.swift :

 struct QuoteView_Previews: PreviewProvider { static var previews: some View { QuoteView(quote: UserData().latinities[0].quotes[0]) } } 

Buka file ContentView.swift dan tambahkan ini sebelum deklarasi body

 @ObservedObject var userData = UserData() 

Bangkit kembali lanskap


Kembali ke file ContentView.swift. Di dalam struktur ContenView, segera setelah definisi userData, tambahkan dua fungsi:

 func sectionIndex(section : SectionDataModel) -> Int { userData.latinities.firstIndex(where: {$0.letter == section.letter})! } func quoteIndex(section : Int, quote : QuoteDataModel) -> Int { return userData.latinities[section].quotes.firstIndex(where: {$0.latin == quote.latin})! } 

Tambahkan pengubah onTapGesture ke header bagian dan sel yang kita buat . Tampilan akhir konten tubuh :

 var body: some View { List { ForEach(userData.latinities) { section in Section(header: HeaderView(section: section) .onTapGesture { self.userData.latinities[self.sectionIndex(section: section)].expanded.toggle() }, footer: EmptyView()) { if section.expanded { ForEach(section.quotes) { quote in QuoteView(quote: quote) .onTapGesture { let sectionIndex = self.sectionIndex(section: section) let quoteIndex = self.quoteIndex(section: sectionIndex, quote: quote) self.userData.latinities[sectionIndex].quotes[quoteIndex].expanded.toggle() } } } } } } .listStyle(GroupedListStyle()) } 

Fungsi sectionIndex dan quoteUndex mengembalikan indeks bagian dan ekspresi yang diberikan kepada mereka. Setelah menerima indeks ini, kami mengubah nilai properti yang diperluas dalam susunan latinity kami , yang mengarah pada pelipatan / pembukaan bagian atau ekspresi.



Kesimpulan


Proyek yang sudah selesai dapat diunduh di sini .

Beberapa tautan bermanfaat:



Saya harap publikasi ini bermanfaat bagi Anda!

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


All Articles