Проблема с использованием анимации matchedGeometryEffect в ScrollView
Анимация View
s между LazyVGrid
и HStack
с другим видом между ними (в данном случае Button
), с помощью matchedGeometryEffect
, работает отлично:
Обратите внимание, как анимированные представления перемещаются над кнопкой "Готово".
Однако, когда представления содержатся в ScrollView
, анимированные представления теперь перемещаются за промежуточным представлением:
Я пробовал установить zIndex
из ScrollView
s до> 0 (или более), но это, похоже, ничего не меняет.
Есть мысли, как это исправить?
Человек
struct Person: Identifiable, Equatable {
var id: String { name }
let name: String
var image: Image { Image(name) }
static var all: [Person] {
["Joe", "Kamala", "Donald", "Mike"].map(Person.init)
}
}
ContentView
struct ContentView: View {
@State var people: [Person]
@State private var selectedPeople: [Person] = []
@Namespace var namespace
var body: some View {
VStack(alignment: .leading, spacing: 0) {
ScrollView(.horizontal) {
SelectedPeopleView(people: $selectedPeople, namespace: namespace) { person in
withAnimation(.easeOut(duration: 1)) {
selectPerson(person)
}
}
.background(Color.orange)
}
doneButton()
ScrollView(.vertical) {
PeopleView(people: people, namespace: namespace) { person in
withAnimation(.easeOut(duration: 1)) {
deselectPerson(person)
}
}
}
Spacer()
}
.padding()
}
func selectPerson(_ person: Person) {
_ = selectedPeople.firstIndex(of: person).map { selectedPeople.remove(at: $0)}
people.append(person)
}
func deselectPerson(_ person: Person) {
_ = people.firstIndex(of: person).map { people.remove(at: $0)}
selectedPeople.append(person)
}
func doneButton() -> some View {
Button("Done") {
}
.font(.title2)
.accentColor(.white)
.frame(maxWidth: .infinity)
.padding()
.background(Color.gray)
}
}
SelectedPeopleView
struct SelectedPeopleView: View {
@Binding var people: [Person]
let namespace: Namespace.ID
let didSelect: (Person) -> Void
var body: some View {
HStack {
ForEach(people) { person in
Button(action: { didSelect(person) } ) {
Text(person.name)
.padding(10)
.background(Color.yellow.cornerRadius(6))
.foregroundColor(.black)
.matchedGeometryEffect(id: person.id, in: namespace)
}
}
}
.frame(height: 80)
}
}
PeopleView
struct PeopleView: View {
let people: [Person]
let namespace: Namespace.ID
let didSelect: (Person) -> Void
let columns: [GridItem] = Array(repeating: .init(.flexible(minimum: .leastNormalMagnitude, maximum: .greatestFiniteMagnitude)), count: 2)
var body: some View {
LazyVGrid(columns: columns) {
ForEach(people) { person in
Button(action: { didSelect(person) }) {
person.image
.resizable()
.scaledToFill()
.layoutPriority(-1)
.clipped()
.aspectRatio(1, contentMode: .fit)
.cornerRadius(6)
}
.zIndex(zIndex(for: person))
.matchedGeometryEffect(id: person.id, in: namespace)
}
}
}
func zIndex(for person: Person) -> Double {
Double(people.firstIndex(of: person)!)
}
}
1 ответ
Это похоже на ошибку в SwiftUI, потому что даже если вы поставите Color.clear
любой высоты вместо и вместо вашего doneButton
(или даже .padding
некоторой высоты для дна ScrollView
) эффект будет такой же.
Как видно из иерархии представлений, между двумя ScrollView
и рендеринг изображений выполняется в одном фоновом режиме