gh-EmergeTools-Pow/Sources/Pow/Transitions/Poof.swift
2024-01-03 09:01:34 -08:00

149 lines
4.7 KiB
Swift

import SwiftUI
public extension AnyTransition.MovingParts {
/// A transition that removes the view in a dissolving cartoon style cloud.
///
/// The transition is only performed on removal and takes 0.4 seconds.
static var poof: AnyTransition {
.asymmetric(
insertion: .identity,
removal: .modifier(
active: Poof(animatableData: 0),
identity: Poof(animatableData: 1)
)
.animation(.linear(duration: 0.4))
)
}
}
struct Poof: ViewModifier, ProgressableAnimation, AnimatableModifier {
var animatableData: CGFloat = 0
internal init(animatableData: CGFloat) {
self.animatableData = animatableData
}
func body(content: Content) -> some View {
let frame = (6 * progress).rounded()
content
.opacity(progress != 1 ? 0 : 1)
.overlay(
ZStack {
poof("poof1").opacity(frame == 5 ? 1 : 0)
poof("poof2").opacity(frame == 4 ? 1 : 0)
poof("poof3").opacity(frame == 3 ? 1 : 0)
poof("poof4").opacity(frame == 2 ? 1 : 0)
poof("poof5").opacity(frame == 1 ? 1 : 0)
}
.accessibilityHidden(true)
)
.animation(nil, value: progress)
}
func poof(_ name: String) -> some View {
Image(name, bundle: .module)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 88, height: 88)
}
}
#if os(iOS) && DEBUG
struct Proof_Preview: PreviewableAnimation, PreviewProvider {
static var animation: Poof {
Poof(animatableData: 0)
}
static var content: any View {
ZStack {
RoundedRectangle(cornerRadius: 32, style: .continuous)
.fill(Color.accentColor)
Text("Hello\nWorld!")
.foregroundColor(.white)
.multilineTextAlignment(.center)
.font(.system(.title, design: .rounded))
}
.frame(width: 300, height: 150)
}
}
@available(iOS 15.0, *)
struct Poof_Previews: PreviewProvider {
struct Preview: View {
@State
var indices: [UUID] = [UUID()]
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 12) {
VStack(alignment: .leading, spacing: 12) {
Text("Poof")
.bold()
Text("myView.transition(.movingParts.poof)")
}
.font(.footnote.monospaced())
.frame(maxWidth: .greatestFiniteMagnitude, alignment: .leading)
.padding()
.background(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(.thickMaterial)
)
Stepper {
Text("View Count ") + Text("(\(indices.count))").foregroundColor(.secondary)
} onIncrement: {
withAnimation {
indices.append(UUID())
}
} onDecrement: {
if !indices.isEmpty {
let _ = withAnimation {
indices.removeLast()
}
}
}
let columns: [GridItem] = [
.init(.flexible()),
.init(.flexible())
]
LazyVGrid(columns: columns) {
ForEach(indices, id: \.self) { uuid in
ZStack {
RoundedRectangle(cornerRadius: 32, style: .continuous)
.fill(Color.accentColor)
Text("Hello\nWorld!")
.foregroundColor(.white)
.multilineTextAlignment(.center)
.font(.system(.title, design: .rounded))
}
.transition(
.movingParts.poof
)
.aspectRatio(2, contentMode: .fit)
.id(uuid)
}
}
Spacer()
}
.padding()
}
}
}
static var previews: some View {
NavigationView {
Preview()
.navigationBarHidden(true)
}
}
}
#endif