blob: 236fec5e1cef0fba54463f28f3d3ba86fe17965e [file] [log] [blame] [edit]
/*
Copyright 2017-present The Material Motion Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
import MotionInterchange
let materialEaseInEaseOut = MotionCurveMakeBezier(p1x: 0.4, p1y: 0.0, p2x: 0.2, p2y: 1.0)
// This demo shows how one might use a motion spec structure to define timing for a multi-state
// animation such as the Material "masked transition" motion.
// Our motion specification. Each row of the spec defines strict timing for some part of the
// animation.
class MaterialMaskedTransitionMotion: AnimationConfigurator {
init(floodColorTransformation: MotionTiming, maskTransformation: MotionTiming) {
self.floodColorTransformation = floodColorTransformation
self.maskTransformation = maskTransformation
}
func timing(forProperty property: String) -> MotionTiming {
switch property {
case "backgroundColor": return floodColorTransformation
case "position": return maskTransformation
case "cornerRadius": return maskTransformation
case "size": return maskTransformation
default:
assertionFailure("Unknown key")
return MotionTimingNone
}
}
let floodColorTransformation: MotionTiming
let maskTransformation: MotionTiming
}
// The motion spec for card expansion.
let cardExpansion = MaterialMaskedTransitionMotion(
floodColorTransformation: .init(
delay: 0.075,
duration: 0.075,
curve: materialEaseInEaseOut
),
maskTransformation: .init(
delay: 0.045,
duration: 0.255,
curve: materialEaseInEaseOut
)
)
// The motion spec for card collapse.
let cardCollapse = MaterialMaskedTransitionMotion(
floodColorTransformation: .init(
delay: 0.060,
duration: 0.150,
curve: materialEaseInEaseOut
),
maskTransformation: .init(
delay: 0.000,
duration: 0.180,
curve: materialEaseInEaseOut
)
)
class SimpleAnimationExampleViewController: ExampleViewController {
var button: UIButton!
var isOpen = false
func didTap() {
isOpen = !isOpen
button.animator.animate(toState: isOpen ? "open" : "closed") { didComplete in
print("Done \(didComplete)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton(type: .custom)
button.backgroundColor = .primaryColor
button.bounds = CGRect(origin: .zero, size: .init(width: 64, height: 64))
button.center = .init(x: view.bounds.width / 2,
y: view.bounds.height - button.bounds.height - 32)
button.layer.cornerRadius = button.bounds.width / 2
view.addSubview(button)
button.animator.states["open"] = [
"backgroundColor": UIColor.secondaryColor,
"cornerRadius": 0,
"size": CGSize(width: 128, height: 128),
"position": CGPoint(x: view.bounds.width / 2, y: view.bounds.height - 64 - 64)
]
button.animator.states["closed"] = [
"backgroundColor": UIColor.primaryColor,
"cornerRadius": 32,
"size": CGSize(width: 64, height: 64),
"position": CGPoint(x: view.bounds.width / 2, y: view.bounds.height - 64 - 32)
]
button.animator.configurationForState["open"] = cardExpansion
button.animator.configurationForState["closed"] = cardCollapse
let tap = UITapGestureRecognizer(target: self, action: #selector(didTap))
view.addGestureRecognizer(tap)
}
override func exampleInformation() -> ExampleInfo {
return .init(title: type(of: self).catalogBreadcrumbs().last!,
instructions: "Tap to present a modal transition.")
}
}