Skip to content
This repository has been archived by the owner on Aug 13, 2021. It is now read-only.

Commit

Permalink
Merge branch 'release-candidate' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Verkoeyen committed May 19, 2017
2 parents a76ad74 + a02f525 commit 47d2f30
Show file tree
Hide file tree
Showing 102 changed files with 2,004 additions and 1,011 deletions.
4 changes: 2 additions & 2 deletions .jazzy.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
module: MaterialMotion
module_version: 1.3.0
module_version: 2.0.0
sdk: iphonesimulator
xcodebuild_arguments:
- -workspace
- MaterialMotion.xcworkspace
- -scheme
- MaterialMotion
github_url: https://github.com/material-motion/material-motion-swift
github_file_prefix: https://github.com/material-motion/material-motion-swift/tree/v1.3.0
github_file_prefix: https://github.com/material-motion/material-motion-swift/tree/v2.0.0
328 changes: 328 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions MaterialMotion.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "MaterialMotion"
s.summary = "Reactive motion driven by Core Animation."
s.version = "1.3.0"
s.version = "2.0.0"
s.authors = "The Material Motion Authors"
s.license = "Apache 2.0"
s.homepage = "https://github.com/material-motion/material-motion-swift"
Expand All @@ -11,5 +11,5 @@ Pod::Spec.new do |s|

s.source_files = "src/**/*.{swift}"

s.dependency "IndefiniteObservable", "~> 3.0"
s.dependency "IndefiniteObservable", "~> 4.0"
end
20 changes: 10 additions & 10 deletions Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
PODS:
- CatalogByConvention (2.0.0)
- IndefiniteObservable (3.1.0):
- IndefiniteObservable/lib (= 3.1.0)
- IndefiniteObservable/lib (3.1.0)
- MaterialMotion (1.3.0):
- IndefiniteObservable (~> 3.0)
- CatalogByConvention (2.1.0)
- IndefiniteObservable (4.0.0):
- IndefiniteObservable/lib (= 4.0.0)
- IndefiniteObservable/lib (4.0.0)
- MaterialMotion (2.0.0):
- IndefiniteObservable (~> 4.0)

DEPENDENCIES:
- CatalogByConvention
Expand All @@ -15,10 +15,10 @@ EXTERNAL SOURCES:
:path: "./"

SPEC CHECKSUMS:
CatalogByConvention: be55c2263132e4f9f59299ac8a528ee8715b3275
IndefiniteObservable: 2789d61f487d8d37fa2b9c3153cc44d4447ff744
MaterialMotion: b5040104b109cf9680a2c4a77296c429dab2c376
CatalogByConvention: ef0913973b86b4234bcadf22aa84037c4a47cbbd
IndefiniteObservable: 1ee6af37efa8763a222cc6d414cd125e26ed9b6a
MaterialMotion: a412b109cfe4ab7b1fd956409a5da9a3635d3dce

PODFILE CHECKSUM: f503265a0d60526a0d28c96dd4bdcfb40fb562fc

COCOAPODS: 1.2.0
COCOAPODS: 1.2.1
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/MaterialMotion.svg)](https://cocoapods.org/pods/MaterialMotion)
[![Platform](https://img.shields.io/cocoapods/p/MaterialMotion.svg)](http://cocoadocs.org/docsets/MaterialMotion)
[![Docs](https://img.shields.io/cocoapods/metrics/doc-percent/MaterialMotion.svg)](http://cocoadocs.org/docsets/MaterialMotion)
[![Chat](https://img.shields.io/discord/198544450366996480.svg)](https://discord.gg/material-motion)

This library includes a variety of ready-to-use **interactions**. Interactions are registered to an
instance of `MotionRuntime`:
Expand Down
31 changes: 13 additions & 18 deletions examples/CarouselExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import MaterialMotion

class CarouselExampleViewController: ExampleViewController, UIScrollViewDelegate {

var runtime: MotionRuntime!
let delegate = ReactiveScrollViewDelegate()
override func viewDidLoad() {
super.viewDidLoad()

Expand All @@ -29,10 +29,10 @@ class CarouselExampleViewController: ExampleViewController, UIScrollViewDelegate
scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
scrollView.isPagingEnabled = true
scrollView.contentSize = .init(width: view.bounds.size.width * 3, height: view.bounds.size.height)
scrollView.delegate = self
scrollView.delegate = delegate
view.addSubview(scrollView)

pager = UIPageControl()
let pager = UIPageControl()
let size = pager.sizeThatFits(view.bounds.size)
pager.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
pager.frame = .init(x: 0, y: view.bounds.height - size.height - 20, width: view.bounds.width, height: size.height)
Expand All @@ -45,9 +45,6 @@ class CarouselExampleViewController: ExampleViewController, UIScrollViewDelegate
(title: "Page 3", description: "Page 3 description", color: .secondaryColor),
]

runtime = MotionRuntime(containerView: view)

let stream = runtime.get(scrollView)
for (index, data) in datas.enumerated() {
let page = CarouselPage(frame: view.bounds)
page.frame.origin.x = CGFloat(index) * view.bounds.width
Expand All @@ -56,21 +53,19 @@ class CarouselExampleViewController: ExampleViewController, UIScrollViewDelegate
page.iconView.backgroundColor = data.color
scrollView.addSubview(page)

let pageEdge = stream.x().offset(by: -page.frame.origin.x)
let pageEdge = delegate.x().offset(by: -page.frame.origin.x)

runtime.connect(pageEdge.rewriteRange(start: 0, end: 128,
destinationStart: 1, destinationEnd: 0),
to: runtime.get(page).alpha)
runtime.connect(pageEdge.rewriteRange(start: -view.bounds.width, end: 0,
destinationStart: 0.5, destinationEnd: 1.0),
to: runtime.get(page.layer).scale)
pageEdge.rewriteRange(start: 0, end: 128, destinationStart: 1, destinationEnd: 0).subscribeToValue {
page.alpha = $0
}
pageEdge.rewriteRange(start: -view.bounds.width, end: 0, destinationStart: 0.5, destinationEnd: 1.0).subscribeToValue {
page.layer.transform = CATransform3DMakeScale($0, $0, 1)
}
}
}

var pager: UIPageControl!

func scrollViewDidScroll(_ scrollView: UIScrollView) {
pager.currentPage = Int((scrollView.contentOffset.x + scrollView.bounds.width / 2) / scrollView.bounds.width)
delegate.x().offset(by: scrollView.bounds.width / 2).scaled(by: 1 / scrollView.bounds.width).subscribeToValue {
pager.currentPage = Int($0)
}
}

override func exampleInformation() -> ExampleInfo {
Expand Down
15 changes: 8 additions & 7 deletions examples/ContextualTransitionExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class PhotoAlbumViewController: UIViewController, UICollectionViewDataSource, UI

super.init(nibName: nil, bundle: nil)

transitionController.transitionType = PushBackTransition.self
transitionController.transition = PushBackTransition()
}

required init?(coder aDecoder: NSCoder) {
Expand Down Expand Up @@ -202,11 +202,10 @@ class PhotoAlbumViewController: UIViewController, UICollectionViewDataSource, UI

view.addSubview(collectionView)

let dismisser = transitionController.dismisser
dismisser.disableSimultaneousRecognition(of: collectionView.panGestureRecognizer)
transitionController.disableSimultaneousRecognition(of: collectionView.panGestureRecognizer)

for gesture in [UIPanGestureRecognizer(), UIPinchGestureRecognizer(), UIRotationGestureRecognizer()] {
dismisser.dismissWhenGestureRecognizerBegins(gesture)
transitionController.dismissWhenGestureRecognizerBegins(gesture)
view.addGestureRecognizer(gesture)
}
}
Expand All @@ -227,6 +226,10 @@ class PhotoAlbumViewController: UIViewController, UICollectionViewDataSource, UI
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false)
}

override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return album.photos.count
}
Expand Down Expand Up @@ -255,8 +258,6 @@ class PhotoAlbumViewController: UIViewController, UICollectionViewDataSource, UI

private class PushBackTransition: Transition {

required init() {}

func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] {
let foreVC = ctx.fore as! PhotoAlbumViewController
let foreImageView = (foreVC.collectionView.cellForItem(at: foreVC.indexPathForCurrentPhoto()) as! PhotoCollectionViewCell).imageView
Expand All @@ -282,7 +283,7 @@ private class PushBackTransition: Transition {

let size = TransitionSpring(back: contextView.bounds.size, fore: fitSize, direction: ctx.direction)
runtime.toggle(size, inReactionTo: draggable)
runtime.add(size, to: runtime.get(replicaView).reactiveLayer.size)
runtime.add(size, to: runtime.get(replicaView).layer.size)

let opacity = TransitionSpring<CGFloat>(back: 0, fore: 1, direction: ctx.direction)
runtime.add(opacity, to: runtime.get(ctx.fore.view.layer).opacity)
Expand Down
13 changes: 6 additions & 7 deletions examples/FabTransitionExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class FabTransitionExampleViewController: ExampleViewController, TransitionConte

func didTap() {
let vc = ModalViewController()
vc.transitionController.transitionType = CircularRevealTransition.self
vc.transitionController.transition = CircularRevealTransition()
present(vc, animated: true)
}

Expand Down Expand Up @@ -76,18 +76,17 @@ private class ModalViewController: UIViewController {

let floodFillOvershootRatio: CGFloat = 1.2

private class CircularRevealTransition: Transition {
private class CircularRevealTransition: TransitionWithTermination {

// TODO: Support for transient views.
var floodFillView: UIView!
var foreViewLayer: CALayer!
deinit {

func didEndTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) {
floodFillView.removeFromSuperview()
foreViewLayer.mask = nil
}

required init() {}

func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] {
foreViewLayer = ctx.fore.view.layer

Expand Down Expand Up @@ -124,14 +123,14 @@ private class CircularRevealTransition: Transition {
let foreShadowPath = CGRect(origin: .zero(), size: expandedSize)
let shadowPath = tween(back: floodFillView.layer.shadowPath!, fore: UIBezierPath(ovalIn: foreShadowPath).cgPath, ctx: ctx)

let floodLayer = runtime.get(floodFillView).reactiveLayer
let floodLayer = runtime.get(floodFillView).layer
runtime.add(expansion, to: floodLayer.size)
runtime.add(fadeOut, to: floodLayer.opacity)
runtime.add(radius, to: floodLayer.cornerRadius)
runtime.add(shadowPath, to: floodLayer.shadowPath)

let shiftIn = tween(back: ctx.fore.view.layer.position.y + 40, fore: ctx.fore.view.layer.position.y, ctx: ctx)
runtime.add(shiftIn, to: runtime.get(ctx.fore.view).reactiveLayer.positionY)
runtime.add(shiftIn, to: runtime.get(ctx.fore.view).layer.positionY)

let maskShiftIn = tween(back: CGFloat(-40), fore: CGFloat(0), ctx: ctx)
runtime.add(maskShiftIn, to: runtime.get(maskLayer).positionY)
Expand Down
4 changes: 1 addition & 3 deletions examples/HowToMakeACustomOperatorExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ class HowToMakeACustomOperatorExampleViewController: ExampleViewController {
extension MotionObservableConvertible where T == CGPoint {

fileprivate func wobble(width: CGFloat) -> MotionObservable<CGPoint> {
return _map(#function) {
.init(x: $0.x + sin($0.y / 50) * width, y: $0.y)
}
return _map { .init(x: $0.x + sin($0.y / 50) * width, y: $0.y) }
}
}
12 changes: 7 additions & 5 deletions examples/InteractivePushBackTransitionExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private class ModalViewController: UIViewController, UIGestureRecognizerDelegate
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

transitionController.transitionType = PushBackTransition.self
transitionController.transition = PushBackTransition()
}

required init?(coder aDecoder: NSCoder) {
Expand All @@ -59,17 +59,19 @@ private class ModalViewController: UIViewController, UIGestureRecognizerDelegate
view.addSubview(scrollView)

let pan = UIPanGestureRecognizer()
pan.delegate = transitionController.dismisser.topEdgeDismisserDelegate(for: scrollView)
transitionController.dismisser.dismissWhenGestureRecognizerBegins(pan)
pan.delegate = transitionController.topEdgeDismisserDelegate(for: scrollView)
transitionController.dismissWhenGestureRecognizerBegins(pan)
scrollView.panGestureRecognizer.require(toFail: pan)
view.addGestureRecognizer(pan)
}

override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}

private class PushBackTransition: Transition {

required init() {}

func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] {
let draggable = Draggable(withFirstGestureIn: ctx.gestureRecognizers)

Expand Down
2 changes: 1 addition & 1 deletion examples/MaterialExpansionExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class MaterialExpansionExampleViewController: ExampleViewController {
let floodExpansion = Tween<CGFloat>(duration: 0.375, values: [0, 1])
floodExpansion.timingFunctions.value = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)]
let fadeOut = Tween<CGFloat>(duration: 0.375, values: [0.75, 0])
fadeOut.keyPositions.value = [0.2, 1]
fadeOut.offsets.value = [0.2, 1]

runtime.add(SetPositionOnTap(.withExistingRecognizer(tap.gestureRecognizer)),
to: runtime.get(flood.layer).position)
Expand Down
61 changes: 39 additions & 22 deletions examples/ModalDialogExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ class ModalDialogViewController: UIViewController {
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

transitionController.transitionType = ModalDialogTransition.self

modalPresentationStyle = .overCurrentContext
transitionController.transition = ModalDialogTransition()
}

required init?(coder aDecoder: NSCoder) {
Expand All @@ -64,44 +62,48 @@ class ModalDialogViewController: UIViewController {
view.layer.shadowRadius = 5
view.layer.shadowOpacity = 1
view.layer.shadowOffset = .init(width: 0, height: 2)

preferredContentSize = .init(width: 200, height: 200)
}
}

class ModalDialogTransition: SelfDismissingTransition {
class ModalDialogTransition: SelfDismissingTransition, TransitionWithPresentation {

required init() {}
public func defaultModalPresentationStyle() -> UIModalPresentationStyle? {
return .custom
}

func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] {
let size = ctx.fore.preferredContentSize
public func presentationController(forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController) -> UIPresentationController? {
return ModalDialogPresentationController(presentedViewController: presented,
presenting: presenting)
}

if ctx.direction == .forward {
ctx.fore.view.bounds = CGRect(origin: .zero, size: size)
}

func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] {
let size = ctx.fore.view.frame.size
let bounds = ctx.containerView().bounds
let backPosition = CGPoint(x: bounds.midX, y: bounds.maxY + size.height * 3 / 4)
let forePosition = CGPoint(x: bounds.midX, y: bounds.midY)
let forePosition = ctx.fore.view.layer.position

let reactiveForeLayer = runtime.get(ctx.fore.view.layer)
let position = reactiveForeLayer.position

let draggable = Draggable(withFirstGestureIn: ctx.gestureRecognizers)

let gesture = runtime.get(draggable.nextGestureRecognizer)
let centerY = ctx.containerView().bounds.height / 2.0

runtime.add(ChangeDirection(withVelocityOf: draggable.nextGestureRecognizer, whenNegative: .forward),
to: ctx.direction)

runtime.connect(gesture
.velocityOnReleaseStream()
.y()
.thresholdRange(min: -100, max: 100)
.rewrite([.within: position.y().threshold(centerY).rewrite([.below: .forward,
.above: .backward])]),
to: ctx.direction)
if let gesture = draggable.nextGestureRecognizer {
runtime.connect(runtime.get(gesture)
.velocityOnReleaseStream()
.y()
.thresholdRange(min: -100, max: 100)
.rewrite([.within: position.y().threshold(centerY).rewrite([.below: .forward,
.above: .backward])]),
to: ctx.direction)
}

let movement = TransitionSpring(back: backPosition,
fore: forePosition,
Expand All @@ -112,7 +114,7 @@ class ModalDialogTransition: SelfDismissingTransition {
return [tossable.spring]
}

static func willPresent(fore: UIViewController, dismisser: ViewControllerDismisser) {
func willPresent(fore: UIViewController, dismisser: ViewControllerDismisser) {
let tap = UITapGestureRecognizer()
fore.view.addGestureRecognizer(tap)
dismisser.dismissWhenGestureRecognizerBegins(tap)
Expand All @@ -121,3 +123,18 @@ class ModalDialogTransition: SelfDismissingTransition {
dismisser.dismissWhenGestureRecognizerBegins(pan)
}
}

private final class ModalDialogPresentationController: UIPresentationController {

override var frameOfPresentedViewInContainerView: CGRect {
guard let containerView = containerView else {
assertionFailure("Missing container view during frame query.")
return .zero()
}
let size = CGSize(width: 200, height: 200)
return CGRect(x: containerView.bounds.midX - size.width / 2,
y: containerView.bounds.midY - size.height / 2,
width: size.width,
height: size.height)
}
}
Loading

0 comments on commit 47d2f30

Please sign in to comment.