Untuk menganimasikan item yang memasuki dan meninggalkan koleksi SwiftUI yang disaring, kekalkan identiti setiap item stabil, lampirkan peralihan ke setiap baris, dan animasikan perubahan ke ID yang terlihat. Tutorial ini membina tetingkap Mac kecil dengan label sintetik tempatan dan penapis yang berfungsi.
Tugas pembaca adalah khusus: taip ke dalam medan penapis atau ubah suai-togel kategori, kemudian lihat baris yang sepadan memasuki, baris yang tidak sepadan meninggalkan, dan baris yang tinggal menyingkir ke kedudukan baharu mereka. Apple mendokumentasikan peralihan penyisipan dan penyingkiran sebagai sebahagian daripada perubahan keadaan beranimasi. Pelaksanaan di bawah menggunakan model itu ke atas sebuah koleksi. Animations
Apakah yang membuat penapisan beranimasi dengan betul?
Tiga tanggungjawab berasingan bekerjasama. Penapis menentukan rekod mana yang berada dalam koleksi yang dipaparkan. Identiti memberitahu SwiftUI rekod mana yang berterusan di seluruh kemas kini. Peralihan menggambarkan bagaimana baris muncul atau hilang, manakala animasi menyediakan pemasaan. Menambah peralihan sahaja tidak menubuhkan perubahan keadaan beranimasi. ForEach, Animations
Beri setiap rekod pengenal pasti tersimpan yang tidak berubah apabila menapis. Protokol Identifiable Swift mewakili identiti entiti yang stabil; ForEach menerima elemen yang boleh dikenal pasti atau laluan kunci identiti tersurat. Untuk contoh ini, integer tetap mengenal pasti empat rekod sintetik. Identifiable, ForEach
Elakkan mengenal pasti baris yang disaring oleh kedudukan array semasa mereka. Menyingkirkan rekod yang lebih awal mengubah kedudukan yang kemudian, walaupun rekod itu masih item yang sama. Demikian juga, pengenal pasti dikira yang menjana UUID segar pada setiap akses memusnahkan kekontinuan. Apple menunjukkan kedua-dua masalah dalam penjelasannya tentang identiti SwiftUI. Demystify SwiftUI
Gunakan VStack biasa di dalam ScrollView untuk contoh kecil ini. Apple menasihatkan tumpukan biasa untuk bilangan subview yang kecil; ia merender mereka bersama-sama, manakala tumpukan malas mencipta view apabila diperlukan. Ia menjadikan contoh empat baris lebih mudah untuk diperiksa sebelum memperkenalkan rendering tertunda. VStack, ScrollView
Bangun contoh Mac lengkap
Cipta projek aplikasi macOS di Xcode menggunakan SwiftUI dan Swift, dan tetapkan sasaran deployment ke macOS 13 atau lebih baharu untuk tutorial ini. Gantikan fail penyertaan aplikasi yang dijana dengan program lengkap di bawah. Kekalkan tepat satu deklarasi @main dalam sasaran; dokumentasi App Apple menentukan satu titik penyertaan. App
Program hanya menggunakan tetingkapnya sendiri dan empat label tempatan. Ia mengandungi model, data sampel, kawalan penapis, persembahan baris, pemicu animasi, dan keadaan kosong. Kod telah diperiksa terhadap dokumentasi yang diperoleh tetapi tidak dikompil atau dijalankan di sini kerana persekitaran yang tersedia tidak memiliki rantaian alat Swift.
import SwiftUI
@main
struct FilteredCollectionDemoApp: App {
var body: some Scene {
WindowGroup {
FilteredCollectionView()
}
}
}
private struct DemoItem: Identifiable {
let id: Int
let title: String
let isTile: Bool
}
private struct FilteredCollectionView: View {
@Environment(\.accessibilityReduceMotion)
private var reduceMotion
@State private var query = ""
@State private var tilesOnly = false
private let items: [DemoItem] = [
DemoItem(id: 1, title: "Tile A", isTile: true),
DemoItem(id: 2, title: "Dot A", isTile: false),
DemoItem(id: 3, title: "Tile B", isTile: true),
DemoItem(id: 4, title: "Dot B", isTile: false)
]
private var visibleItems: [DemoItem] {
let needle = query.lowercased()
return items.filter { item in
let matchesText = needle.isEmpty
|| item.title.lowercased().contains(needle)
let matchesCategory = !tilesOnly || item.isTile
return matchesText && matchesCategory
}
}
private var rowTransition: AnyTransition {
.asymmetric(
insertion: AnyTransition.offset(x: 0, y: 8)
.combined(with: .opacity),
removal: .opacity
)
}
var body: some View {
let displayedItems = visibleItems
let displayedIDs = displayedItems.map(\.id)
VStack(alignment: .leading, spacing: 12) {
Text("Label Collection")
.font(.title2)
TextField("Filter labels", text: $query)
.textFieldStyle(.roundedBorder)
Toggle("Tiles only", isOn: $tilesOnly)
Text("\(displayedItems.count) of \(items.count) labels")
.font(.caption)
ScrollView {
VStack(alignment: .leading, spacing: 8) {
ForEach(displayedItems) { item in
HStack {
Text(item.title)
Spacer()
Text(item.isTile ? "Tile" : "Dot")
.foregroundStyle(.secondary)
}
.padding(12)
.frame(maxWidth: .infinity, alignment: .leading)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.blue.opacity(0.10))
)
.transition(rowTransition)
}
if displayedItems.isEmpty {
Text("No matching labels")
.foregroundStyle(.secondary)
.padding(12)
.transition(.opacity)
}
}
.padding(12)
.animation(
reduceMotion
? nil
: .easeInOut(duration: 0.22),
value: displayedIDs
)
}
.frame(height: 300)
}
.padding(20)
.frame(minWidth: 360)
}
}
Titik penyertaan aplikasi mempersembahkan koleksi melalui WindowGroup, bekas adegan Apple untuk tetingkap yang struktur identik. Jika tetingkap lain dibuka dari kumpulan itu, SwiftUI memberi hierarki viewnya keadaan yang bebas, termasuk tetapan penapis contoh ini. WindowGroup
Penapis melaksanakan perbandingan substring tidak kesensitif kes dengan mengurangkan kedua-dua rentetan kepada huruf kecil. Itu adalah pilihan tersengaja untuk label Inggeris sintetik ini. Kedua-dua syarat digabungkan: satu rekod mesti sepadan dengan teks dan, apabila dinyalakan, suai-togel kategori. Array asal kekal utuh, jadi mengosongkan kawalan mengembalikan kesemua empat rekod.
Mengapa memantau ID yang terlihat bukannya kiraan hasil?
Pemodifikasi animasi memantau displayedIDs, array pengenal pasti stabil yang bertertib. animation(_:value:) Apple memaparkan animasi yang dibekalkan apabila nilai yang dipantau, yang boleh dibandingkan, berubah. Di sini nilai itu mewakili keanggotaan dan tertib koleksi yang dipaparkan. animation(_:value:)
Memantau kiraan sahaja akan terlepas kes yang berguna: mengubah pertanyaan dari a ke b menggantikan dua baris dengan dua baris berbeza. Kiraan kekal dua, tetapi ID berubah dari [1, 2] ke [3, 4]. Memantau ID juga mengesan rekod yang disusun semula jika pensortiran ditambah kemudian. Sebaliknya, perubahan pertanyaan yang meninggalkan ID bertertib yang sama terlihat tidak memicu pemodifikasi ini.
Pemodifikasi duduk pada tumpukan dalam yang kekal yang mengandungi kedua-dua baris dan mesej keadaan kosong. Medan teks, suai-togel, dan kiraan hasil duduk di luar skop itu. Susunan ini mengekalkan kawalan penapis berasingan daripada animasi koleksi dan memberi perubahan penyisipan dan penyingkiran nenek moyang beranimasi yang biasa.
Setiap baris lengkap menerima peralihannya selepas penebalan dan penstilan latar belakang. Penyisipan menggabungkan offset menegak pendek dengan ketelusan; penyingkiran menggunakan ketelusan sahaja. Apple mendokumentasikan combined(with:) sebagai memaparkan kedua-dua peralihan dan asymmetric(insertion:removal:) sebagai memilih peralihan berbeza untuk dua hala. AnyTransition, asymmetric(insertion:removal:)
Tempoh ilustratif ialah 0.22 saat. Ia adalah pilihan penalaan, bukan optimum yang didokumentasikan. Menentukan easeInOut(duration:) membuat pemasaan yang dikehendaki tersurat; Apple mentakrifkan parameter durasinya dalam saat. easeInOut(duration:)
Untuk penapis yang dipacu butang, pendekatan lain yang disokong adalah mengubah keadaan penapis di dalam withAnimation. Pilih itu apabila tindakan itu sendiri sepatutnya mentakrifkan kemas kini beranimasi. Pemodifikasi berasaskan nilai adalah mudah di sini kerana kedua-dua kawalan memakan koleksi terbitan yang sama. Apple mendokumentasikan kedua-dua pendekatan. Animations
Semak kelakuan dengan urutan penapis yang dapat dijangka
Gunakan urutan berikut dalam aplikasi yang berjalan. Array ID yang dijangka terbit daripada data sampel dan predikat penapis; mereka bukan keputusan pelaksanaan.
| Tindakan | ID terlihat yang dijangka | Apa untuk diperiksa |
|---|---|---|
| Mula dengan medan kosong dan suai-togel mati | [1, 2, 3, 4] |
Kesemua empat label hadir. |
Masukkan a |
[1, 2] |
Dua label yang tamat dengan B meninggalkan. |
Gantikan a dengan b |
[3, 4] |
Keanggotaan berubah walaupun kiraan kekal dua. |
Kosongkan medan, then nyalakan Tiles only |
[1, 3] |
Baris titik meninggalkan; baris jubin kekal. |
Masukkan z |
[] |
Baris yang tinggal meninggalkan dan Tiada label yang sepadan muncul. |
| Kosongkan medan dan matikan suai-togel | [1, 2, 3, 4] |
Semua rekod kembali dalam tertib asal mereka. |
Contoh ini membaca accessibilityReduceMotion dan membekalkan nil sebagai ganti animasi apabila keutamaan itu dinyalakan. Apple berkata antara muka sepatutnya mengelakkan animasi besar apabila nilai ini benar; menutup animasi koleksi ini adalah pilihan pelaksanaan contoh. Pemodifikasi animasi mendokumentasikan bahawa animasi nil tidak menganimasi view. accessibilityReduceMotion, animation(_:value:)
Diagnosa peralihan yang hilang atau tidak dijangka
Semak lapisan ini mengikut tertib supaya setiap pemerhatian menyingkirkan punca:
- Periksa ID yang disaring. Pastikan predikat menghasilkan rekod yang dijangka sebelum menyesuaikan tetapan animasi.
- Periksa kestabilan dan keunikan identiti. Rekod yang ditahan mesti mengekalkan pengenal pastinya, dan rekod yang berbeza memerlukan pengenal pasti yang berbeza. Buang ID rawak dikira dan ID berasaskan kedudukan daripada koleksi yang berubah.
- Periksa pemicu animasi. Sahkan bahawa nilai yang dipantau berubah untuk kemas kini yang diuji. Kiraan yang sama tidak menyiratkan keanggotaan yang sama.
- Periksa penempatan peralihan. Lampirkan peralihan ke baris lengkap yang dicipta oleh
ForEach, bukan hanya ke teks dalamannya. - Periksa skop beranimasi. Kekalkan tumpukan induk hadir di seluruh perubahan penapis. Elakkan membuat identitinya bergantung pada pertanyaan.
- Periksa keutamaan. Semak tetapan
Kurangkan Gerakandan mana-mana konfigurasi transaksi atau animasi yang mengelilingi sebelum menyimpulkan bahawa peralihan gagal.
Semakan identiti mengikuti keperluan yang didokumentasikan Apple untuk pengenal pasti stabil, unik. Semakan yang tinggal memaparkan pemisahan Apple antara kemas kini keadaan beranimasi dan peralihan penyisipan atau penyingkiran ke struktur view contoh ini. Demystify SwiftUI, Animations
ID rekod stabil tidak mengekalkan keadaan view tempatan baris yang dibuang selama-lamanya. Apple menjelaskan bahawa menyingkirkan view menamatkan hayatnya. Jika baris yang boleh diedit mesti mengekalkan draf selepas ditapis keluar, simpan draf itu di luar baris, dikaitkan dengan ID rekod. Contoh ini mengelakkan isu itu dengan memaparkan label yang tidak berubah. Demystify SwiftUI
Bila sepatutnya anda menggunakan tumpukan malas, AppKit, atau TextKit?
Untuk koleksi yang lebih besar, pertimbangkan LazyVStack, yang mencipta anak hanya apabila diperlukan untuk paparan. Kekalkan penapisan data sebelum menghantarnya ke ForEach; ini menghasilkan satu baris per elemen yang dibekalkan. Dokumentasi ForEach Apple menjelaskan bahawa bekas malas memberi faida apabila setiap elemen menghasilkan bilangan view yang tetap. Semak semula gelincir dan peralihan selepas menukar bekas. LazyVStack, ForEach
Aplikasi AppKit sedia ada boleh menanam antara muka SwiftUI ini menggunakan NSHostingView, didokumentasikan sebagai view AppKit yang mengendungi hierarki SwiftUI. Identiti koleksi, penapisan, dan peralihan boleh kekal dalam view root SwiftUI-nya. Penghosting mengintegrasikan antara muka ke hierarki view aplikasi itu sendiri. NSHostingView
TextKit melayani tugas yang berbeza: mengurus storan teks dan susun atur teks tersuai, termasuk melalui NSTextView AppKit. Tiada apa-apa dalam contoh penapisan label ini memerlukan enjin susun atur teks tersuai. Kenalkan TextKit apabila keperluan penyuntingan atau susun atur teks baris memanggilnya; kekalkan keanggotaan koleksi dan peralihan baris dalam antara muka SwiftUI yang mengelilingi. TextKit
Mula dengan urutan empat rekod dan sahkan identiti dan keanggotaan sebelum menala gerak. Sekali kes penggantian kiraan-sama dan kes hasil-kosong berkelakuan seperti yang dikehendaki, adaptasi reka bentuk baris dan sumber data sambil mengekalkan pengenal pasti stabil dan pemicu animasi terikat kepada koleksi yang dipaparkan.
Sumber
- Animations — Apple
- ForEach — Apple
- Identifiable — Apple
- Demystify SwiftUI — Apple
- VStack — Apple
- ScrollView — Apple
- App — Apple
- WindowGroup — Apple
- animation(_:value:) — Apple
- AnyTransition — Apple
- asymmetric(insertion:removal:) — Apple
- easeInOut(duration:) — Apple
- accessibilityReduceMotion — Apple
- LazyVStack — Apple
- NSHostingView — Apple
- TextKit — Apple