Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@chriseidhof
Created October 21, 2019 12:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chriseidhof/5429ec66ae5161d5998aa4ab960998c0 to your computer and use it in GitHub Desktop.
Save chriseidhof/5429ec66ae5161d5998aa4ab960998c0 to your computer and use it in GitHub Desktop.
//
// ContentView.swift
// KeyFrameAnimation
//
// Created by Chris Eidhof on 21.10.19.
// Copyright © 2019 objc.io. All rights reserved.
//
import SwiftUI
extension CGSize {
static func *(lhs: CGSize, rhs: CGFloat) -> CGSize {
return CGSize(width: lhs.width * rhs, height: lhs.height * rhs)
}
}
extension VectorArithmetic {
func scaled(by amount: Double) -> Self {
var result = self
result.scale(by: amount)
return result
}
}
extension CGSize: VectorArithmetic {
public static func -= (lhs: inout CGSize, rhs: CGSize) {
lhs = lhs - rhs
}
public static func - (lhs: CGSize, rhs: CGSize) -> CGSize {
CGSize(width: lhs.width - rhs.width, height: lhs.height - rhs.height)
}
public static func += (lhs: inout CGSize, rhs: CGSize) {
lhs = lhs + rhs
}
public mutating func scale(by rhs: Double) {
width *= CGFloat(rhs)
height *= CGFloat(rhs)
}
public var magnitudeSquared: Double {
Double((width*width) + (height*height))
}
public static func + (lhs: CGSize, rhs: CGSize) -> CGSize {
return CGSize(width: lhs.width + rhs.width, height: lhs.height + rhs.height)
}
}
struct Keyframed<D: VectorArithmetic> {
var start: D
var keyframes: [(position: Double, value: D)] = []
var end: D
func value(position: Double) -> D {
if position >= 1 { return end }
var lastValue = start
var lastPosition: Double = 0
var frames = keyframes
frames.append((1, end))
for frame in frames {
if position < frame.position {
let amount = (position - lastPosition) / (frame.position - lastPosition)
return lastValue + (frame.value - lastValue).scaled(by: amount)
} else {
lastValue = frame.value
lastPosition = frame.position
}
}
return end
}
}
struct KeyframeAnimation: AnimatableModifier {
var progress: Double = 0
var values = Keyframed<CGSize>(start: .zero, keyframes: [(position: 0.5, value: CGSize(width: 100, height: 0))], end: CGSize(width: 100, height: 100))
var animatableData: Double {
get { progress }
set { progress = newValue }
}
func body(content: Content) -> some View {
let offset = values.value(position: progress)
print(progress, offset)
return content.offset(offset)
}
}
struct ContentView: View {
@State var progress: Double = 0
var body: some View {
Text("Hello World")
.modifier(KeyframeAnimation(progress: progress))
.animation(Animation.default.speed(0.2))
.onAppear { self.progress = 1 }
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment