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

Commit 6948ea5

Browse files
author
Jeff Verkoeyen
committed
Merge branch 'release-candidate' into stable
2 parents e6dfc04 + 9ab5921 commit 6948ea5

26 files changed

+595
-69
lines changed

.jazzy.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
module: MaterialMotion
2-
module_version: 1.2.1
2+
module_version: 1.3.0
33
sdk: iphonesimulator
44
xcodebuild_arguments:
55
- -workspace
66
- MaterialMotion.xcworkspace
77
- -scheme
88
- MaterialMotion
99
github_url: https://github.com/material-motion/material-motion-swift
10-
github_file_prefix: https://github.com/material-motion/material-motion-swift/tree/v1.2.1
10+
github_file_prefix: https://github.com/material-motion/material-motion-swift/tree/v1.3.0

CHANGELOG.md

Lines changed: 199 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,200 @@
1+
# 1.3.0
2+
3+
Highlights:
4+
5+
- First contribution from [Eric Tang](https://github.com/randcode-generator) adding support for `DispatchTimeInterval` initialization of time-based interactions and operators.
6+
- New visualization tools for streams.
7+
- All gestural interactions can now be reactively enabled and disabled.
8+
- Transitions APIs are evolving as we begin work on [components](https://github.com/material-motion/material-motion-components-swift). View the [roadmap](https://material-motion.github.io/material-motion/roadmap/core-team) for more details.
9+
10+
## Behavioral changes
11+
12+
`defaultTransitionSpringTension` and `defaultTransitionSpringFriction`'s values have been swapped to match the actual default values for tension and friction. These values were previously incorrectly reversed.
13+
14+
• Operators that do not support Core Animation will no longer throw runtime assertions when receiving Core Animation events. We have an [open issue](https://github.com/material-motion/material-motion-swift/issues/41) to explore nicer handling of operators and properties that do not support Core Animation.
15+
16+
## New features
17+
18+
### Runtime
19+
20+
• MotionRuntime now allows you to retrieve interactions associated with a given target with the new `interactions(for:filter:)` API.
21+
22+
Example usage:
23+
24+
```swift
25+
let draggables = runtime.interactions(for: view) { $0 as? Draggable }
26+
```
27+
28+
### Interactions
29+
30+
`PathTween`, `Tween`, `TransitionTween` each have a new convenience initializer that accepts the `DispatchTimeInterval` enum, making it possible to specify explicit time units. Contributed by [Eric Tang](https://github.com/randcode-generator).
31+
32+
Example usage:
33+
34+
```swift
35+
let tween = Tween<CGFloat>(duration: .milliseconds(300), values: [1, 0])
36+
```
37+
38+
`Draggable`, `Rotatable`, `Scalable`, and `DirectlyManipulable` now all conform to the `Togglable` type, meaning they can be reactively enabled and disabled.
39+
40+
Example usage:
41+
42+
```swift
43+
draggable.enabled.value = false // Disables the interaction
44+
```
45+
46+
### Operators
47+
48+
`delay(by:)` now accepts a `DispatchTimeInterval` enum, making it possible to specify explicit time units. Contributed by [Eric Tang](https://github.com/randcode-generator).
49+
50+
```swift
51+
let delayedStream = stream.delay(by: .seconds(1))
52+
```
53+
54+
`toString()` transforms any stream into a string representation. This is part of our [Reactive Controls milestone](https://github.com/material-motion/material-motion-swift/milestone/2).
55+
56+
```swift
57+
let stringStream = stream.toStream()
58+
```
59+
60+
`visualize(in:)` allows you to display a stream's values and changes in your app with a new visualization overlay that appears atop your runtime's container view.
61+
62+
Example usage:
63+
64+
```swift
65+
runtime.add(tossable, to: view) { $0.visualize(in: runtime.visualizationView) }
66+
```
67+
68+
![](assets/visualize-operator.gif)
69+
70+
## API changes
71+
72+
### Runtime
73+
74+
• MotionRuntime's `add` method now requires that targets conform to AnyObject. This will not affect any of the existing Interactions included with Material Motion. What this change means is that you can no longer build interactions that target non-object types.
75+
76+
### Transitions
77+
78+
• TransitionController is now a pure Swift class type. This means TransitionController is no longer visible to Objective-C code. See https://github.com/material-motion/material-motion-swift/issues/108 for our discussion on Objective-C support.
79+
80+
`TransitionController` now exposes a `transitioningDelegate` property. `TransitionController` no longer conforms to `UIViewControllerTransitioningDelegate`.
81+
82+
```swift
83+
// Before
84+
viewController.transitioningDelegate = viewController.transitionController
85+
86+
// After
87+
viewController.transitioningDelegate = viewController.transitionController.transitioningDelegate
88+
```
89+
90+
## Source changes
91+
92+
* [Added convenience constructor that takes DispatchTimeInterval for duration (#107)](https://github.com/material-motion/material-motion-swift/commit/ab44321b3906998a72a3a6b544061441179331dd) (Eric Tang)
93+
* [Make ViewControllerDismisser a pure Swift class.](https://github.com/material-motion/material-motion-swift/commit/c0c67c3ffbcc791bf8295b7ddc5ef5c55fe9caa1) (Jeff Verkoeyen)
94+
* [Make TransitionController a pure Swift class.](https://github.com/material-motion/material-motion-swift/commit/d49e2807a43bcb91063f0bd42f77ba820dd3262e) (Jeff Verkoeyen)
95+
* [Add runtime.interactions(for:) API for fetching interactions associated with a given target.](https://github.com/material-motion/material-motion-swift/commit/a34f9942111b9d958efb9c9da01b2722fbf063ec) (Jeff Verkoeyen)
96+
* [Properly compare visualize's label text against the prefixed value string.](https://github.com/material-motion/material-motion-swift/commit/39a23b8866162925f36e5e3059f8ef9d7cd4a1c6) (Jeff Verkoeyen)
97+
* [Add visualize operator and remove runtime.visualize.](https://github.com/material-motion/material-motion-swift/commit/1d0b055bc3de355bbf6fd9e41fb8ea80aa4a56e1) (Jeff Verkoeyen)
98+
* [Make all gestural interactions conform to Togglable.](https://github.com/material-motion/material-motion-swift/commit/e9a0b9b7965c4ba5a0abc8244caa5c73ce125d27) (Jeff Verkoeyen)
99+
* [Use a reasonable fallback when adding visualization views to the runtime container view.](https://github.com/material-motion/material-motion-swift/commit/2e5cf23a5caf67b6ffd6530c7a897c075c695d11) (Jeff Verkoeyen)
100+
* [Add runtime.visualize for visualizing values emitted by streams.](https://github.com/material-motion/material-motion-swift/commit/688644a9a4545bed72cebae66d514a26e71f0cb9) (Jeff Verkoeyen)
101+
* [Remove runtime assertion when core animation events are sent to operators that don't support them.](https://github.com/material-motion/material-motion-swift/commit/b4854cb30e714f88fbfa56b3ef8deeb2174a90fc) (Jeff Verkoeyen)
102+
* [Add toString operator.](https://github.com/material-motion/material-motion-swift/commit/e26425df855d806789c75962d41a0da0a7d84c5e) (Jeff Verkoeyen)
103+
* [Swap the default transition tension/friction values to match the proper variable names.](https://github.com/material-motion/material-motion-swift/commit/11d8ef6bf4b07c8b2902743a41ce8a0cc93f13d1) (Jeff Verkoeyen)
104+
105+
## API changes
106+
107+
Auto-generated by running:
108+
109+
apidiff origin/stable release-candidate swift MaterialMotion.xcworkspace MaterialMotion
110+
111+
### MotionRuntime
112+
113+
*new* method: `interactions(for:filter:)` in `MotionRuntime`
114+
115+
*modified* method: `add(_:to:constraints:)` in `MotionRuntime`: targets must now conform to AnyObject.
116+
117+
*new* var: `visualizationView` in `MotionRuntime`
118+
119+
### New operators
120+
121+
*new* method: `delay(by:)` in `MotionObservableConvertible`
122+
123+
*new* method: `toString()` in `MotionObservableConvertible`
124+
125+
*new* method: `visualize(_:in:)` in `MotionObservableConvertible`
126+
127+
### Interactions
128+
129+
#### DirectlyManipulable
130+
131+
*modified* class: `DirectlyManipulable`
132+
133+
| Type of change: | Declaration |
134+
|---|---|
135+
| From: | `public final class DirectlyManipulable : NSObject, Interaction, Stateful` |
136+
| To: | `public final class DirectlyManipulable : NSObject, Interaction, Togglable, Stateful` |
137+
138+
#### Draggable
139+
140+
*modified* class: `Draggable`
141+
142+
| Type of change: | Declaration |
143+
|---|---|
144+
| From: | `public final class Draggable : Gesturable<UIPanGestureRecognizer>, Interaction, Stateful` |
145+
| To: | `public final class Draggable : Gesturable<UIPanGestureRecognizer>, Interaction, Togglable, Stateful` |
146+
147+
#### Gesturable
148+
149+
*new* var: `enabled` in `Gesturable`
150+
151+
#### PathTween
152+
153+
*new* method: `init(duration:path:system:timeline:)` in `PathTween`
154+
155+
#### Rotatable
156+
157+
*modified* class: `Rotatable`
158+
159+
| Type of change: | Declaration |
160+
|---|---|
161+
| From: | `public final class Rotatable : Gesturable<UIRotationGestureRecognizer>, Interaction, Stateful` |
162+
| To: | `public final class Rotatable : Gesturable<UIRotationGestureRecognizer>, Interaction, Togglable, Stateful` |
163+
164+
#### Scalable
165+
166+
*modified* class: `Scalable`
167+
168+
| Type of change: | Declaration |
169+
|---|---|
170+
| From: | `public final class Scalable : Gesturable<UIPinchGestureRecognizer>, Interaction, Stateful` |
171+
| To: | `public final class Scalable : Gesturable<UIPinchGestureRecognizer>, Interaction, Togglable, Stateful` |
172+
173+
#### Tween
174+
175+
*new* method: `init(duration:values:system:timeline:)` in `Tween`
176+
177+
#### TransitionTween
178+
179+
*new* method: `init(duration:forwardValues:direction:forwardKeyPositions:system:timeline:)` in `TransitionTween`
180+
181+
### Transitions
182+
183+
#### TransitionController
184+
185+
*modified* class: `TransitionController`
186+
187+
| Type of change: | Declaration |
188+
|---|---|
189+
| From: | `public final class TransitionController : NSObject` |
190+
| To: | `public final class TransitionController` |
191+
192+
*new* var: `transitioningDelegate` in `TransitionController`
193+
194+
#### ViewControllerDismisser
195+
196+
*new* var: `gestureRecognizers` in `ViewControllerDismisser`
197+
1198
# 1.2.1
2199

3200
This is a patch release resolving a crashing bug when `runtime.shouldVisualizeMotion` was enabled and an `ArcMove` interaction was added to a view without a parent.
@@ -14,9 +211,9 @@ This minor release introduces a new operator, `startWith`, which is meant to rep
14211

15212
### startWith operator
16213

17-
The new `startWith` operator replaces `initialValue` and behaves slightly differently: `startWith` returns a [memory stream](https://github.com/staltz/xstream#memorystream), which is a stream that stores the last value it received and emits it upon subscription. What this means is that the provided initial value will only be emitted once once, ever, and that the resulting stream is guaranteed to emit a value on subscription.
214+
The new `startWith` operator replaces `initialValue` and behaves slightly differently: `startWith` returns a [memory stream](https://github.com/staltz/xstream#memorystream), which is a stream that stores the last value it received and emits it upon subscription. What this means is that the provided initial value will only be emitted once, ever, and that the resulting stream is guaranteed to emit a value on subscription.
18215

19-
You can use startWith to turn a stream that may not initially emit values (like a gesture stream) and prime it with an initial value. For example, we use startWith in the "How to use reactive constraints" example in order to ensure that our axis line property is primed with a value.
216+
You can use startWith to take a stream that may not initially emit values (like a gesture stream) and prime it with an initial value. For example, we use startWith in the "How to use reactive constraints" example in order to ensure that our axis line property is primed with a value.
20217

21218
<img src="assets/constraints.gif" />
22219

MaterialMotion.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22
s.name = "MaterialMotion"
33
s.summary = "Reactive motion driven by Core Animation."
4-
s.version = "1.2.1"
4+
s.version = "1.3.0"
55
s.authors = "The Material Motion Authors"
66
s.license = "Apache 2.0"
77
s.homepage = "https://github.com/material-motion/material-motion-swift"

Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ PODS:
33
- IndefiniteObservable (3.1.0):
44
- IndefiniteObservable/lib (= 3.1.0)
55
- IndefiniteObservable/lib (3.1.0)
6-
- MaterialMotion (1.2.1):
6+
- MaterialMotion (1.3.0):
77
- IndefiniteObservable (~> 3.0)
88

99
DEPENDENCIES:
@@ -17,7 +17,7 @@ EXTERNAL SOURCES:
1717
SPEC CHECKSUMS:
1818
CatalogByConvention: be55c2263132e4f9f59299ac8a528ee8715b3275
1919
IndefiniteObservable: 2789d61f487d8d37fa2b9c3153cc44d4447ff744
20-
MaterialMotion: 599cd0743c60cdb62d7bae2b25bebbc77f6cd9b5
20+
MaterialMotion: b5040104b109cf9680a2c4a77296c429dab2c376
2121

2222
PODFILE CHECKSUM: f503265a0d60526a0d28c96dd4bdcfb40fb562fc
2323

assets/visualize-operator.gif

792 KB
Loading

examples/apps/Catalog/ReactivePlayground.playground/Pages/Visualizing the runtime.xcplaygroundpage/Contents.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
## Visualizing the runtime
33

44
The motion runtime represents all of its interactions as **connected streams**, making it possible to visualize the internal state of the runtime as a directed graph. Use `runtime.asGraphviz()` to get a graphviz-compatible string for visualizing the runtime.
5-
5+
66
In this page we'll use webgraphviz.com to visualize the runtime in our playground in real time.
77
*/
88
import MaterialMotion

src/MotionRuntime.swift

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ import IndefiniteObservable
3232
*/
3333
public final class MotionRuntime {
3434

35+
deinit {
36+
_visualizationView?.removeFromSuperview()
37+
}
38+
3539
/**
3640
Creates a motion runtime instance with the provided container view.
3741
*/
@@ -60,9 +64,28 @@ public final class MotionRuntime {
6064
Invokes the interaction's add method and stores the interaction instance for the lifetime of the
6165
runtime.
6266
*/
63-
public func add<I: Interaction>(_ interaction: I, to target: I.Target, constraints: I.Constraints? = nil) {
67+
public func add<I: Interaction>(_ interaction: I, to target: I.Target, constraints: I.Constraints? = nil) where I.Target: AnyObject {
6468
interactions.append(interaction)
6569
interaction.add(to: target, withRuntime: self, constraints: constraints)
70+
71+
let identifier = ObjectIdentifier(target)
72+
var targetInteractions = targets[identifier] ?? []
73+
targetInteractions.append(interaction)
74+
targets[identifier] = targetInteractions
75+
}
76+
77+
/**
78+
Returns all interactions added to the given target.
79+
80+
Example usage:
81+
82+
let draggables = runtime.interactions(for: view) { $0 as? Draggable }
83+
*/
84+
public func interactions<I>(for target: I.Target, filter: (Any) -> I?) -> [I] where I: Interaction, I.Target: AnyObject {
85+
guard let interactions = targets[ObjectIdentifier(target)] else {
86+
return []
87+
}
88+
return interactions.flatMap(filter)
6689
}
6790

6891
/**
@@ -99,6 +122,31 @@ public final class MotionRuntime {
99122
write(stream.asStream(), to: property)
100123
}
101124

125+
/**
126+
The view to which visualization elements should be registered.
127+
128+
This view will be added as an overlay to the runtime's container view.
129+
130+
Use this view like so:
131+
132+
runtime.add(tossable, to: view) { $0.visualize(in: runtime.visualizationView) }
133+
*/
134+
public var visualizationView: UIView {
135+
if let visualizationView = _visualizationView {
136+
return visualizationView
137+
}
138+
139+
let view = UIView(frame: .init(x: 0, y: containerView.bounds.maxY, width: containerView.bounds.width, height: 0))
140+
view.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
141+
view.isUserInteractionEnabled = false
142+
view.backgroundColor = UIColor(white: 0, alpha: 0.1)
143+
containerView.addSubview(view)
144+
_visualizationView = view
145+
146+
return view
147+
}
148+
private var _visualizationView: UIView?
149+
102150
// MARK: Reactive object storage
103151

104152
/**
@@ -213,6 +261,7 @@ public final class MotionRuntime {
213261
return reactiveObject
214262
}
215263
private var reactiveObjects: [ObjectIdentifier: AnyObject] = [:]
264+
private var targets: [ObjectIdentifier: [Any]] = [:]
216265

217266
private var metadata: [Metadata] = []
218267
private var subscriptions: [Subscription] = []
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
Copyright 2016-present The Material Motion Authors. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
extension DispatchTimeInterval {
18+
func toSeconds() -> CGFloat {
19+
let seconds: CGFloat
20+
switch self {
21+
case let .seconds(arg):
22+
seconds = CGFloat(arg)
23+
case let .milliseconds(arg):
24+
seconds = CGFloat(arg) / 1000.0
25+
case let .microseconds(arg):
26+
seconds = CGFloat(arg) / 1000000.0
27+
case let .nanoseconds(arg):
28+
seconds = CGFloat(arg) / 1000000000.0
29+
}
30+
return seconds
31+
}
32+
}

0 commit comments

Comments
 (0)