Как я могу иметь анимацию преобразования в SwiftUI?

#swiftui

#swiftui

Вопрос:

Здесь я получил 2 фигуры, один прямоугольник и один круг, которые при нажатии кнопки только одна из них стала видна пользователю, я попытался использовать @Namespace для этого преобразования, но ничего не получилось!

МОЯ цель: иметь красивую и плавную анимацию преобразования из одной формы в другую.

введите описание изображения здесь

 struct ContentView: View {

@State var action: Bool = false
@Namespace var sameShape

var body: some View {
    
    
    ZStack
    {
        
        Group
        {
            if action
            {
                Circle()
                    .fill(Color.blue).frame(width: 150, height: 150, alignment: .center)
                    .matchedGeometryEffect(id: "Dakota148Zero", in: sameShape)
            }
            else
            {
                Rectangle()
                    .fill(Color.red).frame(width: 150, height: 150, alignment: .center)
                    .matchedGeometryEffect(id: "Dakota148Zero", in: sameShape)
            }
        }
        .animation(.easeInOut)
        
        
        
        VStack
        {
            
            Spacer()
            
            Button("transform") { action.toggle() }.font(Font.largeTitle).padding()
            
        }
        
    }
    
    
    }
}
  

Комментарии:

1. Проверьте это, это действительно круто — swiftui-lab.com/swiftui-animations-part1

Ответ №1:

Вот способ сделать это, представив круг и квадрат как a RoundedRectangle с разными cornerRadius значениями:

 struct ContentView: View {
    
    @State var action = false
    
    var body: some View {
        
        ZStack
        {
            RoundedRectangle(cornerRadius: action ? 0 : 75)
                .fill(action ? Color.red : .blue)
                .frame(width: 150, height: 150, alignment: .center)
                .animation(.easeInOut)
            
            VStack
            {
                Spacer()
                
                Button("transform") {
                    action.toggle()
                }
                .font(Font.largeTitle)
                .padding()
            }
        }
    }
}
  

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

Комментарии:

1. большое спасибо, это было первое, что я подумал об этом! ЛоЛ, но я ищу достойную анимацию преобразования

2. Учитывая, что мое решение и это здесь, мне интересно, что такое «достойная анимация преобразования», которой не являются эти два решения? @Omar

3. @IiroAlhonen, да, это создает иллюзию преобразования, но я не могу использовать этот cornerRadios для преобразования в другую форму, такую как звезда, суть моего вопроса — анимация преобразования, а не решение ее примера

Ответ №2:

Group это не настоящий контейнер, поэтому не сохраняйте анимацию. Group Замените некоторым стеком, например

         VStack
        {
            if action
              // ... other code no change
  

Комментарии:

1. Согласен. Замените Group на ZStack, и это должно сработать.

2. Я уже внес изменения, которые не увенчались успехом! даже используется с анимацией в кнопке, ничего

Ответ №3:

При выходе iOS14 вы можете использовать matchedGeometryEffect() . Если вы используете iOS14, я бы рекомендовал этот подход.

https://www.hackingwithswift.com/quick-start/swiftui/how-to-synchronize-animations-from-one-view-to-another-with-matchedgeometryeffect

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

Итак, в вашем решении, если вы замените action.toggle() на withAnimation{self.action.toggle()} в своем коде кнопки, он будет анимироваться.

 Button("transform") { 
    withAnimation{self.action.toggle()} 
    }
.font(Font.largeTitle).padding()
  

Это решение работает на симуляторе для меня (Xcode 12.1, iPhone 11 iOS 14.1):

 import SwiftUI

struct ContentView: View {

@State var action: Bool = false
@Namespace var transition

var body: some View {
    ZStack {
        Group {
            if action {
                Circle()
                    .fill(Color.blue).frame(width: 150, height: 150, alignment: .center)
                    .matchedGeometryEffect(id: "shape", in: transition)
            } else {
                Rectangle()
                    .fill(Color.red).frame(width: 150, height: 150, alignment: .center)
                    .matchedGeometryEffect(id: "shape", in: transition)
            }
        }
        .animation(.easeInOut)
        
        VStack {
            Spacer()
            
            Button("transform") { withAnimation{self.action.toggle()} }.font(Font.largeTitle).padding()
                
        }
    }
}
}
  

matchedGeometryEffect() не хочет так красиво анимировать разные формы (включая cornerRadius) или цвета, не уверен, является ли это ошибкой, которая будет исправлена в будущих патчах, или просто функцией, которую нужно обойти с помощью обычной анимации. Когда я играю с matchedGeometryEffect(), кажется, он отлично справляется с увеличением и уменьшением размеров, как показано в этом коде:

 import SwiftUI

struct ContentView: View {
@State private var animate: Bool = false
@Namespace private var transition

    var body: some View {
        VStack {
            if animate {
                RoundedRectangle(cornerRadius: 75.0)
                    .matchedGeometryEffect(id: "shape", in: transition)
                    .frame(width: 250, height: 250, alignment: .center)
                    .foregroundColor(Color.blue)
                    .animation(.easeInOut)
                    .onTapGesture {
                        animate.toggle()
                    }
         
            } else {
                // Circle
                RoundedRectangle(cornerRadius: 75.0)
                    .matchedGeometryEffect(id: "shape", in: transition)
                    .frame(width: 150, height: 150, alignment: .center)
                    .foregroundColor(Color.red)
                    .animation(.easeInOut)
                    .onTapGesture {
                        animate.toggle()
                    }
            }
        }
    }
}
  

Комментарии:

1. @Omar вставил весь код, который работает для меня в симуляторе без проблем.

2. У меня был тот же результат, прежде чем задавать этот вопрос, посмотрите код и анимацию @vacawama, он получил правильный эффект, но это не анимация преобразования или что-то в этом роде, он работает с cornerRadius

3. @Omar теперь я действительно заинтересовался, поэтому проведу еще несколько исследований.

4. Да! Эта тема очень сложная, я хотел создать пользовательскую анимацию, но она будет работать только и только для преобразования из круга в прямоугольник или из прямоугольника в круг! но как насчет других фигур! например, преобразовать из прямоугольника в пятиугольник или в звезду! У меня есть идея для работы, и она работает над path of shape, на самом деле это очень сложный и большой проект, я считаю, что было бы лучше работать с Metal или SpritKit для общего использования анимации. Но, конечно, путь, возможно, это путь и основная графика

5. Определенно, этот вопрос может стать причиной для перехода на pool of Metal и посмотреть, что там происходит.