How can I get the blue circles to first move away from the green circle before getting back to it?
The animation should be:
I got everything working except the blue circles moving up part.
This is the current animation:
And its playground.
import SwiftUI
import PlaygroundSupport
struct DotsView: View {
var diameter: CGFloat = 200
var size: CGFloat = 25
var isPressed: Bool = false
var body: some View {
ZStack {
ForEach(0...5, id: \.self) { i in
Circle()
.fill(Color.blue)
.frame(width: size, height: size)
.offset(x: 0, y: -(diameter)/2 - size/2)
.rotationEffect(.degrees(CGFloat(i * 60)))
}
}
.frame(width: diameter, height: diameter)
.animation(.none)
.scaleEffect(isPressed ? 0.8 : 1)
.animation(
isPressed ? .easeOut(duration: 0.2) : .interactiveSpring(response: 0.35, dampingFraction: 0.2),
value: isPressed
)
.background(
Circle()
.fill(Color.green)
.scaleEffect(isPressed ? 0.8 : 1)
.animation(isPressed ? .none : .interactiveSpring(response: 0.35, dampingFraction: 0.2), value: isPressed)
)
}
}
struct ContentView: View {
@State private var isPressed: Bool = false
var body: some View {
DotsView(
diameter: 200,
isPressed: isPressed
)
.frame(width: 500, height: 500)
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged { _ in
isPressed = true
}
.onEnded { _ in
isPressed = false
}
)
}
}
let view = ContentView()
PlaygroundPage.current.setLiveView(view)
Thanks
Actually all is needed is to replace linear scaleEffect
with custom geometry effect that gives needed scale curve (initially growing then falling).
Here is a demo of possible approach (tested with Xcode 13.4 / iOS 15.5)
Main part:
struct JumpyEffect: GeometryEffect {
let offset: Double
var value: Double
var animatableData: Double {
get { value }
set { value = newValue }
}
func effectValue(size: CGSize) -> ProjectionTransform {
let trans = (value + offset * (pow(5, value - 1/pow(value, 5))))
let transform = CGAffineTransform(translationX: size.width * 0.5, y: size.height * 0.5)
.scaledBy(x: trans, y: trans)
.translatedBy(x: -size.width * 0.5, y: -size.height * 0.5)
return ProjectionTransform(transform)
}
}
and usage
.modifier(JumpyEffect(offset: isPressed ? 0.3 : 0, value: isPressed ? 0.8 : 1))