matchedGeometryEffect не всегда анимирует изменение позиции

Моя цель - смоделировать пешку, которая прыгает с поля на поле.

struct MyView: View {
    @State var current = 0;
    @State var colors : [Color] = [.blue, .gray, .red]
    @Namespace var animationNamespace : Namespace.ID
    var body : some View {
        HStack(spacing: 12){
            ForEach(colors.indices) { i in
                ZStack{
                    RoundedRectangle(cornerRadius: 8)
                        .fill(colors[i])
                        .frame(width: 50, height: 50)
                    Image(systemName: "person.crop.square")
                        .resizable()
                        .scaledToFit()
                        .cornerRadius(8)
                        .opacity(current == i ? 1.0 : 0.0)
                        .frame(width: 50, height: 50)
                        .matchedGeometryEffect(id: current == i ? -1 : i , in: animationNamespace)
                        .onTapGesture {
                            withAnimation(.easeInOut){
                                current = (current + 1) % colors.capacity
                            }
                        }
                }
            }
        }
    }
}

анимация

щелкните 1 - из позиции 0 в позицию 1: OK
щелкните 2 - из позиции 1 в позицию 2: OK
щелкните 3 - из позиции 3 в позицию 0: KO
щелкните 4 - из позиции 0 в положение 1: ОК
щелкните 5 - из положения 1 в положение 2: ОК
щелкните 6 - из положения 3 в положение 0: KO
щелкните 7 - из положения 0 в положение 1: ОК
...

https://developer.apple.com/documentation/swiftui/view/matchedgeometryeffect(id:in:properties:anchor:issource:)

Если при вставке представления в ту же транзакцию, что и другое представление с тем же ключом, удаляется, система будет интерполировать их прямоугольники фреймов в пространстве окна, чтобы казалось, что существует единственный вид, перемещающийся из своего старого положения в новое положение.

Я что-то упускаю?
Есть ли ограничения?

Xcode версии 12.1 (12A7403) iOS 14.0


person fdelsert    schedule 04.11.2020    source источник
comment
что ты хочешь делать то не можешь? Я проверил ваш код, нажимаю на изображение, он переходит к следующему прямоугольнику с анимацией.   -  person user    schedule 04.11.2020


Ответы (1)


Вот небольшая модификация, которая заставляет его работать. Вместо того, чтобы добавлять изображение ко всем 3 квадратам с разной степенью непрозрачности, нарисуйте изображение только на том, который в настоящее время содержит пешку. Сделайте это с помощью if current == i { }. Если вы сделаете это, вы можете просто использовать 1 как matchedGeometryEffect id.

struct ContentView: View {
    @State var current = 0;
    @State var colors : [Color] = [.blue, .gray, .red]
    @Namespace var animationNamespace : Namespace.ID
    var body : some View {
        HStack(spacing: 12){
            ForEach(colors.indices) { i in
                ZStack{
                    RoundedRectangle(cornerRadius: 8)
                        .fill(colors[i])
                        .frame(width: 50, height: 50)
                    if current == i {
                        Image(systemName: "person.crop.square")
                            .resizable()
                            .scaledToFit()
                            .cornerRadius(8)
                            .frame(width: 50, height: 50)
                            .matchedGeometryEffect(id: 1 , in: animationNamespace)
                            .onTapGesture {
                                withAnimation(.easeInOut){
                                    current = (current + 1) % colors.capacity
                                }
                            }
                    }
                }
            }
        }
    }
}

Вот оно в симуляторе:

демонстрация симулятора

person vacawama    schedule 05.11.2020