https://github.com/nuplay/animationkit
AnimationKit simplifies sequential animations in iOS and macOS apps with SwiftUI.
https://github.com/nuplay/animationkit
animatable animation-library animations ios macos swift swift-package-manager swiftui ui-components
Last synced: 2 months ago
JSON representation
AnimationKit simplifies sequential animations in iOS and macOS apps with SwiftUI.
- Host: GitHub
- URL: https://github.com/nuplay/animationkit
- Owner: NuPlay
- License: mit
- Created: 2024-05-19T10:21:28.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2025-03-25T12:20:32.000Z (about 1 year ago)
- Last Synced: 2025-06-26T13:47:39.129Z (12 months ago)
- Topics: animatable, animation-library, animations, ios, macos, swift, swift-package-manager, swiftui, ui-components
- Language: Swift
- Homepage:
- Size: 12.7 KB
- Stars: 28
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# AnimationKit

### Swift Package Manager
```swift
dependencies: [
.package(url: "https://github.com/NuPlay/AnimationKit.git", .upToNextMinor(from: "1.0.0"))
]
```
# Usage
### When creating a simple view
```swift
import SwiftUI
import AnimationKit
struct AnimationKit_Test: View {
var body: some View {
VStack {
AnimatedStack(preset: .default) {
Text("Hello, World!")
.font(.title)
Text("This is Simple Stack View")
.font(.title2)
Rectangle()
.fill(Color.blue)
.frame(width: 100, height: 100)
}
}
}
}
```
### When using ForEach
```swift
import SwiftUI
import AnimationKit
struct AnimationKit_Test: View {
@State private var emojiData: [String] = ["🚀", "🛸", "🛰", "🌌", "🌠", "🌟", "🌕", "🌍", "🪐", "🌑", "🌒", "🌓", "🌔", "🌖", "🌗", "🌘", "🌙", "🌚", "🌝", "🌞"]
var body: some View {
ScrollView {
LazyVStack {
AnimatedForEach(emojiData, preset: .list) { emoji in
Text(emoji)
.font(.system(size: 100))
}
}
}
}
}
```
```swift
import SwiftUI
import AnimationKit
struct AnimationKitGrid_Test: View {
@State private var emojiData: [String] = ["🚀", "🛸", "🛰", "🌌", "🌠", "🌟", "🌕", "🌍", "🪐", "🌑", "🌒", "🌓", "🌔", "🌖", "🌗", "🌘", "🌙", "🌚", "🌝", "🌞"]
let columns = [GridItem(.adaptive(minimum: 100))]
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
AnimatedForEach(emojiData, preset: .grid) { emoji in
Text(emoji)
.font(.system(size: 100))
}
}
.padding()
}
}
}
```
# CustomAnimation
### You need to adopt the AnimatableStyle protocol.
```swift
public protocol AnimatableStyle {
var opacity: AnimationValue { get }
var offsetX: AnimationValue { get }
var offsetY: AnimationValue { get }
var rotation: AnimationValue { get }
var scale: AnimationValue { get }
var blur: AnimationValue { get }
var delay: Double { get }
var animation: Animation { get }
var maxAnimationCount: Int { get }
}
```
### You can create a struct that adopts the protocol as shown below.
```swift
struct YourCustomAnimationConfig: AnimatableStyle {
var opacity: AnimationValue = .init(from: 0, to: 1)
var offsetX: AnimationValue = .init(from: 0, to: 0)
var offsetY: AnimationValue = .init(from: 50, to: 0)
var rotation: AnimationValue = .init(from: 0, to: 0)
var scale: AnimationValue = .init(from: 1, to: 1)
var blur: AnimationValue = .init(from: 8, to: 0)
var delay: Double = 0.05
var animation: Animation = .bouncy(duration: 0.4)
var maxAnimationCount: Int = 20
}
```
```swift
AnimatedForEach(emojiData, preset: YourCustomAnimationConfig()) { emoji in
}
```
### You can modify the values of AnimationConfig as needed.
```swift
public struct AnimationConfig: Hashable, Equatable, AnimatableStyle {
public var opacity: AnimationValue
public var offsetX: AnimationValue
public var offsetY: AnimationValue
public var rotation: AnimationValue
public var scale: AnimationValue
public var blur: AnimationValue
public var delay: Double
public var animation: Animation
public var maxAnimationCount: Int
public init(
opacity: AnimationValue,
offsetX: AnimationValue,
offsetY: AnimationValue,
rotation: AnimationValue,
scale: AnimationValue,
blur: AnimationValue,
delay: Double = 0.05,
animation: Animation = .bouncy(duration: 0.4),
maxAnimationCount: Int = 20
) {
self.opacity = opacity
self.offsetX = offsetX
self.offsetY = offsetY
self.rotation = rotation
self.scale = scale
self.blur = blur
self.delay = delay
self.animation = animation
self.maxAnimationCount = maxAnimationCount
}
}
```
```swift
let preset: AnimationConfig = AnimationConfig(
opacity: .init(from: 0, to: 1),
offsetX: .init(from: 50, to: 0),
offsetY: .init(from: 10, to: 0),
rotation: .init(from: 0, to: 0),
scale: .init(from: 1.3, to: 1),
blur: .init(from: 8, to: 0)
)
AnimatedForEach(emojiData, preset: preset) { emoji in
}
```
### Explanation of `AnimatableStyle` Variables
| Variable | Type | Description |
|---------------------|----------------------------|---------------------------------------------------------------------------------------------------------|
| `opacity` | `AnimationValue` | Defines the animation values for opacity. |
| `offsetX` | `AnimationValue` | Defines the animation values for horizontal offset. |
| `offsetY` | `AnimationValue` | Defines the animation values for vertical offset. |
| `rotation` | `AnimationValue` | Defines the animation values for rotation. |
| `scale` | `AnimationValue` | Defines the animation values for scaling. |
| `blur` | `AnimationValue` | Defines the animation values for blur effect. |
| `delay` | `Double` | Determines the delay before each animation starts. |
| `animation` | `Animation` | Set to your desired animation type. |
| `maxAnimationCount` | `Int` | Maximum number of animations to play. |
| | | If set to 20, animations play up to the 20th item (index 19) according to the delay. |
| | | The 21st and subsequent items will animate simultaneously with the 21st. |
| | | This prevents excessive delays when animating large sets of data. |
| | | For example, without this option, you would need to wait `delay * 99` seconds to see the 100th item. |

### AnimationStyle Preset
```swift
var delay: Double = 0.05,
var animation: Animation = .bouncy(duration: 0.4),
var maxAnimationCount: Int = 20
extension AnimationStyle {
var config: AnimationConfig {
switch self {
case .`default`:
return AnimationConfig(
opacity: .init(from: 0, to: 1),
offsetX: .init(from: 0, to: 0),
offsetY: .init(from: 50, to: 0),
rotation: .init(from: 0, to: 0),
scale: .init(from: 1.0, to: 1.0),
blur: .init(from: 0, to: 0)
)
case .grid:
return AnimationConfig(
opacity: .init(from: 0, to: 1),
offsetX: .init(from: 0, to: 0),
offsetY: .init(from: 100, to: 0),
rotation: .init(from: 0, to: 0),
scale: .init(from: 1.3, to: 1.0),
blur: .init(from: 8, to: 0)
)
case .list:
return AnimationConfig(
opacity: .init(from: 0, to: 1),
offsetX: .init(from: 50, to: 0),
offsetY: .init(from: 0, to: 0),
rotation: .init(from: 0, to: 0),
scale: .init(from: 1.1, to: 1.0),
blur: .init(from: 0, to: 0)
)
}
}
}
```