1675092138
TransitionableTab makes it easy to animate when switching between tab .
Move | Scale | Fade | Custom |
![]() | ![]() | ![]() | ![]() |
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
CocoaPods 1.1+ is required to build TransitionableTab 4.2+.
To integrate TransitionableTab into your Xcode project using CocoaPods, specify it in your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
target '<Your Target Name>' do
pod 'TransitionableTab', '~> 0.2.0'
end
Then, run the following command:
$ pod install
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew using the following command:
$ brew update
$ brew install carthage
To integrate TransitionableTab into your Xcode project using Carthage, specify it in your Cartfile
:
github "Interactive-Studio/TransitionableTab" ~> 0.2.0
Run carthage update
to build the framework and drag the built TransitionableTab.framework
into your Xcode project.
If you prefer not to use either of the aforementioned dependency managers, you can integrate TransitionableTab into your project manually.
The usage of TransitionableTab is very simple
import TransitionableTab
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
}
extension TabBarController: TransitionableTab {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
return animateTransition(tabBarController, shouldSelect: viewController)
}
}
public protocol TransitionableTab: UITabBarControllerDelegate {
func transitionTimingFunction() -> CAMediaTimingFunction
func transitionDuration() -> CFTimeInterval
func fromTransitionAnimation(layer: CALayer, direction: Direction) -> CAAnimation
func toTransitionAnimation(layer: CALayer, direction: Direction) -> CAAnimation
}
If you want to know more detailed usage, please refer to Example.
Author: ParkGwangBeom
Source Code: https://github.com/ParkGwangBeom/TransitionableTab
License: MIT license
1674284493
Check out how to schedule notifications in Flutter:
https://youtu.be/T6Wg0AmIESE
Visit my channel for more awesome flutter contents:
https://lnkd.in/gYh4HAfD
#animation #flutter #flutterdev #mobile #mobileapp #appdesign #flutterapp #appdev #mobileapp #developer #ui #ux #dev
1673956336
Apple introduced UIViewPropertyAnimator
for iOS 10. We can use this new API to control interactive animations. To experiment UIViewPropertyAnimator
, we developed this game by using UIKit only đ (no Sprite Kit at all đŹ). And you can see the animations are very smooth, looking forward to see more interactive animations in iOS 10.
$ git clone https://github.com/JakeLin/SaveTheDot.git
$ cd SaveTheDot
$ open "SaveTheDot.xcodeproj"
Requirements
Author: JakeLin
Source Code: https://github.com/JakeLin/SaveTheDot
License: MIT license
1673633400
open var colorForTapView: UIColor = UIColor.black.withAlphaComponent(0.35)
open var shouldAnimateWithPan: Bool = true
// Create FAPanelController object with out any NSCoder, Storyboards and Nib files
let rootController = FAPanelController()
// Configure the panels as you want and assign this panel controller to root controller of window.
window?.rootViewController = rootController
// You can also set window's root controller to any FAPanelController object with different FAPanelConfigurations at any time.
back | front |
---|---|
![]() | ![]() |
// Set the Right Panel position
let rootController: FAPanelController = window?.rootViewController as! FAPanelController
rootController.rightPanelPosition = .front
rootController.rightPanelPosition = .back
back | front |
---|---|
![]() | ![]() |
// Set the Left Panel position
let rootController: FAPanelController = window?.rootViewController as! FAPanelController
rootController.leftPanelPosition = .front
rootController.leftPanelPosition = .back
// Panels width
var leftPanelWidth : CGFloat = 280 // It will override the gap percentage value
var rightPanelWidth: CGFloat = 280
var leftPanelGapPercentage : CGFloat = 0.8
var rightPanelGapPercentage: CGFloat = 0.8
// resizes all subviews as well
var resizeLeftPanel : Bool = false
var resizeRightPanel: Bool = false
// Adds push animation on side panels
var pusheSidePanels: Bool = false
// Bounce effects on panel animations
var bounceOnLeftPanelOpen : Bool = true
var bounceOnRightPanelOpen : Bool = true
var bounceOnCenterPanelOpen: Bool = true
var bounceOnLeftPanelClose : Bool = false
var bounceOnRightPanelClose : Bool = false
var bounceOnCenterPanelChange: Bool = true
var bouncePercentage : CGFloat = 0.075
var bounceDuration : CGFloat = 0.1
// Panning Gesture
var canRecognizePanGesture: Bool = true
var panFromEdge : Bool = false
var minEdgeForLeftPanel : CGFloat = 70.0
var minEdgeForRightPanel : CGFloat = 70.0
var canLeftSwipe : Bool = true
var canRightSwipe: Bool = true
// restricts panning gesture to work for top VC of Navigation/TabBar Controller
var restrictPanningToTopVC: Bool = true
// Handles the interface auto rotation of visible panel
var handleAutoRotation: Bool = true
// Applies corner radius to panels
var cornerRadius: CGFloat = 0.0
// Shadow configurations
open var shadowColor : CGColor = UIColor.black.cgColor
open var shadowOffset : CGSize = CGSize(width: 10.0, height: 0.0)
open var shadowOppacity: Float = 0.5
// Remove panels from super view when possible
var unloadRightPanel: Bool = false
var unloadLeftPanel : Bool = false
// Max animation duration for animations of side panels
var maxAnimDuration : CGFloat = 0.20
// percentage of screen's width to the centerPanel.view must move for panGesture to succeed
var minMovePercentage: CGFloat = 0.15
// Only Center Panel Change animation
var changeCenterPanelAnimated : Bool = true
var centerPanelTransitionType : FAPanelTransitionType = .crossDissolve
var centerPanelTransitionDuration: TimeInterval = 0.60
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
To integrate FAPanel into your Xcode project using CocoaPods, specify it in your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!
target '<Your Target Name>' do
pod 'FAPanels'
end
Then, run the following command:
$ pod install
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew using the following command:
$ brew update
$ brew install carthage
To integrate FAPanels into your Xcode project using Carthage, specify it in your Cartfile
:
github "fahidattique55/FAPanels" >= 0.2.0
Run carthage update
to build the framework and drag the built FAPanels.framework
into your Xcode project.
AppDelegate.swift
file,
// Load the Controllers
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let leftMenuVC: LeftMenuVC = mainStoryboard.instantiateViewController(withIdentifier: "LeftMenuVC") as! LeftMenuVC
let rightMenuVC: RightMenuVC = mainStoryboard.instantiateViewController(withIdentifier: "RightMenuVC") as! RightMenuVC
let centerVC: CenterVC = mainStoryboard.instantiateViewController(withIdentifier: "CenterVC1") as! CenterVC
let centerNavVC = UINavigationController(rootViewController: centerVC)
// Set the Panel controllers with just two lines of code
let rootController: FAPanelController = window?.rootViewController as! FAPanelController
rootController.center(centerNavVC).left(leftMenuVC).right(rightMenuVC)
// This is the code to set all panels
rootController.center(centerNavVC).left(leftMenuVC).right(rightMenuVC)
// Updated code which have only left and center panels
rootController.center(centerNavVC).left(leftMenuVC)
// Similarly, if left panel is not needed the remove the left panel code.
rootController.center(centerNavVC).right(rightMenuVC)
// In case you only want the center panel, then update code to
rootController.center(centerNavVC)
rootController.configs.rightPanelWidth = 80
rootController.configs.bounceOnRightPanelOpen = false
// Should Pan from edge? Add these lines of code,
rootController.configs.panFromEdge = false
rootController.configs.minEdgeForLeftPanel = 70
rootController.configs.minEdgeForRightPanel = 70
rootController.center(centerNavVC).left(leftMenuVC).right(rightMenuVC)
// For more configurations and their details, Please have a look into ``` FAPanelConfigurations.swift ``` file
panel?.configs = FAPanelConfigurations()
panel?.openLeft(animated: true)
panel?.openRight(animated: true)
// Change Center panel
let centerVC: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "CenterVC2")
let centerNavVC = UINavigationController(rootViewController: centerVC)
panel!.center(centerNavVC)
// Change Left panel
let leftVC: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "LeftVC")
panel!.left(leftVC)
// Remove Left panel
panel!.left(nil)
// Specify the transition type
panel!.configs.centerPanelTransitionType = .transitionOption // Transitions supported are mentioned in FAPanelTransitionType
// Specify the transition duration
panel!.configs.centerPanelTransitionDuration = 0.60
// Update the center panel
panel!.center(centerNavVC)
flipFromLeft | flipFromRight |
---|---|
![]() | ![]() |
flipFromTop | flipFromBottom |
---|---|
![]() | ![]() |
curlUp | curlDown |
---|---|
![]() | ![]() |
crossDissolve | moveRight |
---|---|
![]() | ![]() |
moveLeft | moveUp |
---|---|
![]() | ![]() |
moveDown | splitVertically |
---|---|
![]() | ![]() |
splitHorizontally | dumpFall |
---|---|
![]() | ![]() |
boxFade |
---|
![]() |
New Features Added
Author: fahidattique55
Source Code: https://github.com/fahidattique55/FAPanels
License: Apache-2.0 license
1673584800
Delightful SwiftUI effects for your app.
Note Pow is free to test and evaluate. To deploy an app using it to the App Store, you need to purchase a license.
Installation
To add a package dependency to your Xcode project, select File > Add Package and enter this repository's URL (https://github.com/movingparts-io/Pow).
Overview
Pow features a selection of SwiftUI transitions as well as Change Effects that trigger every time a value is updated.
You can find previews of all effects on the Pow website. If you have an iOS Developer Environment, you can check out the Pow Example App.
Change Effects are effects that will trigger a visual or haptic every time a value changes.
Use the changeEffect
modifier and pass in an AnyChangeEffect
as well as a value to watch for changes.
Button {
post.toggleLike()
} label: {
Label(post.likes.formatted(), systemName: "heart.fill")
}
.changeEffect(.spray { heart }, value: post.likes, isEnabled: post.isLiked)
.tint(post.isLiked ? .red : .gray)
You can choose from the following Change Effects: Spray, Haptic Feedback, Jump, Ping, Rise, Shake, Shine, and Spin.
An effect that emits multiple particles in different shades and sizes moving up from the origin point.
likeButton
.changeEffect(
.spray(origin: .center) { Image(systemName: "heart.fill") },
value: likes
)
origin
: The origin of the particles.particles
: The particles to emit.static func spray(origin: UnitPoint = .center, @ViewBuilder _ particles: () -> some View) -> AnyChangeEffect
Triggers the given haptic feedback type whenever a value changes.
feedback
: The feedback type beiged triggered.static func hapticFeedback(_ feedback: UINotificationFeedbackGenerator.FeedbackType) -> AnyChangeEffect
Makes the view jump the given height and then bounces a few times before settling.
height
: The height of the jump.static func jump(height: CGFloat) -> AnyChangeEffect
Adds one or more shapes that slowly grow and fade-out behind the view.
The shape will be colored by the current tint style.
shape
: The shape to use for the effect.count
: The number of shapes to emit. static func ping(shape: some InsettableShape, count: Int) -> AnyChangeEffect
An effect that adds one or more shapes that slowly grow and fade-out behind the view.
shape
: The shape to use for the effect.style
: The style to use for the effect.count
: The number of shapes to emit.static func ping(shape: some InsettableShape, style: some ShapeStyle, count: Int) -> AnyChangeEffect
An effect that emits the provided particles from the origin point and slowly float up while moving side to side.
origin
: The origin of the particle.particles
: The particles to emit.static func rise(origin: UnitPoint = .center, @ViewBuilder _ particles: () -> some View) -> AnyChangeEffect
Shakes the view when a change happens.
static var shake: AnyChangeEffect
An effect that shakes the view when a change happens.
rate
: The rate of the shake.static func shake(rate: ShakeRate) -> AnyChangeEffect
Highlights the view with a shine moving over the view.
The shine moves from the top leading edge to bottom trailing edge.
static var shine: AnyChangeEffect
Highlights the view with a shine moving over the view.
The shine moves from the top leading edge to bottom trailing edge.
static func shine(duration: Double) -> AnyChangeEffect
Highlights the view with a shine moving over the view.
The angle is relative to the current layoutDirection
, such that 0° represents sweeping towards the trailing edge and 90° represents sweeping towards the top edge.
angle
: The angle of the animation.duration
: The duration of the animation.static func shine(angle: Angle, duration: Double = 1.0) -> AnyChangeEffect
Spins the view around the given axis when a change happens.
static var spin: AnyChangeEffect
Spins the view around the given axis when a change happens.
static func spin(axis: (x: CGFloat, y: CGFloat, z: CGFloat), anchor: UnitPoint = .center, anchorZ: CGFloat = 0, perspective: CGFloat = 1 / 6) -> AnyChangeEffect
All transitions are namespaced under the movingParts
static variable, e.g.
myView.transition(.movingParts.anvil)
A transition that drops the view down from the top with matching haptic feedback.
The transition is only performed on insertion and takes 1.4 seconds.
static var anvil: AnyTransition
A transition that reveals the view as if it was behind window blinds.
static var blinds: AnyTransition
A transition that reveals the view as if it was behind window blinds.
Parameters:
slatWidth
: The width of each slat.style
: The style of blinds, either .venetian
or .vertical
.isStaggered
: Whether all slats opens at the same time or in sequence.static func blinds(slatWidth: CGFloat, style: BlindsStyle = .venetian, isStaggered: Bool = false) -> AnyTransition
A transition from blurry to sharp on insertion, and from sharp to blurry on removal.
static var blur: AnyTransition
A transition that moves the view down with any overshoot resulting in an elastic deformation of the view.
static var boing: AnyTransition
A transition that moves the view away towards the specified edge, with any overshoot resulting in an elastic deformation of the view.
static func boing(edge: Edge) -> AnyTransition
A transition using a clockwise sweep around the centerpoint of the view.
static var clock: AnyTransition
A transition using a clockwise sweep around the centerpoint of the view.
blurRadius
: The radius of the blur applied to the mask.static func clock(blurRadius: CGFloat) -> AnyTransition
A transition that toggles the visibility of the view multiple times before settling.
static var flicker: AnyTransition
A transition that toggles the visibility of the view multiple times before settling.
count
: The number of times the visibility is toggled.static func flicker(count: Int) -> AnyTransition
A transition from completely dark to fully visible on insertion, and from fully visible to completely dark on removal.
static var filmExposure: AnyTransition
A transition that inserts by rotating the view towards the viewer, and removes by rotating the view away from the viewer.
Note: Any overshoot of the animation will result in the view continuing the rotation past the view's normal state before eventually settling.
static var flip: AnyTransition
A transitions that shows the view by combining a diagonal wipe with a white streak.
static var glare: AnyTransition
A transitions that shows the view by combining a wipe with a colored streak.
The angle is relative to the current layoutDirection
, such that 0° represents sweeping towards the leading edge on insertion and 90° represents sweeping towards the top edge.
In this example, the removal of the view is using a glare with an exponential ease-in curve, combined with a anticipating scale animation, making for a more dramatic exit.
infoBox
.transition(
.asymmetric(
insertion: .movingParts.glare(angle: .degrees(225)),
removal: .movingParts.glare(angle: .degrees(45)
)
.animation(.movingParts.easeInExponential(duration: 0.9))
.combined(with:
.scale(scale: 1.4)
.animation(.movingParts.anticipate(duration: 0.9).delay(0.1)
)
)
)
)
direction
: The angle of the wipe.color
: The color of the glare effect.static func glare(angle: Angle, color: Color = .white) -> AnyTransition
A transition that takes the shape of a growing circle when inserting, and a shrinking circle when removing.
origin
: The center point of the circle as it grows or shrinks.blurRadius
: The radius of the blur applied to the mask.static func iris(origin: UnitPoint = .center, blurRadius: CGFloat = 0) -> AnyTransition
A transition that moves the view from the specified edge of the on insertion and towards it on removal.
static func move(edge: Edge) -> AnyTransition
A transition that moves the view at the specified angle.
The angle is relative to the current layoutDirection
, such that 0° represents animating towards the leading edge on insertion and 90° represents inserting towards the top edge.
In this example, the view insertion is animated by moving it towards the top trailing corner and the removal is animated by moving it towards the bottom edge.
Text("Hello")
.transition(
.asymmetric(
insertion: .movingParts.move(angle: .degrees(45)),
removal: .movingParts.move(angle: .degrees(90))
)
)
angle
: The direction of the animation.static func move(angle: Angle) -> AnyTransition
A transition that shows a view with a ripple effect and a flurry of tint-colored particles.
The transition is only performed on insertion and takes 1.2 seconds.
static var pop: AnyTransition
A transition that shows a view with a ripple effect and a flurry of colored particles.
In this example, the star uses the pop effect only when transitioning from starred == false
to starred == true
:
Button {
starred.toggle()
} label: {
if starred {
Image(systemName: "star.fill")
.foregroundStyle(.orange)
.transition(.movingParts.pop(.orange))
} else {
Image(systemName: "star")
.foregroundStyle(.gray)
.transition(.identity)
}
}
The transition is only performed on insertion.
style
: The style to use for the effect.static func pop<S: ShapeStyle>(_ style: S) -> AnyTransition
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
A transition that inserts by rotating from the specified rotation, and removes by rotating to the specified rotation in three dimensions.
In this example, the view is rotated 90Ë about the y axis around its bottom edge as if it was rising from lying on its back face:
Text("Hello")
.transition(.movingParts.rotate3D(
.degrees(90),
axis: (1, 0, 0),
anchor: .bottom,
perspective: 1.0 / 6.0)
)
Note: Any overshoot of the animation will result in the view continuing the rotation past the view's normal state before eventually settling.
angle
: The angle from which to rotate the view.axis
: The x, y and z elements that specify the axis of rotation.anchor
: The location with a default of center that defines a point in 3D space about which the rotation is anchored.anchorZ
: The location with a default of 0 that defines a point in 3D space about which the rotation is anchored.perspective
: The relative vanishing point with a default of 1 for this rotation.static func rotate3D(_ angle: Angle, axis: (x: CGFloat, y: CGFloat, z: CGFloat), anchor: UnitPoint = .center, anchorZ: CGFloat = 0, perspective: CGFloat = 1) -> AnyTransition
A transition from completely bright to fully visible on insertion, and from fully visible to completely bright on removal.
static var snapshot: AnyTransition
A transition that moves the view in from its leading edge with any overshoot resulting in an elastic deformation of the view.
static var skid: AnyTransition
A transition that moves the view in from the specified edge during insertion and towards it during removal with any overshoot resulting in an elastic deformation of the view.
direction
: The direction of the transition.static func skid(direction: SkidDirection) -> AnyTransition
A three-dimensional transition from the back of the towards the front during insertion and from the front towards the back during removal.
static var swoosh: AnyTransition
A transition that dissolves the view into many small particles.
The transition is only performed on removal.
Note: This transition will use an ease-out animation with a duration of 900ms if the current
Animation
is.default
.
static var vanish: AnyTransition
A transition that dissolves the view into many small particles.
The transition is only performed on removal.
Note: This transition will use an ease-out animation with a duration of 900ms if the current
Animation
is.default
.
style
: The style to use for the particles.static func vanish<S: ShapeStyle>(_ style: S) -> AnyTransition
A transition that dissolves the view into many small particles following a given shape.
The transition is only performed on removal.
Note: This transition will use an ease-out animation with a duration of 900ms if the current
Animation
is.default
.
style
: The style to use for the particles.mask
: The mask that determines where particles should be placed.eoFill
: A Boolean that indicates whether the shape is interpreted with the even-odd winding number rule.static func vanish<T: ShapeStyle, S: Shape>(_ style: T, mask: S, eoFill: Bool = false) -> AnyTransition
A transition using a sweep from the specified edge on insertion, and towards it on removal.
edge
: The edge at which the sweep starts or ends.blurRadius
: The radius of the blur applied to the mask.static func wipe(edge: Edge, blurRadius: CGFloat = 0) -> AnyTransition
Author: Movingparts-io
Source Code: https://github.com/movingparts-io/Pow
License: View license
1673373540
DynamicBlurView is a dynamic and high performance UIView subclass for Blur.
Add the following to your Podfile
:
pod "DynamicBlurView"
Add the following to your Cartfile
:
github "KyoheiG3/DynamicBlurView"
Blur the whole
let blurView = DynamicBlurView(frame: view.bounds)
blurView.blurRadius = 10
view.addSubview(blurView)
Animation
UIView.animateWithDuration(0.5) {
blurView.blurRadius = 30
}
Ratio
blurView.blurRatio = 0.5
var blurRadius: CGFloat
var trackingMode: TrackingMode
Common
is constantly updated.Tracking
is only during scrolling update.None
is not update.var blendColor: UIColor?
var iterations: Int
var isDeepRendering: Bool
var blurRatio: CGFloat
var quality: CaptureQuality
func refresh()
func remove()
func animate()
Author: KyoheiG3
Source Code: https://github.com/KyoheiG3/DynamicBlurView
License: MIT license
1673345400
Windless makes it easy to implement invisible layout loading view.
![]() | ![]() | ![]() |
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
CocoaPods 1.1+ is required to build Windless 4.0+.
To integrate Windless into your Xcode project using CocoaPods, specify it in your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
target '<Your Target Name>' do
pod 'Windless', '~> 0.1.5'
end
Then, run the following command:
$ pod install
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew using the following command:
$ brew update
$ brew install carthage
To integrate Windless into your Xcode project using Carthage, specify it in your Cartfile
:
github "Interactive-Studio/Windless" ~> 0.1.5
Run carthage update
to build the framework and drag the built Windless.framework
into your Xcode project.
If you prefer not to use either of the aforementioned dependency managers, you can integrate Windless into your project manually.
import Windless
class ViewController: UIViewController {
lazy var contentsView = UIView()
var subView1 = UIView()
var subView2 = UIView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(contentsView)
contentsView.addSubview(subView1)
contentsView.addSubview(subView2)
// start
contentsView.windless
.setupWindlessableViews([subView1, subView2])
.start()
// stop
contentsView.windless.end()
}
}
If you use Storyboard or xib, you only need to set the isWindlessable
flag to true for the views you want to show as fake in the view inspector of the view, and you do not have to pass the view through the setupWindlessableViews
method.
import Windless
class ViewController: UIViewController {
@IBOutlet weak var contentsView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
contentsView.windless.start()
}
}
Depending on the lineHeight
value and the spacing
value, UILabel and UITextView will reconstruct the layout when the windless animation runs.
public protocol CanBeMultipleLines {
var lineHeight: CGFloat { get set }
var spacing: CGFloat { get set }
}
There are several customizable options in Windless.
public class WindlessConfiguration {
/// The direction of windless animation. Defaults to rightDiagonal.
public var direction: WindlessDirection = .rightDiagonal
/// The speed of windless animation. Defaults to 1.
public var speed: Float = 1
/// The duration of the fade used when windless begins. Defaults to 0.
public var beginTime: CFTimeInterval = 0
/// The time interval windless in seconds. Defaults to 4.
public var duration: CFTimeInterval = 4
/// The time interval between windless in seconds. Defaults to 2.
public var pauseDuration: CFTimeInterval = 2
/// gradient animation timingFunction default easeOut
public var timingFuction: CAMediaTimingFunction = .easeOut
/// gradient layer center color default .lightGray
public var animationLayerColor: UIColor = .lightGray
/// Mask layer background color default .groupTableViewBackground
public var animationBackgroundColor: UIColor = .groupTableViewBackground
/// The opacity of the content while it is windless. Defaults to 0.8.
public var animationLayerOpacity: CGFloat = 0.8
}
To set the options, use the apply method as shown below.
import Windless
class ViewController: UIViewController {
@IBOutlet weak var contentsView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
contentsView.windless
.apply {
$0.beginTime = 1
$0.pauseDuration = 2
$0.duration = 3
$0.animationLayerOpacity = 0.5
}
.start()
}
}
If you want to know more detailed usage, please refer to Example.
The isWindlessable
value determines how the loading view looks. The images below show how the loading screen will look according to the isWindlessable
value.
isWindlessable
= đ
Author: ParkGwangBeom
Source Code: https://github.com/ParkGwangBeom/Windless
License: MIT license
1673243250
Check out how to implement local push notification in flutter: https://lnkd.in/gJapii36
Visit my channel for more awesome flutter contents: https://lnkd.in/gYh4HAfD
#animation #flutter #flutterdev #mobile #mobileapp #appdesign #flutterapp #appdev #mobileapp #developer #ui #ux #uiux #appUI #design
1673134620
Purpose
GravitySlider is a lightweight animation flowlayot for UICollectionView completely written in Swift 4, compatible with iOS 11 and xCode 9.
Supported OS & SDK Versions
GravitySliderFlowLayout is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'GravitySliderFlowLayout'
Usage
import GravitySliderFlowLayout
let gravitySliderLayout = GravitySliderFlowLayout(with: CGSize(width: 50, height: 50))
collectionView.collectionViewLayout = gravitySliderLayout
Demo
Release Notes
Version 1.0
Contact Us
You can always contact us via github@applikeysolutions.com We are open for any inquiries regarding our libraries and controls, new open-source projects and other ways of contributing to the community. If you have used our component in your project we would be extremely happy if you write us your feedback and let us know about it!
Made by Applikey Solutions
Find this project on Dribbble
Author: ApplikeySolutions
Source Code: https://github.com/ApplikeySolutions/GravitySlider
License: MIT license
1673130780
With ParticlesLoadingView
you can create your own amazing SpriteKit
particles animations with the Xcode's built-in Particle Emitter Editor that looks like the following picture. Go ahead and create your own particles animation by doing File âĄď¸ New File âĄď¸ iOS Resource âĄď¸ SpriteKit Particle File.
To see it in action, run the example project, clone the repo, and run pod install
from the Example
directory first. The example project shows how to set up ParticlesLoadingView
in a few different ways.
The easiest way to add a particles animation around the border of any UIView
subclass is to use the extension method as follows:
let view = ... // Your UIView subclass here
view.addParticlesAnimation(effect: ParticleEffect.Fire) // Use a built-in effect
view.addParticlesAnimation(emitter: emitter) // Use your own SKEmitterNode
You can also use the already provided ParticlesLoadingView
class to create an animation. Instantiate it by code or in Storyboard and select a built-in ParticleEffect
or set the scene.emitterNode
to your custom SKEmitterNode
object.
var loadingView: ParticlesLoadingView = {
let view = ParticlesLoadingView(frame: 0, y: 0, width: 75, height: 75))
view.particleEffect = .Spark
view.duration = 1.5
view.layer.cornerRadius = 15.0
return view
}()
// OR provide your own SKEmitterNode
let emitter = NSKeyedUnarchiver.unarchiveObjectWithFile(NSBundle.mainBundle().pathForResource("Spark", ofType: "sks")!) as? SKEmitterNode
if let emitter = emitter {
loadingView.scene.emitterNode = emitter
loadingView.startAnimating()
}
/// Duration in seconds of the animation to complete a tour on the border of the view.
public var duration = 2.0
/// The size of each particle image. This value is used to calculate the inner padding of the view path so that the emitted particles are visible.
public var particlesSize: CGFloat = 5.0
/// The emitter of particles that is animated along the border of the view.
public var emitterNode: SKEmitterNode? = nil
You can provide your own particle emitter node by designing an animation with the particle emitter editor and creating a SKEmitterNode
. If you want to customize it further than that, the project is documented so go ahead and đ´ it.
If you think a feature should be included in this project, submit a PR or open a new issue.
ParticlesLoadingView
is available through CocoaPods. To install it, simply add the following line to your Podfile
:
pod "ParticlesLoadingView"
You can also use Carthage if you prefer. Add this line to your Cartfile
.
github "BalestraPatrick/ParticlesLoadingView"
iOS 9.0 and Swift 3 are required.
If you are using Swift 4, please use the swift4 branch.
If you are using Swift 2.3, please use the swift2.3 branch.
Author: BalestraPatrick
Source Code: https://github.com/BalestraPatrick/ParticlesLoadingView
License: MIT license
1673099923
Check out how to implement Swipe Animation in Flutter: https://lnkd.in/g7usvuTg
Visit my channel for more awesome flutter contents: https://lnkd.in/gYh4HAfD
#animation #flutter #flutterdev #mobile #mobileapp #appdesign #flutterapp #appdev #mobileapp #developer #ui #ux #uiux #appUI #design
1672731660
Oasis is a web-first and mobile-first high-performance real-time interactive engine. Use component system design and pursue ease of use and light weight. Developers can independently use and write Typescript scripts to develop projects using pure code.
// Create engine by passing in the HTMLCanvasElement id and adjust canvas size.
const engine = new WebGLEngine("canvas-id");
engine.canvas.resizeByClientSize();
// Get scene and create root entity.
const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity("Root");
// Create light.
const lightEntity = rootEntity.createChild("Light");
const directLight = lightEntity.addComponent(DirectLight);
lightEntity.transform.setRotation(-45, -45, 0);
directLight.intensity = 0.4;
// Create camera.
const cameraEntity = rootEntity.createChild("Camera");
cameraEntity.addComponent(Camera);
cameraEntity.transform.setPosition(0, 0, 12);
// Create sphere.
const meshEntity = rootEntity.createChild("Sphere");
const meshRenderer = meshEntity.addComponent(MeshRenderer);
const material = new BlinnPhongMaterial(engine);
meshRenderer.setMaterial(material);
meshRenderer.mesh = PrimitiveMesh.createSphere(engine, 1);
// Run engine.
engine.run();
The engine is published on npm with full typing support. To install, use:
npm install oasis-engine
This will allow you to import engine entirely using:
import * as OASIS from "oasis-engine";
or individual classes using:
import { Engine, Scene, Entity } from "oasis-engine";
Everyone is welcome to join us! Whether you find a bug, have a great feature request or you fancy owning a task from the road map feel free to get in touch.
Make sure to read the Contributing Guide / č´ĄçŽćĺ before submitting changes.
Prerequisites:
npm install -g pnpm
)In the folder where you have cloned the repository, install the build dependencies using pnpm:
pnpm install
Then, to build the source, using npm:
npm run b:all
Author: Ant-galaxy
Source Code: https://github.com/ant-galaxy/oasis-engine
License: MIT license
1671291320
About 10 years ago web animation was in big trouble. Adobe Flash was dying but there was still no obvious replacement. We needed a fast, easy-to-author, web-friendly format capable of staging larger-scale animated demos, cartoons, and banners.
Happily, in 2014 AirBnB offered us their solution â Lottie.JS.
Lottie.js is an open-source, vector-based animation format created by AirBnB Experience and Motion Designer, Salih Abdul-Karim. The Lottie engine was designed to render fast, crisp, low-bandwidth vector animations identically on Web, iOS, Android, Windows and React Native.
In short, if you enjoy using SVG for your imagery, Lottie is a great way to animate those vector graphics. If youâre looking to replace GIFs, MPEG, or CSS animation with something lighter faster, and more scalable, Lottie may well be your best answer.
Lottie in action: Popeye the Sailor Man by Bashir Ahmed
As Bashir Ahmedâs beautiful example demonstrates, Lottie can produce character-rich, lithe, fluid movement from tiny files â this animation is generated from a 54kb file.
At their most basic, Lottie animations like Bashirâs require just two files.
There are many ways to animate web vectors â from CSS animations to SVGâs SMIL to GreenSock, AnimeJS, and other JavaScript libraries.
However, Lottie has a killer âone-two punchâ of:
For all its well-documented problems, Adobe Flashâs long success was based on combining a good authoring tool with easy cross-platform deployment. I think Lottie shares some of Flashâs advantages.
As Lottie files are nothing more than JSON text files, technically you could just code your animation straight into any IDE. In reality, youâll want to select a âLottie-capableâ animation tool. Here are my thoughts on the handful that Iâve tried and tested.
In my view there are two factors to consider when selecting a Lottie Animator:
Iâll cover these two areas separately for each tool.
After Effects does a lot. But is it too much?
Ok, this is arguably a controversial take, given the Lottie format was built for After Effects, but I donât believe AE is the best Lottie creation platform⌠for most people.
Firstly, it isnât cheap. If youâre already paying a Creative Cloud subscription, the cost wonât be an issue. But if youâre NOT currently a CC subscriber, you will be biting off a new ongoing minimum charge of $US21/month.
Secondly, Lottie was conceived as a clever way to âhackâ After Effects into making web graphics. While After Effects is an incredibly powerful tool, itâs designed to produce everything from Hollywood special effects to movie title sequences to 3D game cut-scenes to big-budget TVCs. Thereâs a boatload of stuff you simply wonât need or want.
If you are already an âAfter Effects guruâ, by all means, leverage your hard-won talents and make amazing stuff. Likewise, if youâre a Windows or Linux user, After Effects may still be your most viable option.
However, if youâre currently a Mac-based AE novice, thereâs an argument that using After Effects to make Lottie animations is like water-skiing from an aircraft carrier.
Sure, you can do it, but there are easier ways.
Cost: | US$20.99/mo |
---|---|
OS: | macOS, Windows, Linux |
Link: | Adobe After Effects Download |
As I write this (2022), Haiku Animator appears to be a tragic victim of being the perfect product at the wrong time.
Launched in 2018, Haiku was built from the ground up as an ideal blend of design and code. The animation tools were rich and powerful and the UI was fast and sensible.
The Haiku animation interface
However, for me it was Haikuâs export tools that really set it apart from anything else, offering ready-to-use code for React, React Native, iOS, Android, Vue, and Angular, as well as traditional GIF and Video.
Export options in Haiku
Sadly, development on Haiku began to peter out some time in 2020 as the team pivoted to another product. They officially open-sourced the Haiku codebase in late 2021. Apparently, it still works if you go through the installation process, but the prospects for future development and support appear shaky.
I only mention Haiku here in the slim hope that it has been revived by the time you read this. It was an excellent product (I paid for it) and is sorely missed.
Cost: | Free |
---|---|
OS: | macOS, Windows, Linux |
Link: | Haiku Download |
Flow is arguably the logical heir to Haikuâs legacy â a nicely featured animator that delivers neat, production-ready Lottie code for a range of popular web and mobile platforms.
Incidentally, it weighs in at a tidy 88Mb installed on my MacBook, which is handy for anyone with space limitations (thatâs me). Unlike Haiku, there are currently no Windows or Linux options offered.
Although Flow pitches strongly at Sketch users, it will work with practically any SVG file you provide. It was simple to import and sync my Figma files, and Flow even did a very creditable job at âsmart auto-animatingâ the tween states between two static SVG frames I gave it. It wasnât a flawless import of what I had, but it was competent enough to be useful.
Flow doesnât offer much in the way of built-in drawing/shape/text tools. Ultimately, this isnât a big deal, since syncing between Flow and Figma/Sketch works very well, and this helps keeps the Flow animation UI sharp and uncluttered.
The Flow UI
Flow offers excellent Lottie export facilities, but you will need to select one of the two higher-end plans to access it:
The âCode+â tier lets you export Lottie for Web, although, slightly disappointingly, youâll need to upgrade to the top tier Pro user plan to get access to Lottie for iOS and Android. That may or may not matter be a dealbreaker for you.
Flow isnât the cheapest option â in the ballpark of After Effects â but itâs not expensive if you animate regularly. Itâs an attractive, slickly-designed tool perfectly suited to creating and deploying Lottie animations at a reasonable price.
Cost: | US$199/Annual |
---|---|
OS: | macOS |
Link: | Flow Download |
Keyshape is an excellent product with only two problems.
The Keyshape website doesnât fill you with confidence.
I admit I had low expectations when I downloaded Keyshape. The website screams âanimation toy for hobbyistsâ, rather than âserious pro animation toolâ. The modest pricing ($29) backs up that idea. It canât be good at that price, right?
To my surprise, Keyshape turned out to be much better than I expected. Itâs actually VERY good!
Sketch App as an animator.
The Keyshape App install is a little under 100Mb on my Mac. The left side tool panel contains about a dozen basic vector editing tools â lines, rectangles, circles, text and the like. Though I suspect most of us would use Illustrator, Figma, or Sketch to create our vector artwork, itâs still useful to be able to make simple edits in your animator.
Keyshape lets you create base âsymbolsâ and then manipulate as many instances as you like.
The animation timeline runs along the bottom panel. Auto-Keyframing creates new keyframes any time you transform your artwork in the canvas view. Clicking on a âtweenedâ section gives you access to different easing functions â including customizable cubic-beziers.
The righthand panel gives you fine control over any canvas object you select. As you might expect, that includes scale, skew, rotation, XY position and blending modes, but also lets you control SVG filters such as blur, drop shadow, contrast and hue.
Keyshape offers a range of export options including MPEG, GIF, SVG animation, CSS, sprite sheets, custom JS and even PNG image sequences.
The Keyshape export dialog â with Lottie plugin installed
Keep in mind that Lottie is not a default export option in Keyshape. Youâll need to install the free Lottie plugin for Keyshape to access this new superpower.
Keyshape doesnât offer any component export facilities for React, Node, Vue, or any of the other popular dev platforms, so you may need to solve that part yourself.
It doesnât attempt to âsmart auto-generateâ the tween states between imported SVG keyframes like Flow does.
But generally there wasnât anything else glaringly obvious I missed when using Keyshape App.
I enjoy animation in general and Lottie in particular, but the truth is, itâs not where I spend most of my work hours. Iâd like to do more, but months go by when I might not touch an animation project. Do I really want another monthly subscription? Probably not.
For me, Keyshape seems like an amazing bargain for the power it delivers â even if it hide it well.
Cost: | $29 one-off |
---|---|
OS: | MacOS |
Link | Keyshape Download |
Attempting to put a single label on Lottiefiles.com is no easy task because they offer a lot. This includes an active Lottie community, a Lottie asset marketplace, Lottie tutorials, and Lottie showcase, preview and hosting applications. Itâs fair to say, theyâve gone all in on the future of Lottie.
The Lottiefiles Editor
LottieFiles also offer a handful of simple Lottie editing utilities. These include:
Lottie Files: Their SVG to Lottie tool
Letâs be frank: It would be difficult to create complex work from scratch using the LottieFiles tools, but there are more than enough useful resources there to make it worth your while.
Cost: | Free |
---|---|
OS: | Web, MacOS, Windows, Linux |
Link: | https://lottiefiles.com |
If creating lightweight vector animation takes up a lot of your time, Flow may be the most focused and complete Lottie development tool available. It has a crisp workflow and the export options are as good or better than most competitors.
If you already know and like Adobe After Effects, use what you know.
In my case, I enjoy animation, but that is not where I expend most of my work hours. Months may pass when I donât touch an animation project. Do I really want another monthly subscription? Probably⌠not.
For me, Keyshape (at $29) seems like an amazing bargain for the power it delivers â even if they obscure it well.
Original article source at: https://www.sitepoint.com/
1670512249
what is it
https://user-images.githubusercontent.com/9412501/159002380-329fb171-c993-4373-b5e1-ad28fe05e7d4.mp4
https://user-images.githubusercontent.com/9412501/159002392-f00afe4a-dcb9-4081-bc52-417f4f2b281d.mp4
how to use
Center(
child: View3D.me(),
)
const WinLoading({
this.color = Colors.white,
this.radius = 3,
this.gap = 0.04,
this.amount = 5,
this.width = 60,
this.height = 60,
this.duration = const Duration(milliseconds: 7200),
this.cubic = const Cubic(.21, .6, .59, .8),
Key? key,
})
Run this command:
With Flutter:
$ flutter pub add winloading
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
winloading: ^0.0.3
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:winloading/winloading.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:winloading/winloading.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ColoredBox(
color: Colors.black38,
child: const WinLoading(),
),
const SizedBox.square(dimension: 10,),
const ColoredBox(
color: Colors.black38,
child: WinLoading(cubic: const Cubic(.07, .59, .59, .8),),
),
const SizedBox.square(dimension: 10,),
const ColoredBox(
color: Colors.black38,
child: WinLoading(cubic: const Cubic(.17,.59,.59,.8),),
),
const SizedBox.square(dimension: 10,),
const ColoredBox(
color: Colors.black38,
child: WinLoading(cubic: const Cubic(.22,.42,.64,.79),),
),
const SizedBox.square(dimension: 10,),
const ColoredBox(
color: Colors.black38,
child: WinLoading(cubic: const Cubic(.22,.42,.44,.71),),
),
const SizedBox.square(dimension: 10,),
const ColoredBox(
color: Colors.black38,
child: WinLoading(cubic: const Cubic(.15,.6,.64,.79),),
),
const SizedBox.square(dimension: 10,),
],
),
);
}
}
Download Details:
Author: ZuYun
Source Code: https://github.com/ZuYun/winloading
1670420220
Animations make websites look more polished and exciting, and help improve user experience. Explore how the combined potential of SVG and CSS can be leveraged to create animations without relying on external libraries.
Animations are a ubiquitous part of the web. Unlike the flashing GIF images that plagued websites in the internetâs earlier days, todayâs animations are more subtle and tasteful. Designers and front-end specialists use them to make websites look more polished, enhance the user experience, call attention to important elements, and convey information.
Web developers can benefit from combining the power of SVG and CSS to create animations without using external libraries. This SVG animation tutorial shows how to build custom animations for real-world projects.
Before animating SVGs with CSS, developers need to understand how SVGs work internally. Fortunately, itâs similar to HTML: We define SVG elements with XML syntax and style them with CSS, just as if they were HTML.
SVG elements are purposely built for drawing graphics. We can use <rect>
for drawing a rectangle, <circle>
for drawing circles, etc.âSVG also defines <ellipse>
, <line>
, <polyline>
, <polygon>
, and <path>
.
Note: The full list of SVG elements even includes <animate>
, which allows you to create animations using synchronized multimedia integration language (SMIL). However, its future is uncertain and the Chromium team recommends using a CSS- or JavaScript-based approach to animating SVGs whenever possible.
The available attributes depend on the element, so while <rect>
has width
and height
attributes, the <circle>
element has the r
attribute, which defines its radius.
Select basic SVG elements; coordinates are relative to the origin (the top-left corner of the SVG viewport).
While most HTML elements can have children, most SVG elements cannot. One exception is the group element <g>
, which we can use in order to apply CSS styles and transformations to multiple elements at once.
<svg>
Element and Its AttributesAnother important difference between HTML and SVG is how we position elements, notably via the viewBox
attribute of a given outer <svg>
element. Its value consists of four numbers separated by whitespace or a comma: min-x
, min-y
, width
, and height
. Together, these specify how much of our SVG drawing we want the browser to render. That area will be scaled to fit the bounds of the viewport, as defined by the width
and height
attributes of the <svg>
element.
When it comes to letterboxing, the ratio of the width
and height
attributes of the viewport may indeed differ from the ratio of the width
and height
parts of the viewBox
attribute.
By default, the aspect ratio of the SVG canvas will be preserved at the expense of a larger-than-specified viewBox
, thereby causing a smaller, letterboxed rendering within the viewport. But you can specify a different behavior via the preserveAspectRatio
attribute.
This allows us to draw images in isolation and be confident that all elements will be positioned correctly no matter the context or rendering size.
Maintaining the aspect ratio of an image via letterboxing.
While you can code SVG images by hand, more complex images may require a vector graphics program (our SVG animation tutorial demonstrates both techniques). My editor of choice is Affinity Designer, but any editor should provide enough functionality for the simple operations covered here.
CSS transitions allow us to define the rate and duration of property changes. Instead of jumping instantly from the starting value to the end value, the values transition smoothly as in this example in which the color of an SVG circle changes when you hover over it with a mouse:
We can define transitions with the transition
property, which accepts the name of the property that we want to transition, the duration of the transition, a transition timing function (also known as easing function), and the length of the delay before the effect begins:
/* property name | duration | easing function | delay */
transition: margin-right 4s ease-in-out 1s;
We can define transitions for multiple CSS properties, each of which can have separate transition values. However, there are two obvious limitations to this approach.
The first limitation is that transitions are triggered automatically when a property value changes. This is inconvenient in some use cases. For example, we canât have an animation that loops infinitely.
The second limitation is that transitions always have two steps: the initial state and the final state. We can extend the duration of the animation, but we canât add different keyframes.
This is why a more powerful concept exists: CSS animations. With CSS animations, we can have multiple keyframes and an infinite loop:
To animate CSS properties over multiple keyframes, first we need to define the keyframes using an @keyframes
at-rule. The timing of keyframes is defined in relative units (percentages) because at this point, we havenât yet defined the animation duration. Each keyframe describes the values of one or more CSS properties at that point in time. CSS animations will ensure smooth transitions between keyframes.
We apply the animation with described keyframes to the desired element using the animation
property. Similar to the transition
property, it accepts a duration, an easing function, and a delay.
The only difference is that the first parameter is our @keyframes
name instead of a property name:
/* @keyframes name | duration | easing-function | delay */
animation: my-sliding-animation 3s linear 1s;
Now that we have a basic understanding of how animating SVGs works, we can start building a classic animationâa menu toggle that smoothly transitions between a âhamburgerâ icon and a close button (an âXâ):
This is a subtle but valuable animation. It attracts the userâs attention, informing them that the icon can be used to close the menu.
We start our demonstration by creating an SVG element with three lines:
<svg class="hamburger">
<line x1="0" y1="50%" x2="100%" y2="50%"
class="hamburger__bar hamburger__bar--top" />
<line x1="0" y1="50%" x2="100%" y2="50%"
class="hamburger__bar hamburger__bar--mid" />
<line x1="0" y1="50%" x2="100%" y2="50%"
class="hamburger__bar hamburger__bar--bot" />
</svg>
Each line has two sets of attributes. The x1
and y1
represent the coordinates of the start of the line, while x2
and y2
represent the coordinates of the end of the line. Weâve used relative units to set positions. This is a simple way to ensure that image contents get resized to fit the containing SVG element. While this approach works in this case, there is one big drawback: We canât maintain the aspect ratio of elements positioned this way. For that, we would have to use the viewBox
attribute of the <svg>
element.
Note that we applied CSS classes to SVG elements. There are many properties that can be changed via CSS, so letâs apply some basic styling to our SVG elements.
Weâll set the size of the <svg>
element, as well as change the cursor type to indicate that itâs clickable. But to set the color and thickness of the lines, weâll use the stroke
and stroke-width
properties. You might have expected to use color
or border
, but unlike <svg>
itself, SVG sub-elements are not HTML elements, so they often have different property names:
.hamburger {
width: 62px;
height: 62px;
cursor: pointer;
}
.hamburger__bar {
stroke: white;
stroke-width: 10%;
}
If we render at this point, weâll see that all three lines have the same size and position, overlapping each other completely. Unfortunately, we canât change the starting and ending positions independently via CSS, but we can move whole elements. Letâs move the top and bottom bars with the transform
CSS property:
.hamburger__bar--top {
transform: translateY(-40%);
}
.hamburger__bar--bot {
transform: translateY(40%);
}
By moving the bars on the Y axis we end up with a decent-looking hamburger.
Now itâs time to code our second state: the close button. We rely on an .is-opened
CSS class applied to the SVG element to toggle between the two states. To make the result more accessible, letâs wrap our SVG in a <button>
element and handle clicks on that level.
The process of adding and removing the class will be handled by a simple JavaScript snippet:
const hamburger = document.querySelector("button");
hamburger.addEventListener("click", () => {
hamburger.classList.toggle("is-opened");
});
In order to create our X, we can apply a different transform
property to our hamburger bars. Because the new transform
property will override the old one, our starting point will be the original, shared position of the three bars.
From there, we can rotate the top bar 45 degrees clockwise around its center, and rotate the bottom bar 45 degrees counterclockwise. We can shrink the middle bar horizontally until it is narrow enough to be hidden behind the center of the X:
.is-opened .hamburger__bar--top {
transform: rotate(45deg);
}
.is-opened .hamburger__bar--mid {
transform: scaleX(0.1);
}
.is-opened .hamburger__bar--bot {
transform: rotate(-45deg);
}
By default, the transform-origin
property for SVG elements is normally 0,0
. This means that our bars will be rotated around the top-left corner of the viewport, but we want them to rotate around the center. To fix this, letâs set the transform-origin
property to center
for the .hamburger__bar
class.
transition
The transition
CSS property tells the browser to smoothly transition between two different states of CSS properties. Here we want to animate our changes to the transform
property, which dictates the positions, orientation, and scale of the bars.
We can also control the duration of the transition using the transition-duration
property. To make the animation look snappy, weâll set a short duration of 0.3 seconds:
.hamburger__bar {
transition-property: transform;
transition-duration: 0.3s;
...
}
The only piece of JavaScript we need is the bit that makes the icon state toggleable:
const hamburger = document.querySelector("button");
hamburger.addEventListener("click", () => {
hamburger.classList.toggle("is-opened");
});
Here, we select the outer SVG element by its .mute
class using querySelector()
. We then add a click event listener. When a click event is triggered, we toggle the .is-active
class only on the <svg>
itselfâno deeper in the hierarchy. Because we made the CSS animation only apply to elements with the .is-active
class, toggling this class will activate and deactivate the animation.
As a final touch, weâll convert the HTML body to a flex container, which will help us center the icon horizontally and vertically. Weâll also update the background color to a very dark gray and the icon color to white, to attain a sleek âdark modeâ look and feel:
body {
display: flex;
justify-content: center;
align-items: center;
background-color: #222;
height: 100vh;
}
With that, weâve built a fully functional animated button using some basic CSS and a short JavaScript snippet. Itâs easy to change the transformations weâve applied to make a variety of animations. Readers can simply fork the CodePenâwhich includes a bit of extra CSS for polishâand get creative.
Our hamburger menu is extremely simple. What if we want to make something more complex? Thatâs where coding SVG by hand becomes difficult and vector graphics editing software can help.
Our second SVG animation is a mute button showing a headphones icon. When the music is active, the icon will pulsate and dance; when itâs muted, the icon will be crossed out:
Drawing icons would be outside of the scope of this tutorial (and probably your job description), so we are going to start with a pre-drawn SVG icon. Weâll also want the same body
styling as our hamburger menu example.
You might want to clean up the SVG code before working with it. You can do this with svgo, an open-source, Node.js-based SVG optimizer tool. This will remove unnecessary elements and make the code easier to edit by hand, which you will need to do in order to add classes and combine different elements.
SVG icons created in image editing software are unlikely to use relative units. Additionally, we want to make sure that the iconâs aspect ratio is maintained, regardless of the aspect ratio of the SVG element containing it. To make this level of control possible, we will use the viewBox
attribute.
Itâs a good idea to resize the SVG so that viewBox
can be set to some easy-to-use values. In this case, Iâve converted it to a viewBox
that is 100 x 100 pixels.
Letâs make sure the icon is centered and appropriately sized. Weâll apply the mute
class to our base SVG element and then add the following CSS styles:
.mute {
fill: white;
width: 80px;
height: 70px;
cursor: pointer;
}
Here, the width
is slightly greater than the height
to avoid clipping during the rotations of our animation.
The now-clean SVG contains a single <g>
element that contains three <path>
elements.
The path element allows us to draw lines, curves, and arcs. Paths are described with a series of commands that describe how the shape should be drawn. As our icon consists of three unconnected shapes, we have three paths to describe them.
The g SVG element is a container used to group other SVG elements. We use it to apply the pulsating and dancing transformations on all three paths simultaneously.
<svg class="mute" viewBox="0 0 100 100">
<g>
<path d="M92.6,50.075C92.213,26.775 73.25,7.938 50,7.938C26.75,7.938 7.775,26.775 7.388,50.075C3.112,51.363 -0.013,55.425 -0.013,60.25L-0.013,72.7C-0.013,78.55 4.575,83.3 10.238,83.3L18.363,83.3L18.363,51.6C18.4,51.338 18.438,51.075 18.438,50.813C18.438,33.275 32.6,19 50,19C67.4,19 81.563,33.275 81.563,50.813C81.563,51.088 81.6,51.338 81.638,51.6L81.638,83.313L89.763,83.313C95.413,83.313 100.013,78.563 100.013,72.713L100.013,60.263C100,55.438 96.875,51.362 92.6,50.075Z" />
<path d="M70.538,54.088L70.538,79.588C70.538,81.625 72.188,83.275 74.225,83.275L74.225,83.325L78.662,83.325L78.662,50.4L74.225,50.4C72.213,50.4 70.538,52.063 70.538,54.088Z" />
<path d="M25.75,50.4L21.313,50.4L21.313,83.325L25.75,83.325L25.75,83.275C27.788,83.275 29.438,81.625 29.438,79.588L29.438,54.088C29.45,52.063 27.775,50.4 25.75,50.4Z" />
</g>
</svg>
To make the headphones pulsate and dance, transition
wonât suffice. This is an example that is complex enough to need keyframes.
In this case, our starting and ending keyframes (at 0% and 100% of the animation, respectively) use a slightly shrunken headphones icon. For the first 40% of the animation we grow the image slightly and tilt it 5 degrees. Then, for the next 40% of the animation, we scale it back down to 0.9x and rotate it 5 degrees to the other side. Finally, for the last 20% of the animation, the icon transformation returns to the same initial parameters in order to loop smoothly.
@keyframes pulse {
0% {
transform: scale(0.9);
}
40% {
transform: scale(1) rotate(5deg);
}
80% {
transform: scale(1) rotate(-5deg);
}
100% {
transform: scale(0.9) rotate(0);
}
}
To show how keyframes work, we left our keyframe CSS more verbose than it needs to be. There are three ways we could shorten it.
Since our 100%
keyframe sets the entire transform
list, if we were to omit rotate()
entirely, its value would default to 0:
100% {
transform: scale(0.9);
}
Secondly, we know we want our 0%
and 100%
keyframes to match because weâre looping the animation. By defining them with the same CSS rule, we wonât have to remember to modify both of them if we want to change this shared point in the animation loop:
0%, 100% {
transform: scale(0.9);
}
Lastly, weâll soon apply transform: scale(0.9);
to the mute__headphones
class, and when we do, we wonât need to define the starting and ending keyframes at all! Theyâll default to the static style used by mute__headphones
.
Now that weâve defined the animation keyframes, we can apply the animation. We add the .mute__headphones
class to the <g>
element so that it affects all three parts of the headphones icon. First, we once again set transform-origin
to center
as we want the icon to rotate around its center. We also scale it so that its size matches the initial animation keyframe. Without this step, switching from the static âmutedâ icon to the animated one will always result in a sudden jump in size. (Either way, switching back to muted will cause a jump in scaleâand likely rotation tooâif the user clicks while the scale is larger than 0.9x. We canât do much about that effect with CSS alone.)
We apply the animation using the animation
CSS property but only when the .is-active
parent class is present, similar to how we animated our hamburger menu.
.mute__headphones {
transform-origin: center;
transform: scale(0.9);
}
.is-active .mute__headphones {
animation: pulse 2s infinite;
}
The JavaScript we need to let us switch between states follows the same pattern as the hamburger menu too:
const muteButton = document.querySelector(".mute");
muteButton.addEventListener("click", () => {
muteButton.classList.toggle("is-active");
});
The next piece weâll add is a strikethrough line that appears when the icon is inactive. As this is a simple design element, we can code it manually. This is where having simple and reasonable viewBox
values is useful. We know that the edges of the canvas are at 0 and 100 so it is easy to calculate the start and end positions for our line:
<line x1="12" y1="12" x2="88" y2="88" class="mute__strikethrough" />
A case can be made for using relative units instead of resizing the image. This applies in our example because we are adding only a simple SVG line over our icon.
In real-world scenarios you might want to combine more complex SVG content from several different sources. This is where making them all a uniform size is useful, as we canât manually hard-code the relative values like we did in our example.
Because we applied a class directly to our strikethrough <line>
element, we can style it via CSS. We just need to make sure that the line is not visible when the icon is active:
.mute__strikethrough {
stroke: red;
opacity: 0.8;
stroke-width: 12px;
}
.is-active .mute__strikethrough {
opacity: 0;
}
Optionally, we can add the .is-active
class directly to the SVG. This will make the animation start as soon as the page is loaded, so we effectively change the initial state of the icon from non-animated (muted) to animated (non-muted).
Weâve only scratched the surface of CSS animation techniques and how viewports work. Itâs worth knowing how to write SVG code by hand to keep simple animations simple, but itâs also important to know how and when to make use of graphics created with external editors. While modern browsers enable us to create impressive animations using only built-in functionality, for (very) complex use cases, developers might want to explore animation libraries like GSAP or anime.js.
Animations donât have to be reserved for extravagant projects. Modern CSS animation techniques allow us to create a wide array of engaging and polished animations in a simple, cross-browser-compatible way.
Original article source at: https://www.toptal.com/