https://github.com/c-villain/animatable
Yet another animation modifiers (like fireworks, live comments or explosion) on SwiftUI
https://github.com/c-villain/animatable
blinking ios shimmers swift-package swiftui swiftui-animation swiftui-animations swiftui-example
Last synced: 28 days ago
JSON representation
Yet another animation modifiers (like fireworks, live comments or explosion) on SwiftUI
- Host: GitHub
- URL: https://github.com/c-villain/animatable
- Owner: c-villain
- License: mit
- Created: 2023-01-05T12:01:54.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-06-03T15:50:14.000Z (11 months ago)
- Last Synced: 2025-04-06T12:03:51.582Z (about 1 month ago)
- Topics: blinking, ios, shimmers, swift-package, swiftui, swiftui-animation, swiftui-animations, swiftui-example
- Language: Swift
- Homepage: https://t.me/swiftui_dev
- Size: 9.15 MB
- Stars: 55
- Watchers: 2
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Animatable
[](https://github.com/c-villain/Animatable/releases/latest)
[](https://swiftpackageindex.com/c-villain/Animatable)
[](https://swiftpackageindex.com/c-villain/Animatable)
[](https://swift.org/package-manager/)
[](https://t.me/lexkraev)
[](https://telegram.dog/swiftui_dev)Yet another animation modifiers for buttons, skeletons and other views on pure SwiftUI.
![]()
![]()
### Demo example for card skeletons
![]()
🔍 Full demo video you can find [here](https://t.me/swiftui_dev/222).
👨🏻💻 Feel free to subscribe to channel **[SwiftUI dev](https://t.me/swiftui_dev)** in telegram.## Requirements
- iOS 13.0 or macOS 10.15
## Installation
#### Swift Package Manager
To integrate ```Animatable``` into your project using SwiftPM add the following to your `Package.swift`:
```swift
dependencies: [
.package(url: "https://github.com/c-villain/Animatable", from: "0.1.0"),
],
```
or via [XcodeGen](https://github.com/yonaskolb/XcodeGen) insert into your `project.yml`:```yaml
name: YourProjectName
options:
deploymentTarget:
iOS: 13.0
packages:
Animatable:
url: https://github.com/c-villain/Animatable
from: 0.1.0
targets:
YourTarget:
type: application
...
dependencies:
- package: Animatable
```## Quick start
All examples you can find in demo project inside package.
There are different custom animation types provided by `Animatable`.
👇🏻 Tap on its name to see description and example of using.
Live comments effect
![]()
Use `.animate(.liveComments(stamps:),animate:)` where `stamps` is number of prints in animation activity, `animate` is flag to start animation.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "heart.fill" : "heart")
.resizable()
.scaledToFit()
.animate(.liveComments(stamps: 4),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.white)Text("Like")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.pink.opacity(0.8))
.cornerRadius(12)
)
}
```Explosion effect
![]()
Use `.animate(.explosive(color:),animate:)` where `color` is color of explosion in animation activity, `animate` is flag to start animation.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "power" : "poweroff")
.resizable()
.scaledToFit()
.animate(.explosive(color: .white),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.white)Text(animate ? "On" : "Off")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.gray.opacity(0.8))
.cornerRadius(12)
)
}
```
Tweak effect
![]()
Use `.animate(.tweaking(amount:,shakesPerUnit:),animate:)` where `amount` is tweak offset, `shakesPerUnit` is number of shakes in tweking, `animate` is flag to start animation.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "hand.thumbsup.fill" : "hand.thumbsup")
.resizable()
.scaledToFit()
.animate(.tweaking(),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.white)Text("Like")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.blue.opacity(0.8))
.cornerRadius(12)
)
}
```
Scaling effect
![]()
Use `.animate(.scaling(scaling:),animate:)` where `scaling` is scaling factor, `animate` is flag to start animation.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "plus.app.fill" : "plus.app")
.resizable()
.scaledToFit()
.animate(.scaling(),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.white)Text("Add")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.yellow.opacity(0.8))
.cornerRadius(12)
)
}
```
Rotating effect
![]()
Use `.animate(.rotating,animate:)` where `animate` is flag to start animation.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "arrow.triangle.2.circlepath.circle.fill" : "arrow.triangle.2.circlepath.circle")
.resizable()
.scaledToFit()
.animate(.rotating,
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.white)Text("Sync")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.blue.opacity(0.8))
.cornerRadius(12)
)
}
```
Fireworks effect
![]()
Use `.animate(.fireworks(color:),animate:)` where `color` is color of animation, `animate` is flag to start animation.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "sun.max.fill" : "sun.max")
.resizable()
.scaledToFit()
.animate(.fireworks(color: .white),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.white)Text("Weather")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.blue.opacity(0.8))
.cornerRadius(12)
)
}
```
👇🏻 You can easily join them together to combine animation.
Combining animation
![]()
Use sequence of `.animate(type:,animate:)` to get multiple animation effect.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "sun.max.fill" : "sun.max")
.resizable()
.scaledToFit()
.animate(.rotating,
animate: animate)
.animate(.explosive(color: .red, factor: 2.0),
animate: animate)
.animate(.explosive(color: .blue, factor: 1.4),
animate: animate)
.animate(.fireworks(color: .yellow, factor: 3.5),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.red)Text("Combined")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.blue.opacity(0.6))
.cornerRadius(12)
)
}
```
👇🏻 Animation for skeletons and other views.
Shimmers
![]()
Use sequence of `.shimmerable(configuration:)` where `configuration` is settings for for shimmers or `.shimmerable()` for defaults
```swift
Rectangle()
.fill(.pink.opacity(0.8))
.frame(height: 40)
.frame(maxWidth: .infinity)
.shimmerable()
.cornerRadius(12)
```
Blinking
![]()
Use sequence of `.blinking(configuration:)` where `configuration` is settings for for blinking animation or `.blinking()` for defaults
```swift
Rectangle()
.fill(.pink.opacity(0.8))
.frame(height: 40)
.frame(maxWidth: .infinity)
.blinking()
.cornerRadius(12)
```
Combining blinking and shimmerable
![]()
Use sequence of `.blinking()` and `.shimmerable()` to get multiple animation effect.
```swift
Rectangle()
.fill(.pink.opacity(0.8))
.frame(height: 40)
.frame(maxWidth: .infinity)
.blinking()
.shimmerable()
.cornerRadius(12)
```
### ⚠️ Recommendations for usewith combining animation
Order in sequence of `.animate(type:,animate:)` is really important!
Feel the difference in the next example:```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: multiple ? "sun.max.fill" : "sun.max")
.resizable()
.scaledToFit()
.animate(.liveComments(stamps: 4),
animate: animate)
.animate(.rotating,
animate: animate)
.animate(.explosive(color: .red, factor: 2.0),
animate: animate)
.animate(.explosive(color: .blue, factor: 1.4),
animate: animate)
.animate(.fireworks(color: .yellow, factor: 3.0),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.red)Text("Weather")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.blue.opacity(0.6))
.cornerRadius(12)
)
}
```Using this sequence of `.animate(...)` leads to such behaviour:
![]()
To get expected behaviour this we should change the order in chain:
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: multiple ? "sun.max.fill" : "sun.max")
.resizable()
.scaledToFit()
.animate(.rotating, // <== Look here!
animate: animate)
.animate(.liveComments(stamps: 4), // <== Look here!
animate: animate)
.animate(.explosive(color: .red, factor: 2.0),
animate: animate)
.animate(.explosive(color: .blue, factor: 1.4),
animate: animate)
.animate(.fireworks(color: .yellow, factor: 3.0),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.red)Text("Weather")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background(
Rectangle()
.fill(.blue.opacity(0.6))
.cornerRadius(12)
)
}
```
The result:
![]()
with group of viewsUse can use `.animate(...)` not only for one view but for group of views
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: animate ? "heart.fill" : "heart")
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.foregroundColor(.red)Text("Like")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.red)
}
.animate(.liveComments(stamps: 4), // <== Look here!
animate: animate)
.padding(12)
.background(
Rectangle()
.fill(.blue.opacity(0.8))
.cornerRadius(12)
)
}
```
The result:
![]()
with standart SUI modifiersBe careful with standard SUI modifiers. It may cause different side effects.
For example [`cornerRadius`](https://developer.apple.com/documentation/quartzcore/calayer/1410818-cornerradius) crops the modified view.
```swift
@State var animate: Bool = false
...
Button {
animate.toggle()
} label: {
HStack(spacing: 8) {
Image(systemName: liveComments ? "heart.fill" : "heart")
.resizable()
.scaledToFit()
.animate(.liveComments(stamps: 4),
animate: animate)
.frame(width: 24, height: 24)
.foregroundColor(.red)Text("Like")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.white)
}
.padding(12)
.background (
Color.blue.opacity(0.8)
)
.cornerRadius(12) // <== Look here!
}
```
The result:
![]()
I recommend you to use it in the `.background` to get expected behaviour:
```swift
.background ( // <== Look here
Rectangle()
.fill(.blue.opacity(0.8))
.cornerRadius(12) // <== Look here
)
```
## Communication
- If you like this repository, please do :star: to make this useful for others.
- If you **found a bug**, open an issue or submit a fix via a pull request.
- If you **have a feature request**, open an issue or submit a implementation via a pull request or hit me up on **[email protected]** or **[telegram](https://t.me/lexkraev)**.
- If you **want to contribute**, submit a pull request onto the master branch.## License
Animatable package is released under an MIT license.