cramos24
cramos24

Reputation: 39

Layering iOS Animations

I'm having some trouble layering iOS animations for my video recoding button. I've modeled it after other standard recording buttons and I'd like for it to begin as a solid circle and then on press, transform to a rounded rectangle where its opacity pulses.

The issue is that I've ordered the animations in a way such that their all applied at the same time.

https://i.sstatic.net/N8lzx.jpg

I've tried reordering these animations but can't figure out which ordering with achieve the scope I want.

import SwiftUI

struct ContentView: View {
    @State var recordComplete = false
    @State private var rCorner: CGFloat = 100
    @State private var rWidth: CGFloat = 70
    @State private var rHeight: CGFloat = 70
    @State private var opacityVal = 1.0
    
    var body: some View {
        HStack{
            Button(action: {
                self.rCorner = self.rCorner == 100 ? 12 : 100
                self.rWidth = self.rWidth == 70 ? 45 : 70
                self.rHeight = self.rHeight == 70 ? 45 : 70
                self.recordComplete.toggle()
                
            }) {
                ZStack{
                    Circle()
                        .stroke(Color.red, lineWidth: 6)
                        .frame(width:85, height: 85)
                
                    
                    RoundedRectangle(cornerRadius: rCorner)
                        .fill(Color.red)
                        .frame(width: rWidth, height: rHeight)
                        .opacity(opacityVal)
                        .animation(Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)).onAppear{ self.opacityVal = 0.3 }
                    
                }
                .padding(.vertical, 25)
                
            }
        }.animation(.spring(response: 0.5, dampingFraction: 2, blendDuration: 0.5))
    }
}

Thank you as always for the help with this issue!

Upvotes: 1

Views: 59

Answers (1)

Asperi
Asperi

Reputation: 257543

Here is a possible solution - the main idea is to separate animations by value and make them serial. Tested with Xcode 12 / iOS 14

demo

struct ContentView: View {
    @State var recordComplete = false
    @State private var rCorner: CGFloat = 100
    @State private var rWidth: CGFloat = 70
    @State private var rHeight: CGFloat = 70
    @State private var opacityVal = 1.0

    var body: some View {
        HStack{
            Button(action: {
                self.rCorner = self.rCorner == 100 ? 12 : 100
                self.rWidth = self.rWidth == 70 ? 45 : 70
                self.rHeight = self.rHeight == 70 ? 45 : 70

                self.recordComplete.toggle()
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    self.opacityVal = self.recordComplete ? 0.3 : 1.0
                }
            }) {
                ZStack{
                    Circle()
                        .stroke(Color.red, lineWidth: 6)
                        .frame(width:85, height: 85)


                    RoundedRectangle(cornerRadius: rCorner)
                        .fill(Color.red)
                        .frame(width: rWidth, height: rHeight)
                        .opacity(opacityVal)
                        .animation(
                            self.recordComplete ?
                                Animation.easeInOut(duration: 1).repeatForever(autoreverses: true) :
                                Animation.default,
                            value: opacityVal)
                }
                .padding(.vertical, 25)

            }
        }.animation(.spring(response: 0.5, dampingFraction: 2, blendDuration: 0.5), value: rCorner)
    }
}

Upvotes: 1

Related Questions