SwiftUI matchedGeometry + LazyVStack = crash
Oct 18 2020
Saya memerlukan waktu berjam-jam untuk membuat contoh ini, dan saya tidak yakin apakah saya melakukan sesuatu yang salah atau ada bug yang merusak aplikasi saat menggunakan matchedGeometry+ LazyVStack.
Dalam video di bawah, aplikasi macet ketika saya mengklik persegi panjang ketiga (yang tidak terlihat saat aplikasi dimulai). Crash hilang jika saya ganti LazyVStackdengan VStack, tapi jelas saya ingin malas memuat barang saya.
Versi Xcode: Versi 12.0.1 (12A7300)
struct ContentView: View {
@Namespace var namespace
@State var selected: Int?
var body: some View {
ZStack {
VStack {
Text("Cool rectangles")
if selected == nil {
ScrollView(.vertical, showsIndicators: false) {
BoxList(namespace: namespace, selected: $selected)
}
}
}
if let id = selected {
Rectangle()
.foregroundColor(.red)
.matchedGeometryEffect(id: id, in: namespace)
.onTapGesture {
withAnimation{
selected = nil
}
}
}
}
}
}
struct BoxList: View {
let namespace: Namespace.ID
@Binding var selected: Int?
var body: some View {
LazyVStack {
ForEach(0..<10){ item in
Rectangle()
.matchedGeometryEffect(id: item, in: namespace)
.frame(width: 200, height: 200)
.onTapGesture {
withAnimation {
selected = item
}
}
}
}
}
}
Jawaban
Asperi Oct 18 2020 at 14:06
Masalahnya adalah Anda menghancurkan ScrollViewtata letak yang cocok dan melanggar.
Berikut adalah varian tetap. Diuji dengan Xcode 12 / iOS 14
struct ContentView: View {
@Namespace var namespace
@State var selected: Int?
var body: some View {
ZStack {
VStack {
Text("Cool rectangles")
ScrollView(.vertical, showsIndicators: false) {
BoxList(namespace: namespace, selected: $selected)
}.opacity(selected == nil ? 1 : 0)
} // << or place here opacity modifier here
if let id = selected {
Rectangle()
.foregroundColor(.red)
.matchedGeometryEffect(id: id, in: namespace)
.onTapGesture {
withAnimation{
selected = nil
}
}
}
}
}
}
struct BoxList: View {
let namespace: Namespace.ID
@Binding var selected: Int?
var body: some View {
LazyVStack {
ForEach(0..<10){ item in
if item == selected {
Color.clear // placeholder to avoid duplicate match id run-time warning
.frame(width: 200, height: 200)
} else {
Rectangle()
.matchedGeometryEffect(id: item, in: namespace)
.frame(width: 200, height: 200)
.onTapGesture {
withAnimation {
selected = item
}
}
}
}
}
}
}
Selalu Menjadi Ancaman: Mengapa Orang Berkulit Coklat dan Hitam Tidak Bisa Nyaman di Amerika Serikat
Taylor Sheridan Baru Menambahkan 1 Bintang 'Yellowstone' Favoritnya ke Pemeran 'Lawmen: Bass Reeves'