├── .clang-format ├── .codecov.yml ├── .gitignore ├── .jazzy.yaml ├── .kokoro ├── .travis.yml ├── AUTHORS ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Info.plist ├── LICENSE ├── MotionInterchange.podspec ├── MotionInterchange.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── MotionInterchange.xcscheme ├── Podfile ├── Podfile.lock ├── README.md ├── examples ├── apps │ └── Catalog │ │ ├── Catalog │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ │ ├── MotionInterchangeCatalog.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── MotionInterchangeCatalog.xcscheme │ │ │ └── UnitTests.xcscheme │ │ ├── TableOfContents.swift │ │ ├── TestHarness │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ │ └── UnitTests │ │ └── Info.plist └── supplemental │ ├── ExampleViewController.swift │ ├── ExampleViews.swift │ ├── HexColor.swift │ ├── Layout.swift │ └── ModalViewController.swift ├── img └── motion-interchange-banner.gif ├── resources └── Info.plist ├── scripts └── v1_to_v2.sh ├── src ├── CAMediaTimingFunction+MDMTimingCurve.h ├── CAMediaTimingFunction+MDMTimingCurve.m ├── MDMAnimationTraits.h ├── MDMAnimationTraits.m ├── MDMMotionCurve.h ├── MDMMotionCurve.m ├── MDMMotionRepetition.h ├── MDMMotionTiming.h ├── MDMRepetition.h ├── MDMRepetition.m ├── MDMRepetitionOverTime.h ├── MDMRepetitionOverTime.m ├── MDMRepetitionTraits.h ├── MDMSpringTimingCurve.h ├── MDMSpringTimingCurve.m ├── MDMSpringTimingCurveGenerator.h ├── MDMSpringTimingCurveGenerator.m ├── MDMSubclassingRestricted.h ├── MDMTimingCurve.h └── MotionInterchange.h └── tests └── unit ├── CAMediaTimingFunctionTests.swift ├── MDMAnimationTraitsTests.swift ├── MDMLegacyAPITests.swift ├── MDMModalMovementTimingTests.m ├── MDMMotionCurveTests.m ├── MDMMotionCurveTests.swift ├── MDMRepetitionOverTimeTests.swift ├── MDMRepetitionTests.swift └── MDMSpringTimingCurve.swift /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | 3 | AllowShortFunctionsOnASingleLine: Inline 4 | AllowShortIfStatementsOnASingleLine: false 5 | AllowShortLoopsOnASingleLine: false 6 | AlwaysBreakBeforeMultilineStrings: false 7 | BinPackParameters: false 8 | ColumnLimit: 0 9 | IndentWrappedFunctionNames: true 10 | ObjCSpaceBeforeProtocolList: true 11 | PointerBindsToType: false 12 | SortIncludes: true 13 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - "examples/" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | .kokoro-ios-runner 3 | 4 | # Jazzy 5 | docs/ 6 | 7 | # Xcode 8 | # 9 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 10 | 11 | ## Build generated 12 | build/ 13 | DerivedData/ 14 | 15 | ## Various settings 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata/ 25 | 26 | ## Other 27 | *.moved-aside 28 | *.xcuserstate 29 | 30 | ## Obj-C/Swift specific 31 | *.hmap 32 | *.ipa 33 | *.dSYM.zip 34 | *.dSYM 35 | 36 | ## Playgrounds 37 | timeline.xctimeline 38 | playground.xcworkspace 39 | 40 | # Swift Package Manager 41 | # 42 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 43 | # Packages/ 44 | .build/ 45 | 46 | # CocoaPods 47 | # 48 | # We recommend against adding the Pods directory to your .gitignore. However 49 | # you should judge for yourself, the pros and cons are mentioned at: 50 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 51 | # 52 | Pods/ 53 | *.xcworkspace 54 | 55 | # Carthage 56 | # 57 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 58 | # Carthage/Checkouts 59 | 60 | Carthage/Build 61 | 62 | # fastlane 63 | # 64 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 65 | # screenshots whenever they are needed. 66 | # For more information about the recommended setup visit: 67 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 68 | 69 | fastlane/report.xml 70 | fastlane/Preview.html 71 | fastlane/screenshots 72 | fastlane/test_output 73 | .DS_Store 74 | -------------------------------------------------------------------------------- /.jazzy.yaml: -------------------------------------------------------------------------------- 1 | module: MotionInterchange 2 | module_version: 3.0.0 3 | sdk: iphonesimulator 4 | umbrella_header: src/MotionInterchange.h 5 | objc: true 6 | github_url: https://github.com/material-motion/motion-interchange-objc 7 | github_file_prefix: https://github.com/material-motion/motion-interchange-objc/tree/v3.0.0 8 | 9 | -------------------------------------------------------------------------------- /.kokoro: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2017-present The Material Motion Authors. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | # Display commands to stderr. 21 | set -x 22 | 23 | BAZEL_VERSION="0.20.0" 24 | 25 | fix_bazel_imports() { 26 | if [ -z "$KOKORO_BUILD_NUMBER" ]; then 27 | repo_prefix="" 28 | else 29 | repo_prefix="github/repo/" 30 | fi 31 | 32 | # Fixes a bug in bazel where objc_library targets have a _ prefix. 33 | find "${repo_prefix}tests/unit" -type f -name '*.swift' -exec sed -i '' -E "s/import Motion(.+)/import _Motion\1/" {} + || true 34 | stashed_dir=$(pwd) 35 | reset_imports() { 36 | # Undoes our source changes from above. 37 | find "${stashed_dir}/${tests_dir_prefix}tests/unit" -type f -name '*.swift' -exec sed -i '' -E "s/import _Motion(.+)/import Motion\1/" {} + || true 38 | } 39 | trap reset_imports EXIT 40 | } 41 | 42 | run_bazel() { 43 | echo "Running bazel builds..." 44 | 45 | fix_bazel_imports 46 | 47 | if [ -n "$KOKORO_BUILD_NUMBER" ]; then 48 | bazel version 49 | use_bazel.sh "$BAZEL_VERSION" 50 | bazel version 51 | 52 | # Move into our cloned repo 53 | cd github/repo 54 | fi 55 | 56 | # Run against whichever Xcode is currently selected. 57 | selected_xcode_developer_path=$(xcode-select -p) 58 | selected_xcode_contents_path=$(dirname "$selected_xcode_developer_path") 59 | 60 | xcode_version=$(cat "$selected_xcode_contents_path/version.plist" \ 61 | | grep "CFBundleShortVersionString" -A1 \ 62 | | grep string \ 63 | | cut -d'>' -f2 \ 64 | | cut -d'<' -f1) 65 | 66 | bazel clean 67 | bazel test //... --xcode_version $xcode_version --ios_minimum_os=9.0 --ios_multi_cpus=i386,x86_64 --test_output=all 68 | } 69 | 70 | run_bazel 71 | 72 | echo "Success!" 73 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | sudo: false 3 | env: 4 | global: 5 | - LC_CTYPE=en_US.UTF-8 6 | - LANG=en_US.UTF-8 7 | - LANGUAGE=en_US.UTF-8 8 | matrix: 9 | include: 10 | - osx_image: xcode12.2 11 | env: COVERAGE=code_coverage SDK="iphonesimulator14.2" DESTINATION="name=iPhone 6s,OS=11.4" 12 | - osx_image: xcode12.2 13 | env: SDK="iphonesimulator14.2" DESTINATION="name=iPhone 6s,OS=10.3.1" 14 | before_install: 15 | - gem install cocoapods --no-document --quiet 16 | - pod install --repo-update 17 | script: 18 | - set -o pipefail 19 | - xcodebuild test -workspace MotionInterchange.xcworkspace -scheme MotionInterchangeCatalog -sdk "$SDK" -destination "$DESTINATION" -enableCodeCoverage YES ONLY_ACTIVE_ARCH=YES | xcpretty -c; 20 | after_success: 21 | - if [ "$COVERAGE" == "code_coverage" ]; then 22 | bash <(curl -s https://codecov.io/bash); 23 | fi 24 | - bash <(curl -s https://codecov.io/bash) 25 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the list of Motion Timing authors for copyright purposes. 2 | # 3 | # This does not necessarily list everyone who has contributed code, since in 4 | # some cases, their employer may be the copyright holder. To see the full list 5 | # of contributors, see the revision history with git log. 6 | 7 | Google Inc. 8 | and other contributors 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 4.0.1 2 | 3 | This patch release resolves some missed warnings in 4.0.0 and fixes a broken test on iOS 13+14. 4 | 5 | # 4.0.0 6 | 7 | This major release drops official support for Bazel and iOS 9. 8 | 9 | # 3.0.0 10 | 11 | This major release drops official support for iOS 8. 12 | 13 | ## Non-source changes 14 | 15 | * [Drop support for iOS 8 (#43)](https://github.com/material-motion/motion-interchange-objc/commit/31a6c576f752a132206c7b09412bd6a390052b88) (featherless) 16 | * [Remove the xcode_select logic. (#42)](https://github.com/material-motion/motion-interchange-objc/commit/9cd51bc492174aabfa99cd2d4d802f8f58a3239c) (featherless) 17 | 18 | # 2.0.0 19 | 20 | This major release upgrades the bazel dependencies and workspace. This change is breaking for anyone 21 | using bazel to build this library. In order to use this library with bazel, you will also need to 22 | upgrade your workspace versions to match the ones now used in this library's `WORKSPACE` file. 23 | 24 | ## Source changes 25 | 26 | * [Update .travis.yml (#35)](https://github.com/material-motion/motion-interchange-objc/commit/f9891a24b843edc004f86ee86f7477d6327957b1) (featherless) 27 | 28 | ## Non-source changes 29 | 30 | * [Update bazel workspace to latest versions. (#40)](https://github.com/material-motion/motion-interchange-objc/commit/a9a1cab4354ce45d8a4548b28c708455ce93885a) (featherless) 31 | * [Update .kokoro](https://github.com/material-motion/motion-interchange-objc/commit/cfbd73021314ce24b0e0f2d37906b58b128e416c) (featherless) 32 | * [Update .kokoro](https://github.com/material-motion/motion-interchange-objc/commit/7e3af4ac83426ea8da8283211e09c0458ff24b81) (featherless) 33 | * [Update bazel workspace and version to latest (#38)](https://github.com/material-motion/motion-interchange-objc/commit/71aa2e4393574d2b4b5cf55695787b9a662165d1) (featherless) 34 | * [Update .kokoro to build against Xcode 9.1](https://github.com/material-motion/motion-interchange-objc/commit/816f52f4600b311f50dae7ef9aa3b9f9f1fb1b0e) (featherless) 35 | * [Update .travis.yml](https://github.com/material-motion/motion-interchange-objc/commit/ba7e0f0015b83eda35edf0144fb6fa3ebb52a81a) (featherless) 36 | 37 | # 1.6.0 38 | 39 | This patch release introduces a compatibility initializer for creating Objective-C animation traits from C-style motion timings. 40 | 41 | ## Source changes 42 | 43 | * [Add a legacy initializer for animation traits. (#34)](https://github.com/material-motion/motion-interchange-objc/commit/e3321d0e4081de1f3d8edee115af0a9ea2142c48) (featherless) 44 | 45 | ## API changes 46 | 47 | Auto-generated by running: 48 | 49 | apidiff origin/stable release-candidate objc src/MotionInterchange.h 50 | 51 | #### MDMAnimationTraits(Legacy) 52 | 53 | *new* method: `-initWithMotionTiming:` in `MDMAnimationTraits(Legacy)` 54 | 55 | *new* category: `MDMAnimationTraits(Legacy)` 56 | 57 | # 1.5.0 58 | 59 | This minor release introduces new Objective-C APIs for creating and storing animation traits. 60 | 61 | ## New deprecations 62 | 63 | All of the original C-style APIs for animation timing are now informally deprecated. We will remove these APIs in the future. 64 | 65 | ## New features 66 | 67 | New Objective-C APIs for storing animation traits. 68 | 69 | | Old API | New API | Rationale | 70 | |:------- |:-------- |:-----------| 71 | | MotionTiming | AnimationTraits | This structure is intended to describe animations only, not motion in general. | 72 | | MotionCurve | TimingCurve | This brings the API name closer to the similarly-purposed `CAMediaTimingFunction`. MotionCurve could also be easily confused with motion through x/y space rather than through time (e.g. ArcMove), which will be problematic as we start defining paths of motion through space. | 73 | | MotionRepetition | RepetitionTraits | This aligns the naming with AnimationTraits. | 74 | 75 | ## Source changes 76 | 77 | * [Restrict subclassing on all types. (#32)](https://github.com/material-motion/motion-interchange-objc/commit/0530ba355d8af640fd9fd51df137c6aed494f63c) (featherless) 78 | * [Re-introduce v1 APIs. (#33)](https://github.com/material-motion/motion-interchange-objc/commit/4a857a0393d55e01d1b282d12a814cec197111c0) (featherless) 79 | * [Extract the UIKit damping ratio APIs to their own class. (#31)](https://github.com/material-motion/motion-interchange-objc/commit/e9226a45892cf1a3f783232e6e7fc81751aaeb1d) (featherless) 80 | * [Add support for copying animation traits. (#30)](https://github.com/material-motion/motion-interchange-objc/commit/f7fb09546d034fcdf8e57509aa157a760aebd398) (featherless) 81 | * [Allow writing of all properties. (#26)](https://github.com/material-motion/motion-interchange-objc/commit/4f74d24b6d66503fed71af36482665814e10a3a4) (featherless) 82 | * [Add support for damping ratio initializers on the spring timing curve. (#27)](https://github.com/material-motion/motion-interchange-objc/commit/9d7352cec750b8c00fe300708647ebb01189b6c2) (featherless) 83 | * [Use UIViewAnimationCurve instead of NSString as the easing curve type. (#28)](https://github.com/material-motion/motion-interchange-objc/commit/d94246c2b5286d20f92dfc7569b39798394d9422) (featherless) 84 | * [Add APIs for initializing an animation trait with a named timing function. (#25)](https://github.com/material-motion/motion-interchange-objc/commit/72e75e44a940e815a06ee516237451be0646b688) (featherless) 85 | * [Implement v2 APIs (#22)](https://github.com/material-motion/motion-interchange-objc/commit/3a28e221cfe9fccc2c46523adbb817334e7e918a) (featherless) 86 | * [Standardize the timing curve creation methods on CGFloat. (#21)](https://github.com/material-motion/motion-interchange-objc/commit/75f0d3515bda6cb9770c96ddb787a3da50a2b7c6) (featherless) 87 | 88 | ## API changes 89 | 90 | Auto-generated by running: 91 | 92 | apidiff origin/stable release-candidate objc src/MotionInterchange.h 93 | 94 | #### MDMRepetitionOverTime 95 | 96 | *new* class: `MDMRepetitionOverTime` 97 | 98 | *new* method: `-initWithDuration:autoreverses:` in `MDMRepetitionOverTime` 99 | 100 | *new* method: `-init` in `MDMRepetitionOverTime` 101 | 102 | *new* property: `duration` in `MDMRepetitionOverTime` 103 | 104 | *new* method: `-initWithDuration:` in `MDMRepetitionOverTime` 105 | 106 | #### MDMTimingCurve 107 | 108 | *new* protocol: `MDMTimingCurve` 109 | 110 | #### CAMediaTimingFunction() 111 | 112 | *new* category: `CAMediaTimingFunction()` 113 | 114 | #### MDMRepetitionTraits 115 | 116 | *new* property: `autoreverses` in `MDMRepetitionTraits` 117 | 118 | *new* protocol: `MDMRepetitionTraits` 119 | 120 | #### MDMMotionCurveMakeSpringWithInitialVelocity 121 | 122 | *modified* function: `MDMMotionCurveMakeSpringWithInitialVelocity` 123 | 124 | | Type of change: | Swift declaration | 125 | |---|---| 126 | | From: | `func MotionCurveMakeSpring(mass: Float, tension: Float, friction: Float, initialVelocity: Float) -> MotionCurve` | 127 | | To: | `func MotionCurveMakeSpring(mass: CGFloat, tension: CGFloat, friction: CGFloat, initialVelocity: CGFloat) -> MotionCurve` | 128 | 129 | *modified* function: `MDMMotionCurveMakeSpringWithInitialVelocity` 130 | 131 | | Type of change: | Declaration | 132 | |---|---| 133 | | From: | `extern MDMMotionCurve MDMMotionCurveMakeSpringWithInitialVelocity( float mass, float tension, float friction, float initialVelocity)` | 134 | | To: | `extern MDMMotionCurve MDMMotionCurveMakeSpringWithInitialVelocity( CGFloat mass, CGFloat tension, CGFloat friction, CGFloat initialVelocity)` | 135 | 136 | #### MDMSpringTimingCurve 137 | 138 | *new* property: `tension` in `MDMSpringTimingCurve` 139 | 140 | *new* method: `-init` in `MDMSpringTimingCurve` 141 | 142 | *new* property: `friction` in `MDMSpringTimingCurve` 143 | 144 | *new* property: `initialVelocity` in `MDMSpringTimingCurve` 145 | 146 | *new* property: `mass` in `MDMSpringTimingCurve` 147 | 148 | *new* class: `MDMSpringTimingCurve` 149 | 150 | *new* method: `-initWithMass:tension:friction:` in `MDMSpringTimingCurve` 151 | 152 | *new* method: `-initWithMass:tension:friction:initialVelocity:` in `MDMSpringTimingCurve` 153 | 154 | #### MDMAnimationTraits 155 | 156 | *new* class: `MDMAnimationTraits` 157 | 158 | *new* property: `repetition` in `MDMAnimationTraits` 159 | 160 | *new* property: `delay` in `MDMAnimationTraits` 161 | 162 | *new* property: `duration` in `MDMAnimationTraits` 163 | 164 | *new* method: `-initWithDelay:duration:animationCurve:` in `MDMAnimationTraits` 165 | 166 | *new* method: `-initWithDelay:duration:timingCurve:repetition:` in `MDMAnimationTraits` 167 | 168 | *new* method: `-initWithDuration:animationCurve:` in `MDMAnimationTraits` 169 | 170 | *new* method: `-initWithDelay:duration:` in `MDMAnimationTraits` 171 | 172 | *new* method: `-init` in `MDMAnimationTraits` 173 | 174 | *new* method: `-initWithDelay:duration:timingCurve:` in `MDMAnimationTraits` 175 | 176 | *new* method: `-initWithDuration:` in `MDMAnimationTraits` 177 | 178 | *new* property: `timingCurve` in `MDMAnimationTraits` 179 | 180 | #### CAMediaTimingFunction(MotionInterchangeExtension) 181 | 182 | *new* method: `-mdm_reversed` in `CAMediaTimingFunction(MotionInterchangeExtension)` 183 | 184 | *new* property: `mdm_point1` in `CAMediaTimingFunction(MotionInterchangeExtension)` 185 | 186 | *new* category: `CAMediaTimingFunction(MotionInterchangeExtension)` 187 | 188 | *new* property: `mdm_point2` in `CAMediaTimingFunction(MotionInterchangeExtension)` 189 | 190 | #### MDMMotionCurveMakeSpring 191 | 192 | *modified* function: `MDMMotionCurveMakeSpring` 193 | 194 | | Type of change: | Swift declaration | 195 | |---|---| 196 | | From: | `func MotionCurveMakeSpring(mass: Float, tension: Float, friction: Float) -> MotionCurve` | 197 | | To: | `func MotionCurveMakeSpring(mass: CGFloat, tension: CGFloat, friction: CGFloat) -> MotionCurve` | 198 | 199 | *modified* function: `MDMMotionCurveMakeSpring` 200 | 201 | | Type of change: | Declaration | 202 | |---|---| 203 | | From: | `extern MDMMotionCurve MDMMotionCurveMakeSpring(float mass, float tension, float friction)` | 204 | | To: | `extern MDMMotionCurve MDMMotionCurveMakeSpring(CGFloat mass, CGFloat tension, CGFloat friction)` | 205 | 206 | #### MDMAnimationTraits(SystemTraits) 207 | 208 | *new* category: `MDMAnimationTraits(SystemTraits)` 209 | 210 | *new* property: `systemModalMovement` in `MDMAnimationTraits(SystemTraits)` 211 | 212 | #### MDMSpringTimingCurveGenerator 213 | 214 | *new* property: `initialVelocity` in `MDMSpringTimingCurveGenerator` 215 | 216 | *new* class: `MDMSpringTimingCurveGenerator` 217 | 218 | *new* method: `-init` in `MDMSpringTimingCurveGenerator` 219 | 220 | *new* method: `-initWithDuration:dampingRatio:initialVelocity:` in `MDMSpringTimingCurveGenerator` 221 | 222 | *new* property: `dampingRatio` in `MDMSpringTimingCurveGenerator` 223 | 224 | *new* method: `-springTimingCurve` in `MDMSpringTimingCurveGenerator` 225 | 226 | *new* method: `-initWithDuration:dampingRatio:` in `MDMSpringTimingCurveGenerator` 227 | 228 | *new* property: `duration` in `MDMSpringTimingCurveGenerator` 229 | 230 | #### MDMMotionCurveMakeBezier 231 | 232 | *modified* function: `MDMMotionCurveMakeBezier` 233 | 234 | | Type of change: | Swift declaration | 235 | |---|---| 236 | | From: | `func MotionCurveMakeBezier(p1x: Float, p1y: Float, p2x: Float, p2y: Float) -> MotionCurve` | 237 | | To: | `func MotionCurveMakeBezier(p1x: CGFloat, p1y: CGFloat, p2x: CGFloat, p2y: CGFloat) -> MotionCurve` | 238 | 239 | *modified* function: `MDMMotionCurveMakeBezier` 240 | 241 | | Type of change: | Declaration | 242 | |---|---| 243 | | From: | `extern MDMMotionCurve MDMMotionCurveMakeBezier(float p1x, float p1y, float p2x, float p2y)` | 244 | | To: | `extern MDMMotionCurve MDMMotionCurveMakeBezier(CGFloat p1x, CGFloat p1y, CGFloat p2x, CGFloat p2y)` | 245 | 246 | #### MDMRepetition 247 | 248 | *new* method: `-initWithNumberOfRepetitions:autoreverses:` in `MDMRepetition` 249 | 250 | *new* method: `-initWithNumberOfRepetitions:` in `MDMRepetition` 251 | 252 | *new* class: `MDMRepetition` 253 | 254 | *new* property: `numberOfRepetitions` in `MDMRepetition` 255 | 256 | *new* method: `-init` in `MDMRepetition` 257 | 258 | ## Non-source changes 259 | 260 | * [Update docs with new API.](https://github.com/material-motion/motion-interchange-objc/commit/c30d90457c7bf6901e684ba932a5dd3b8ecd5fe5) (Jeff Verkoeyen) 261 | * [Fixing travis builds.](https://github.com/material-motion/motion-interchange-objc/commit/a4301e2eb55594408452446b37dec9a13d93ca53) (Jeff Verkoeyen) 262 | * [Use http_archive instead of git_respository as per the bazel team's recommendations. (#29)](https://github.com/material-motion/motion-interchange-objc/commit/0730f1a905421f9a5d75e6015e1bf4d242a76988) (featherless) 263 | * [Remove unused header.](https://github.com/material-motion/motion-interchange-objc/commit/e8af0592da1aa244867089532381f6dbdd801a77) (Jeff Verkoeyen) 264 | * [Iterating on the usage docs.](https://github.com/material-motion/motion-interchange-objc/commit/dcca85ea152d83cbdcf88d74916a228f40c8c2e1) (Jeff Verkoeyen) 265 | * [Revert "Add todo configuration"](https://github.com/material-motion/motion-interchange-objc/commit/41588742c057d79a3a3a7338f867a9622d84e143) (Jeff Verkoeyen) 266 | * [Add todo configuration](https://github.com/material-motion/motion-interchange-objc/commit/d2e1450ac327ebfba49c7489375bd635e9cfc1bb) (featherless) 267 | * [Enable code coverage on travis](https://github.com/material-motion/motion-interchange-objc/commit/111d91ea2da6ee2a8acd73c89664f4b10b6232c1) (featherless) 268 | * [Run tests on Travis.](https://github.com/material-motion/motion-interchange-objc/commit/f56f8a7a75e93a087aadc0f0d5759be13fd43cb7) (Jeff Verkoeyen) 269 | * [Update README.md](https://github.com/material-motion/motion-interchange-objc/commit/3f9405eac1445d0f12cb4fad4ad0a89631ded920) (featherless) 270 | * [Fix minor typo.](https://github.com/material-motion/motion-interchange-objc/commit/671ab1d579fd1d1c228ec266396145bbaf70f996) (Jeff Verkoeyen) 271 | * [Initial pass at fleshing out the readme (#24)](https://github.com/material-motion/motion-interchange-objc/commit/4e0a2e7ad5f258bc450a9dde3281fa7c3752bae6) (featherless) 272 | * [Fix travis.](https://github.com/material-motion/motion-interchange-objc/commit/866ec18cf2353c2682f89d1350af57c05ce25839) (Jeff Verkoeyen) 273 | * [Add missing Info.plist. (#20)](https://github.com/material-motion/motion-interchange-objc/commit/0080128a6846d2eda8538cab260cbecbbe32b9a1) (Sylvain Defresne) 274 | 275 | # 1.4.0 276 | 277 | This minor release introduces new APIs for creating springs that have an initial velocity. 278 | 279 | ## New features 280 | 281 | Added new APIs for creating springs with initial velocity: 282 | `MDMMotionCurveMakeSpringWithInitialVelocity` and `_MDMSpringWithInitialVelocity`. 283 | 284 | ## Source changes 285 | 286 | * [Add new APIs for creating springs with initial velocity. (#19)](https://github.com/material-motion/motion-interchange-objc/commit/326180f9f5f99e7d5e9e23131de8c24abe2e1dbf) (featherless) 287 | 288 | ## API changes 289 | 290 | ### MDMMotionCurveMakeSpringWithInitialVelocity 291 | 292 | **new** function: `MDMMotionCurveMakeSpringWithInitialVelocity` 293 | 294 | ### _MDMSpringWithInitialVelocity 295 | 296 | **new** macro: `_MDMSpringWithInitialVelocity` 297 | 298 | ## Non-source changes 299 | 300 | * [Add sdk_frameworks dependencies to the BUILD file. (#18)](https://github.com/material-motion/motion-interchange-objc/commit/a601fb65166426bc708d84c0e29d89913c445d04) (featherless) 301 | * [Add jazzy yaml.](https://github.com/material-motion/motion-interchange-objc/commit/130e9760bbb8c0e2179f820cc14f1278c9465b84) (Jeff Verkoeyen) 302 | 303 | # 1.3.0 304 | 305 | This minor releases introduces new APIs for defining motion curves. 306 | 307 | ## New deprecations 308 | 309 | `MDMMotionCurveTypeDefault` is now deprecated. Use `MDMMotionCurveTypeBezier` instead. 310 | 311 | ## New features 312 | 313 | The new `MDMLinearMotionCurve` macro allows you to define linear easing curves in specs. 314 | 315 | Spring curve specs can now define initial velocity. This value can be read using the new 316 | `MDMSpringMotionCurveDataIndexInitialVelocity` enum value for `MDMSpringMotionCurveDataIndex`. 317 | 318 | ## Source changes 319 | 320 | * [Document and define the initial velocity parameter of spring curves (#17)](https://github.com/material-motion/motion-interchange-objc/commit/7eb5e2f79229c3b7cdada7b8df3e1e66b7e229e5) (featherless) 321 | * [Add a linear curve constant. (#16)](https://github.com/material-motion/motion-interchange-objc/commit/0aa4f8caff7314310c3cbd721814305ee6f53601) (featherless) 322 | * [Deprecate MDMMotionCurveTypeDefault in favor of MDMMotionCurveTypeBezier. (#15)](https://github.com/material-motion/motion-interchange-objc/commit/f5a7f3b4a63d4643700403930e2cafd7d4482013) (featherless) 323 | 324 | ## API changes 325 | 326 | ### MDMSpringMotionCurveDataIndexInitialVelocity 327 | 328 | **new** enum: `MDMSpringMotionCurveDataIndexInitialVelocity`. 329 | 330 | ### MDMLinearMotionCurve 331 | 332 | **new** constant/macro: `MDMLinearMotionCurve`. 333 | 334 | # 1.2.0 335 | 336 | This minor release introduces a new API for reversing cubic beziers and a unit test for 337 | `MDMModalMovementTiming`. 338 | 339 | ## New features 340 | 341 | `MDMMotionCurveReversedBezier` reverses cubic bezier curves. Intended for use when building mirrored 342 | bi-directional transitions. 343 | 344 | ## Source changes 345 | 346 | * [Add a unit test for MDMModalMovementTiming. (#12)](https://github.com/material-motion/motion-interchange-objc/commit/a0c3566ad52a45365657e0591701afa7989eb822) (featherless) 347 | * [Add MDMMotionCurveReversed for reversing timing curves. (#11)](https://github.com/material-motion/motion-interchange-objc/commit/a54a5ffa49052a198b4bb5beedce737bb61ebc91) (featherless) 348 | 349 | ## API changes 350 | 351 | ### MDMMotionCurveReversedBezier 352 | 353 | **new** function: `MDMMotionCurveReversedBezier`. 354 | 355 | ## Non-source changes 356 | 357 | * [Standardize the kokoro and bazel files. (#13)](https://github.com/material-motion/motion-interchange-objc/commit/a009d3f7d08d8b2d087891a86eb1e298714198b4) (featherless) 358 | * [Use the v1.0.0 tag for bazel_ios_warnings. (#10)](https://github.com/material-motion/motion-interchange-objc/commit/545b6a448ddb235279318dc262f051d653a48ed4) (featherless) 359 | 360 | # 1.1.1 361 | 362 | This patch release migrates the project's continuous integration pipeline from arc to bazel and 363 | kokoro. 364 | 365 | ## New features 366 | 367 | Continuous integration can now be run locally by executing `./.kokoro` from the root of the git 368 | repo. Requires [bazel](http://bazel.io/). 369 | 370 | ## Source changes 371 | 372 | * [Replace arc with bazel and Kokoro continuous integration. (#9)](https://github.com/material-motion/motion-interchange-objc/commit/2ef4dfbf95a7beb3f0e323e259576b6797420202) (featherless) 373 | * [Fix warning in unit tests. (#8)](https://github.com/material-motion/motion-interchange-objc/commit/d3203a2857648f74d478525514c0f10cb6552b19) (featherless) 374 | * [Add missing import.](https://github.com/material-motion/motion-interchange-objc/commit/445091dbbd68cd0a75e4dd86195cb431b0717e71) (Jeff Verkoeyen) 375 | 376 | # 1.1.0 377 | 378 | This minor release introduces two new APIs for working with timing curves. 379 | 380 | ## New features 381 | 382 | - `MDMMotionCurveFromTimingFunction` can create a timing curve from a `CAMediaTimingFunction`. 383 | - `MDMModalMovementTiming` is the iOS timing curve for modal presentation movement. 384 | 385 | ## Source changes 386 | 387 | * [Add MDMMotionCurveFromTimingFunction for creating motion curves from timing functions. (#7)](https://github.com/material-motion/motion-interchange-objc/commit/5e9837cb453f354609f574e42c3c7cf69d4e2796) (featherless) 388 | * [Add system timing constant for movement during modal presentation. (#4)](https://github.com/material-motion/motion-interchange-objc/commit/bf757fe5dac65f9e76778d57988689b908a6c69b) (featherless) 389 | 390 | ## API changes 391 | 392 | *new* function: `MDMMotionCurveFromTimingFunction`. 393 | 394 | *new* macro: `MDMModalMovementTiming`. 395 | 396 | ## Non-source changes 397 | 398 | * [Update Xcode project settings.](https://github.com/material-motion/motion-interchange-objc/commit/d932efd547276084a09334f38595a3f8da28205d) (Jeff Verkoeyen) 399 | * [Update Podfile.lock.](https://github.com/material-motion/motion-interchange-objc/commit/07f701eb6918752c29f381a028080c5c12511474) (Jeff Verkoeyen) 400 | 401 | # 1.0.1 402 | 403 | Added a missing framework header for Objective-C support. 404 | 405 | ## Source changes 406 | 407 | * [Add missing framework header.](https://github.com/material-motion/motion-interchange-objc/commit/03a9b2592e805f06eb622238d7ce8ad7e6f56e90) (Jeff Verkoeyen) 408 | 409 | ## Non-source changes 410 | 411 | * [Fix links in readme.](https://github.com/material-motion/motion-interchange-objc/commit/a438194edb51214fca13955fc2badcd93f587ec5) (Jeff Verkoeyen) 412 | 413 | # 1.0.0 414 | 415 | Initial release. 416 | 417 | Includes MotionTiming structure for representing cubic bezier and spring animations. 418 | 419 | ## Source changes 420 | 421 | * [Initial commit of motion interchange format. (#1)](https://github.com/material-motion/motion-interchange-objc/commit/e1d882b11f1ecdd3edf5c8746c8d243939ea097a) (featherless) 422 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at 2 | the end). 3 | 4 | ### Before you contribute 5 | 6 | Before we can use your code, you must sign the 7 | [Google Individual Contributor License Agreement] 8 | (https://cla.developers.google.com/about/google-individual) 9 | (CLA), which you can do online. The CLA is necessary mainly because you own the 10 | copyright to your changes, even after your contribution becomes part of our 11 | codebase, so we need your permission to use and distribute your code. We also 12 | need to be sure of various other things—for instance that you'll tell us if you 13 | know that your code infringes on other people's patents. You don't have to sign 14 | the CLA until after you've submitted your code for review and a member has 15 | approved it, but you must do it before we can put your code into our codebase. 16 | Before you start working on a larger contribution, you should get in touch with 17 | us first through the issue tracker with your idea so that we can help out and 18 | possibly guide you. Coordinating up front makes it much easier to avoid 19 | frustration later on. 20 | 21 | ### Code reviews 22 | 23 | All submissions, including submissions by project members, require review. 24 | We use GitHub pull requests for this purpose. 25 | 26 | ### The small print 27 | 28 | Contributions made by corporations are covered by a different agreement than 29 | the one above, the 30 | [Software Grant and Corporate Contributor License Agreement] 31 | (https://cla.developers.google.com/about/google-corporate). 32 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.0.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /MotionInterchange.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "MotionInterchange" 3 | s.summary = "Motion interchange format." 4 | s.version = "4.0.1" 5 | s.authors = "The Material Motion Authors" 6 | s.license = "Apache 2.0" 7 | s.homepage = "https://github.com/material-motion/motion-interchange-objc" 8 | s.source = { :git => "https://github.com/material-motion/motion-interchange-objc.git", :tag => "v" + s.version.to_s } 9 | s.platform = :ios, "10.0" 10 | s.requires_arc = true 11 | 12 | s.public_header_files = "src/*.h" 13 | s.source_files = "src/*.{h,m,mm}", "src/private/*.{h,m,mm}" 14 | end 15 | -------------------------------------------------------------------------------- /MotionInterchange.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6DC6507322388CE7003DBBF5 /* MDMRepetitionTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6505F22388CE7003DBBF5 /* MDMRepetitionTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 6DC6507422388CE7003DBBF5 /* MDMRepetitionOverTime.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6506022388CE7003DBBF5 /* MDMRepetitionOverTime.m */; }; 12 | 6DC6507522388CE7003DBBF5 /* MDMMotionCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6506122388CE7003DBBF5 /* MDMMotionCurve.m */; }; 13 | 6DC6507622388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6506222388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.m */; }; 14 | 6DC6507722388CE7003DBBF5 /* MotionInterchange.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506322388CE7003DBBF5 /* MotionInterchange.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 6DC6507822388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6506422388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.m */; }; 16 | 6DC6507922388CE7003DBBF5 /* MDMSubclassingRestricted.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506522388CE7003DBBF5 /* MDMSubclassingRestricted.h */; settings = {ATTRIBUTES = (Public, ); }; }; 17 | 6DC6507A22388CE7003DBBF5 /* MDMRepetition.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6506622388CE7003DBBF5 /* MDMRepetition.m */; }; 18 | 6DC6507B22388CE7003DBBF5 /* MDMAnimationTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6506722388CE7003DBBF5 /* MDMAnimationTraits.m */; }; 19 | 6DC6507C22388CE7003DBBF5 /* MDMSpringTimingCurve.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC6506822388CE7003DBBF5 /* MDMSpringTimingCurve.m */; }; 20 | 6DC6507D22388CE7003DBBF5 /* MDMMotionTiming.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506922388CE7003DBBF5 /* MDMMotionTiming.h */; settings = {ATTRIBUTES = (Public, ); }; }; 21 | 6DC6507E22388CE7003DBBF5 /* MDMRepetitionOverTime.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506A22388CE7003DBBF5 /* MDMRepetitionOverTime.h */; settings = {ATTRIBUTES = (Public, ); }; }; 22 | 6DC6507F22388CE7003DBBF5 /* MDMMotionCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506B22388CE7003DBBF5 /* MDMMotionCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23 | 6DC6508022388CE7003DBBF5 /* MDMTimingCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506C22388CE7003DBBF5 /* MDMTimingCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; 24 | 6DC6508122388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506D22388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25 | 6DC6508222388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506E22388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; 26 | 6DC6508322388CE7003DBBF5 /* MDMSpringTimingCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6506F22388CE7003DBBF5 /* MDMSpringTimingCurve.h */; settings = {ATTRIBUTES = (Public, ); }; }; 27 | 6DC6508422388CE7003DBBF5 /* MDMAnimationTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6507022388CE7003DBBF5 /* MDMAnimationTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | 6DC6508522388CE7003DBBF5 /* MDMRepetition.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6507122388CE7003DBBF5 /* MDMRepetition.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29 | 6DC6508622388CE7003DBBF5 /* MDMMotionRepetition.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC6507222388CE7003DBBF5 /* MDMMotionRepetition.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 6DC6505322388CA7003DBBF5 /* MotionInterchange.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MotionInterchange.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 6DC6505F22388CE7003DBBF5 /* MDMRepetitionTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMRepetitionTraits.h; sourceTree = ""; }; 35 | 6DC6506022388CE7003DBBF5 /* MDMRepetitionOverTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMRepetitionOverTime.m; sourceTree = ""; }; 36 | 6DC6506122388CE7003DBBF5 /* MDMMotionCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMMotionCurve.m; sourceTree = ""; }; 37 | 6DC6506222388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CAMediaTimingFunction+MDMTimingCurve.m"; sourceTree = ""; }; 38 | 6DC6506322388CE7003DBBF5 /* MotionInterchange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MotionInterchange.h; sourceTree = ""; }; 39 | 6DC6506422388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMSpringTimingCurveGenerator.m; sourceTree = ""; }; 40 | 6DC6506522388CE7003DBBF5 /* MDMSubclassingRestricted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMSubclassingRestricted.h; sourceTree = ""; }; 41 | 6DC6506622388CE7003DBBF5 /* MDMRepetition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMRepetition.m; sourceTree = ""; }; 42 | 6DC6506722388CE7003DBBF5 /* MDMAnimationTraits.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMAnimationTraits.m; sourceTree = ""; }; 43 | 6DC6506822388CE7003DBBF5 /* MDMSpringTimingCurve.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMSpringTimingCurve.m; sourceTree = ""; }; 44 | 6DC6506922388CE7003DBBF5 /* MDMMotionTiming.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMMotionTiming.h; sourceTree = ""; }; 45 | 6DC6506A22388CE7003DBBF5 /* MDMRepetitionOverTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMRepetitionOverTime.h; sourceTree = ""; }; 46 | 6DC6506B22388CE7003DBBF5 /* MDMMotionCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMMotionCurve.h; sourceTree = ""; }; 47 | 6DC6506C22388CE7003DBBF5 /* MDMTimingCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMTimingCurve.h; sourceTree = ""; }; 48 | 6DC6506D22388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMSpringTimingCurveGenerator.h; sourceTree = ""; }; 49 | 6DC6506E22388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CAMediaTimingFunction+MDMTimingCurve.h"; sourceTree = ""; }; 50 | 6DC6506F22388CE7003DBBF5 /* MDMSpringTimingCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMSpringTimingCurve.h; sourceTree = ""; }; 51 | 6DC6507022388CE7003DBBF5 /* MDMAnimationTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMAnimationTraits.h; sourceTree = ""; }; 52 | 6DC6507122388CE7003DBBF5 /* MDMRepetition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMRepetition.h; sourceTree = ""; }; 53 | 6DC6507222388CE7003DBBF5 /* MDMMotionRepetition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMMotionRepetition.h; sourceTree = ""; }; 54 | 6DC6508722388CFA003DBBF5 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 6DC6505022388CA7003DBBF5 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 6DC6504922388CA7003DBBF5 = { 69 | isa = PBXGroup; 70 | children = ( 71 | 6DC6505E22388CE7003DBBF5 /* src */, 72 | 6DC6505422388CA7003DBBF5 /* Products */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | 6DC6505422388CA7003DBBF5 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 6DC6505322388CA7003DBBF5 /* MotionInterchange.framework */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | 6DC6505E22388CE7003DBBF5 /* src */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 6DC6508722388CFA003DBBF5 /* Info.plist */, 88 | 6DC6506E22388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.h */, 89 | 6DC6506222388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.m */, 90 | 6DC6507022388CE7003DBBF5 /* MDMAnimationTraits.h */, 91 | 6DC6506722388CE7003DBBF5 /* MDMAnimationTraits.m */, 92 | 6DC6506B22388CE7003DBBF5 /* MDMMotionCurve.h */, 93 | 6DC6506122388CE7003DBBF5 /* MDMMotionCurve.m */, 94 | 6DC6507222388CE7003DBBF5 /* MDMMotionRepetition.h */, 95 | 6DC6506922388CE7003DBBF5 /* MDMMotionTiming.h */, 96 | 6DC6507122388CE7003DBBF5 /* MDMRepetition.h */, 97 | 6DC6506622388CE7003DBBF5 /* MDMRepetition.m */, 98 | 6DC6506A22388CE7003DBBF5 /* MDMRepetitionOverTime.h */, 99 | 6DC6506022388CE7003DBBF5 /* MDMRepetitionOverTime.m */, 100 | 6DC6505F22388CE7003DBBF5 /* MDMRepetitionTraits.h */, 101 | 6DC6506F22388CE7003DBBF5 /* MDMSpringTimingCurve.h */, 102 | 6DC6506822388CE7003DBBF5 /* MDMSpringTimingCurve.m */, 103 | 6DC6506D22388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.h */, 104 | 6DC6506422388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.m */, 105 | 6DC6506522388CE7003DBBF5 /* MDMSubclassingRestricted.h */, 106 | 6DC6506C22388CE7003DBBF5 /* MDMTimingCurve.h */, 107 | 6DC6506322388CE7003DBBF5 /* MotionInterchange.h */, 108 | ); 109 | path = src; 110 | sourceTree = ""; 111 | }; 112 | /* End PBXGroup section */ 113 | 114 | /* Begin PBXHeadersBuildPhase section */ 115 | 6DC6504E22388CA7003DBBF5 /* Headers */ = { 116 | isa = PBXHeadersBuildPhase; 117 | buildActionMask = 2147483647; 118 | files = ( 119 | 6DC6508322388CE7003DBBF5 /* MDMSpringTimingCurve.h in Headers */, 120 | 6DC6507322388CE7003DBBF5 /* MDMRepetitionTraits.h in Headers */, 121 | 6DC6508522388CE7003DBBF5 /* MDMRepetition.h in Headers */, 122 | 6DC6508022388CE7003DBBF5 /* MDMTimingCurve.h in Headers */, 123 | 6DC6508122388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.h in Headers */, 124 | 6DC6508622388CE7003DBBF5 /* MDMMotionRepetition.h in Headers */, 125 | 6DC6507F22388CE7003DBBF5 /* MDMMotionCurve.h in Headers */, 126 | 6DC6508222388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.h in Headers */, 127 | 6DC6507722388CE7003DBBF5 /* MotionInterchange.h in Headers */, 128 | 6DC6507922388CE7003DBBF5 /* MDMSubclassingRestricted.h in Headers */, 129 | 6DC6507E22388CE7003DBBF5 /* MDMRepetitionOverTime.h in Headers */, 130 | 6DC6507D22388CE7003DBBF5 /* MDMMotionTiming.h in Headers */, 131 | 6DC6508422388CE7003DBBF5 /* MDMAnimationTraits.h in Headers */, 132 | ); 133 | runOnlyForDeploymentPostprocessing = 0; 134 | }; 135 | /* End PBXHeadersBuildPhase section */ 136 | 137 | /* Begin PBXNativeTarget section */ 138 | 6DC6505222388CA7003DBBF5 /* MotionInterchange */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = 6DC6505B22388CA7003DBBF5 /* Build configuration list for PBXNativeTarget "MotionInterchange" */; 141 | buildPhases = ( 142 | 6DC6504E22388CA7003DBBF5 /* Headers */, 143 | 6DC6504F22388CA7003DBBF5 /* Sources */, 144 | 6DC6505022388CA7003DBBF5 /* Frameworks */, 145 | 6DC6505122388CA7003DBBF5 /* Resources */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | ); 151 | name = MotionInterchange; 152 | productName = MotionInterchange; 153 | productReference = 6DC6505322388CA7003DBBF5 /* MotionInterchange.framework */; 154 | productType = "com.apple.product-type.framework"; 155 | }; 156 | /* End PBXNativeTarget section */ 157 | 158 | /* Begin PBXProject section */ 159 | 6DC6504A22388CA7003DBBF5 /* Project object */ = { 160 | isa = PBXProject; 161 | attributes = { 162 | LastUpgradeCheck = 1010; 163 | ORGANIZATIONNAME = "The Material Motion Authors"; 164 | TargetAttributes = { 165 | 6DC6505222388CA7003DBBF5 = { 166 | CreatedOnToolsVersion = 10.1; 167 | }; 168 | }; 169 | }; 170 | buildConfigurationList = 6DC6504D22388CA7003DBBF5 /* Build configuration list for PBXProject "MotionInterchange" */; 171 | compatibilityVersion = "Xcode 9.3"; 172 | developmentRegion = en; 173 | hasScannedForEncodings = 0; 174 | knownRegions = ( 175 | en, 176 | ); 177 | mainGroup = 6DC6504922388CA7003DBBF5; 178 | productRefGroup = 6DC6505422388CA7003DBBF5 /* Products */; 179 | projectDirPath = ""; 180 | projectRoot = ""; 181 | targets = ( 182 | 6DC6505222388CA7003DBBF5 /* MotionInterchange */, 183 | ); 184 | }; 185 | /* End PBXProject section */ 186 | 187 | /* Begin PBXResourcesBuildPhase section */ 188 | 6DC6505122388CA7003DBBF5 /* Resources */ = { 189 | isa = PBXResourcesBuildPhase; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXResourcesBuildPhase section */ 196 | 197 | /* Begin PBXSourcesBuildPhase section */ 198 | 6DC6504F22388CA7003DBBF5 /* Sources */ = { 199 | isa = PBXSourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | 6DC6507B22388CE7003DBBF5 /* MDMAnimationTraits.m in Sources */, 203 | 6DC6507522388CE7003DBBF5 /* MDMMotionCurve.m in Sources */, 204 | 6DC6507422388CE7003DBBF5 /* MDMRepetitionOverTime.m in Sources */, 205 | 6DC6507C22388CE7003DBBF5 /* MDMSpringTimingCurve.m in Sources */, 206 | 6DC6507622388CE7003DBBF5 /* CAMediaTimingFunction+MDMTimingCurve.m in Sources */, 207 | 6DC6507822388CE7003DBBF5 /* MDMSpringTimingCurveGenerator.m in Sources */, 208 | 6DC6507A22388CE7003DBBF5 /* MDMRepetition.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin XCBuildConfiguration section */ 215 | 6DC6505922388CA7003DBBF5 /* Debug */ = { 216 | isa = XCBuildConfiguration; 217 | buildSettings = { 218 | ALWAYS_SEARCH_USER_PATHS = NO; 219 | CLANG_ANALYZER_NONNULL = YES; 220 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 221 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 222 | CLANG_CXX_LIBRARY = "libc++"; 223 | CLANG_ENABLE_MODULES = YES; 224 | CLANG_ENABLE_OBJC_ARC = YES; 225 | CLANG_ENABLE_OBJC_WEAK = YES; 226 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 227 | CLANG_WARN_BOOL_CONVERSION = YES; 228 | CLANG_WARN_COMMA = YES; 229 | CLANG_WARN_CONSTANT_CONVERSION = YES; 230 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 231 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 232 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 233 | CLANG_WARN_EMPTY_BODY = YES; 234 | CLANG_WARN_ENUM_CONVERSION = YES; 235 | CLANG_WARN_INFINITE_RECURSION = YES; 236 | CLANG_WARN_INT_CONVERSION = YES; 237 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 238 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 239 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 240 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 241 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 242 | CLANG_WARN_STRICT_PROTOTYPES = YES; 243 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 244 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 245 | CLANG_WARN_UNREACHABLE_CODE = YES; 246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 247 | CODE_SIGN_IDENTITY = "iPhone Developer"; 248 | COPY_PHASE_STRIP = NO; 249 | CURRENT_PROJECT_VERSION = 1; 250 | DEBUG_INFORMATION_FORMAT = dwarf; 251 | ENABLE_STRICT_OBJC_MSGSEND = YES; 252 | ENABLE_TESTABILITY = YES; 253 | GCC_C_LANGUAGE_STANDARD = gnu11; 254 | GCC_DYNAMIC_NO_PIC = NO; 255 | GCC_NO_COMMON_BLOCKS = YES; 256 | GCC_OPTIMIZATION_LEVEL = 0; 257 | GCC_PREPROCESSOR_DEFINITIONS = ( 258 | "DEBUG=1", 259 | "$(inherited)", 260 | ); 261 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 262 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 263 | GCC_WARN_UNDECLARED_SELECTOR = YES; 264 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 265 | GCC_WARN_UNUSED_FUNCTION = YES; 266 | GCC_WARN_UNUSED_VARIABLE = YES; 267 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 268 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 269 | MTL_FAST_MATH = YES; 270 | ONLY_ACTIVE_ARCH = YES; 271 | SDKROOT = iphoneos; 272 | VERSIONING_SYSTEM = "apple-generic"; 273 | VERSION_INFO_PREFIX = ""; 274 | }; 275 | name = Debug; 276 | }; 277 | 6DC6505A22388CA7003DBBF5 /* Release */ = { 278 | isa = XCBuildConfiguration; 279 | buildSettings = { 280 | ALWAYS_SEARCH_USER_PATHS = NO; 281 | CLANG_ANALYZER_NONNULL = YES; 282 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 283 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 284 | CLANG_CXX_LIBRARY = "libc++"; 285 | CLANG_ENABLE_MODULES = YES; 286 | CLANG_ENABLE_OBJC_ARC = YES; 287 | CLANG_ENABLE_OBJC_WEAK = YES; 288 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 289 | CLANG_WARN_BOOL_CONVERSION = YES; 290 | CLANG_WARN_COMMA = YES; 291 | CLANG_WARN_CONSTANT_CONVERSION = YES; 292 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 293 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 294 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 295 | CLANG_WARN_EMPTY_BODY = YES; 296 | CLANG_WARN_ENUM_CONVERSION = YES; 297 | CLANG_WARN_INFINITE_RECURSION = YES; 298 | CLANG_WARN_INT_CONVERSION = YES; 299 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 300 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 301 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 302 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 303 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 304 | CLANG_WARN_STRICT_PROTOTYPES = YES; 305 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 306 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 307 | CLANG_WARN_UNREACHABLE_CODE = YES; 308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 309 | CODE_SIGN_IDENTITY = "iPhone Developer"; 310 | COPY_PHASE_STRIP = NO; 311 | CURRENT_PROJECT_VERSION = 1; 312 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 313 | ENABLE_NS_ASSERTIONS = NO; 314 | ENABLE_STRICT_OBJC_MSGSEND = YES; 315 | GCC_C_LANGUAGE_STANDARD = gnu11; 316 | GCC_NO_COMMON_BLOCKS = YES; 317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 318 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 319 | GCC_WARN_UNDECLARED_SELECTOR = YES; 320 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 321 | GCC_WARN_UNUSED_FUNCTION = YES; 322 | GCC_WARN_UNUSED_VARIABLE = YES; 323 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 324 | MTL_ENABLE_DEBUG_INFO = NO; 325 | MTL_FAST_MATH = YES; 326 | SDKROOT = iphoneos; 327 | VALIDATE_PRODUCT = YES; 328 | VERSIONING_SYSTEM = "apple-generic"; 329 | VERSION_INFO_PREFIX = ""; 330 | }; 331 | name = Release; 332 | }; 333 | 6DC6505C22388CA7003DBBF5 /* Debug */ = { 334 | isa = XCBuildConfiguration; 335 | buildSettings = { 336 | CODE_SIGN_IDENTITY = ""; 337 | CODE_SIGN_STYLE = Automatic; 338 | DEFINES_MODULE = YES; 339 | DYLIB_COMPATIBILITY_VERSION = 1; 340 | DYLIB_CURRENT_VERSION = 1; 341 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 342 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 343 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 344 | LD_RUNPATH_SEARCH_PATHS = ( 345 | "$(inherited)", 346 | "@executable_path/Frameworks", 347 | "@loader_path/Frameworks", 348 | ); 349 | PRODUCT_BUNDLE_IDENTIFIER = "com.material-motion.MotionInterchange"; 350 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 351 | SKIP_INSTALL = YES; 352 | TARGETED_DEVICE_FAMILY = "1,2"; 353 | }; 354 | name = Debug; 355 | }; 356 | 6DC6505D22388CA7003DBBF5 /* Release */ = { 357 | isa = XCBuildConfiguration; 358 | buildSettings = { 359 | CODE_SIGN_IDENTITY = ""; 360 | CODE_SIGN_STYLE = Automatic; 361 | DEFINES_MODULE = YES; 362 | DYLIB_COMPATIBILITY_VERSION = 1; 363 | DYLIB_CURRENT_VERSION = 1; 364 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 365 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 366 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 367 | LD_RUNPATH_SEARCH_PATHS = ( 368 | "$(inherited)", 369 | "@executable_path/Frameworks", 370 | "@loader_path/Frameworks", 371 | ); 372 | PRODUCT_BUNDLE_IDENTIFIER = "com.material-motion.MotionInterchange"; 373 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 374 | SKIP_INSTALL = YES; 375 | TARGETED_DEVICE_FAMILY = "1,2"; 376 | }; 377 | name = Release; 378 | }; 379 | /* End XCBuildConfiguration section */ 380 | 381 | /* Begin XCConfigurationList section */ 382 | 6DC6504D22388CA7003DBBF5 /* Build configuration list for PBXProject "MotionInterchange" */ = { 383 | isa = XCConfigurationList; 384 | buildConfigurations = ( 385 | 6DC6505922388CA7003DBBF5 /* Debug */, 386 | 6DC6505A22388CA7003DBBF5 /* Release */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | defaultConfigurationName = Release; 390 | }; 391 | 6DC6505B22388CA7003DBBF5 /* Build configuration list for PBXNativeTarget "MotionInterchange" */ = { 392 | isa = XCConfigurationList; 393 | buildConfigurations = ( 394 | 6DC6505C22388CA7003DBBF5 /* Debug */, 395 | 6DC6505D22388CA7003DBBF5 /* Release */, 396 | ); 397 | defaultConfigurationIsVisible = 0; 398 | defaultConfigurationName = Release; 399 | }; 400 | /* End XCConfigurationList section */ 401 | }; 402 | rootObject = 6DC6504A22388CA7003DBBF5 /* Project object */; 403 | } 404 | -------------------------------------------------------------------------------- /MotionInterchange.xcodeproj/xcshareddata/xcschemes/MotionInterchange.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | workspace 'MotionInterchange.xcworkspace' 2 | use_frameworks! 3 | platform :ios, '10.0' 4 | 5 | target "MotionInterchangeCatalog" do 6 | pod 'CatalogByConvention' 7 | pod 'MotionInterchange', :path => './' 8 | 9 | project 'examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj' 10 | end 11 | 12 | target "UnitTests" do 13 | pod 'MotionInterchange', :path => './' 14 | 15 | project 'examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj' 16 | end 17 | 18 | post_install do |installer| 19 | installer.pods_project.targets.each do |target| 20 | target.build_configurations.each do |configuration| 21 | configuration.build_settings['SWIFT_VERSION'] = "3.0" 22 | if target.name.start_with?("MotionInterchange") 23 | configuration.build_settings['WARNING_CFLAGS'] ="$(inherited) -Wall -Wcast-align -Wconversion -Werror -Wextra -Wimplicit-atomic-properties -Wmissing-prototypes -Wno-sign-conversion -Wno-unused-parameter -Woverlength-strings -Wshadow -Wstrict-selector-match -Wundeclared-selector -Wunreachable-code" 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CatalogByConvention (2.5.2) 3 | - MotionInterchange (4.0.1) 4 | 5 | DEPENDENCIES: 6 | - CatalogByConvention 7 | - MotionInterchange (from `./`) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - CatalogByConvention 12 | 13 | EXTERNAL SOURCES: 14 | MotionInterchange: 15 | :path: "./" 16 | 17 | SPEC CHECKSUMS: 18 | CatalogByConvention: ef713654160053be026fa4648dd28caf6b5ca4e1 19 | MotionInterchange: d58704efd5dcd62c6535bc1081df832533a8e9b9 20 | 21 | PODFILE CHECKSUM: aea7b8b75a397821880e2ba54fc4cf979d21cd99 22 | 23 | COCOAPODS: 1.10.1 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Motion Interchange Banner](img/motion-interchange-banner.gif) 2 | 3 | > A standard format for representing animation traits in Objective-C and Swift. 4 | 5 | [![Build Status](https://travis-ci.org/material-motion/motion-interchange-objc.svg?branch=develop)](https://travis-ci.org/material-motion/motion-interchange-objc) 6 | [![codecov](https://codecov.io/gh/material-motion/motion-interchange-objc/branch/develop/graph/badge.svg)](https://codecov.io/gh/material-motion/motion-interchange-objc) 7 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/MotionInterchange.svg)](https://cocoapods.org/pods/MotionInterchange) 8 | [![Platform](https://img.shields.io/cocoapods/p/MotionInterchange.svg)](http://cocoadocs.org/docsets/MotionInterchange) 9 | 10 | "Magic numbers" — those lonely, abandoned values without a home — are often one of the first things 11 | targeted in code review for cleanup. And yet, numbers related to animations may go unnoticed and 12 | left behind, scattered throughout a code base with little to no organizational diligence. These 13 | forgotten metrics form the backbone of mobile interactions and are often the ones needing the most 14 | care - so why are we ok leaving them scattered throughout a code base? 15 | 16 | ```objc 17 | // Let's play "find the magic number": how many magic numbers are hidden in this code? 18 | [UIView animateWithDuration:0.230 19 | delay:0 20 | options:UIViewAnimationOptionCurveEaseOut 21 | animations:^{ 22 | myButton.position = updatedPosition; 23 | } 24 | completion:nil]; 25 | // Hint: the answer is not "one, the number 0.230". 26 | ``` 27 | 28 | The challenge with extracting animation magic numbers is that we often don't have a clear 29 | definition of *what an animation is composed of*. An animation is not simply determined by its 30 | duration, in the same way that a color is not simply determined by how red it is. 31 | 32 | The traits of an animation — like the red, green, and blue components of a color — include the 33 | following: 34 | 35 | - Delay. 36 | - Duration. 37 | - Timing curve. 38 | - Repetition. 39 | 40 | Within this library you will find simple data types for storing and representing animation 41 | traits so that the magic numbers that define your animations can find a place to call home. 42 | 43 | Welcome home, lost numbers. 44 | 45 | ## Sibling library: Motion Animator 46 | 47 | While it is possible to use the Motion Interchange as a standalone library, the Motion Animator 48 | is designed to be the primary consumer of Motion Interchange data types. Consider using these 49 | libraries together, with MotionAnimator as your primary dependency. 50 | 51 | ```objc 52 | MDMAnimationTraits *animationTraits = 53 | [[MDMAnimationTraits alloc] initWithDuration:0.230 54 | timingFunctionName:kCAMediaTimingFunctionEaseInEaseOut]; 55 | 56 | MDMMotionAnimator *animator = [[MDMMotionAnimator alloc] init]; 57 | [animator animateWithTraits:animationTraits animations:^{ 58 | view.alpha = 0; 59 | }]; 60 | ``` 61 | 62 | To learn more, visit the MotionAnimator GitHub page: 63 | 64 | https://github.com/material-motion/motion-animator-objc 65 | 66 | ## Installation 67 | 68 | ### Installation with CocoaPods 69 | 70 | > CocoaPods is a dependency manager for Objective-C and Swift libraries. CocoaPods automates the 71 | > process of using third-party libraries in your projects. See 72 | > [the Getting Started guide](https://guides.cocoapods.org/using/getting-started.html) for more 73 | > information. You can install it with the following command: 74 | > 75 | > gem install cocoapods 76 | 77 | Add `MotionInterchange` to your `Podfile`: 78 | 79 | pod 'MotionInterchange' 80 | 81 | Then run the following command: 82 | 83 | pod install 84 | 85 | ### Usage 86 | 87 | Import the framework: 88 | 89 | @import MotionInterchange; 90 | 91 | You will now have access to all of the APIs. 92 | 93 | ## Example apps/unit tests 94 | 95 | Check out a local copy of the repo to access the Catalog application by running the following 96 | commands: 97 | 98 | git clone https://github.com/material-motion/motion-interchange-objc.git 99 | cd motion-interchange-objc 100 | pod install 101 | open MotionInterchange.xcworkspace 102 | 103 | ## Guides 104 | 105 | 1. [Animation traits](#animation-traits) 106 | 2. [Timing curves](#timing-curves) 107 | 108 | ### Animation traits 109 | 110 | The primary data type you'll make use of is `MDMAnimationTraits`. This class can store all of 111 | the necessary traits that make up an animation, including: 112 | 113 | - Delay. 114 | - Duration. 115 | - Timing curve. 116 | - Repetition. 117 | 118 | In Objective-C, you initialize a simple ease in/out cubic bezier instance like so: 119 | 120 | ```objc 121 | MDMAnimationTraits *traits = [[MDMAnimationTraits alloc] initWithDuration:0.5]; 122 | ``` 123 | 124 | And in Swift: 125 | 126 | ```swift 127 | let traits = MDMAnimationTraits(duration: 0.5) 128 | ``` 129 | 130 | There are many more ways to initialize animation traits. Read the 131 | [header documentation](src/MDMAnimationTraits.h) to see all of the available initializers. 132 | 133 | ### Timing curves 134 | 135 | A timing curve describes how quickly an animation progresses over time. Two types of timing 136 | curves are supported by Core Animation, and therefore by the MotionInterchange: 137 | 138 | - Cubic bezier 139 | - Spring 140 | 141 | **Cubic beziers** are represented by the CAMediaTimingFunction object. To define an 142 | animation trait with a cubic bezier curve in Objective-C: 143 | 144 | ```objc 145 | CAMediaTimingFunction *timingCurve = 146 | [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 147 | MDMAnimationTraits *traits = 148 | [[MDMAnimationTraits alloc] initWithDelay:0 duration:0.5 timingCurve:timingCurve]; 149 | ``` 150 | 151 | And in Swift: 152 | 153 | ```swift 154 | let timingCurve = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 155 | let traits = MDMAnimationTraits(delay: 0, duration: 0.5, timingCurve: timingCurve) 156 | ``` 157 | 158 | You can also use the UIViewAnimationCurve type to initialize a timing curve in Objective-C: 159 | 160 | ```objc 161 | MDMAnimationTraits *traits = 162 | [[MDMAnimationTraits alloc] initWithDuration:0.5 animationCurve:UIViewAnimationCurveEaseIn]; 163 | ``` 164 | 165 | And in Swift: 166 | 167 | ```swift 168 | let traits = MDMAnimationTraits(duration: 0.5, animationCurve: .easeIn) 169 | ``` 170 | 171 | **Springs** are represented with the custom `MDMSpringTimingCurve` type. To define an 172 | animation trait with a spring curve in Objective-C: 173 | 174 | ```objc 175 | MDMSpringTimingCurve *timingCurve = 176 | [[MDMSpringTimingCurve alloc] initWithMass:1 tension:100 friction:10]; 177 | MDMAnimationTraits *traits = 178 | [[MDMAnimationTraits alloc] initWithDelay:0 duration:0.5 timingCurve:timingCurve]; 179 | ``` 180 | 181 | And in Swift: 182 | 183 | ```swift 184 | let timingCurve = MDMSpringTimingCurve(mass: 1, tension: 100, friction: 10) 185 | let traits = MDMAnimationTraits(delay: 0, duration: 0.5, timingCurve: timingCurve) 186 | ``` 187 | 188 | Springs can also be initialized using UIKit's [damping ratio concept](https://developer.apple.com/documentation/uikit/uiview/1622594-animatewithduration). The `MDMSpringTimingCurveGenerator` type generates `MDMSpringTimingCurve` instances when needed. A spring timing curve generator can be stored as the `timingCurve` of an `MDMAnimationTraits` instance. 189 | 190 | ```objc 191 | MDMSpringTimingCurveGenerator *timingCurve = 192 | [[MDMSpringTimingCurveGenerator alloc] initWithDuration:<#(NSTimeInterval)#> dampingRatio:<#(CGFloat)#>]; 193 | MDMAnimationTraits *traits = 194 | [[MDMAnimationTraits alloc] initWithDelay:0 duration:0.5 timingCurve:timingCurve]; 195 | ``` 196 | 197 | And in Swift: 198 | 199 | ```swift 200 | let timingCurve = MDMSpringTimingCurveGenerator(duration: 0.5, dampingRatio: 0.5) 201 | let traits = MDMAnimationTraits(delay: 0, duration: 0.5, timingCurve: timingCurve) 202 | ``` 203 | 204 | ## Contributing 205 | 206 | We welcome contributions! 207 | 208 | Check out our [upcoming milestones](https://github.com/material-motion/motion-interchange-objc/milestones). 209 | 210 | Learn more about [our team](https://material-motion.github.io/material-motion/team/), 211 | [our community](https://material-motion.github.io/material-motion/team/community/), and 212 | our [contributor essentials](https://material-motion.github.io/material-motion/team/essentials/). 213 | 214 | ## License 215 | 216 | Licensed under the Apache 2.0 license. See LICENSE for details. 217 | -------------------------------------------------------------------------------- /examples/apps/Catalog/Catalog/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import UIKit 18 | import CatalogByConvention 19 | 20 | @UIApplicationMain 21 | class AppDelegate: UIResponder, UIApplicationDelegate { 22 | 23 | var window: UIWindow? 24 | 25 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 26 | let window = UIWindow(frame: UIScreen.main.bounds) 27 | self.window = window 28 | 29 | let rootViewController = CBCNodeListViewController(node: CBCCreateNavigationTree()) 30 | rootViewController.title = "Motion Interchange" 31 | window.rootViewController = UINavigationController(rootViewController: rootViewController) 32 | 33 | window.makeKeyAndVisible() 34 | return true 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/apps/Catalog/Catalog/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /examples/apps/Catalog/Catalog/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/apps/Catalog/Catalog/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj/xcshareddata/xcschemes/MotionInterchangeCatalog.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 87 | 93 | 94 | 95 | 96 | 98 | 99 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 41 | 42 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/apps/Catalog/TableOfContents.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | // MARK: Catalog by convention 18 | 19 | // Note: this library does not include examples because it is solely a data format. 20 | -------------------------------------------------------------------------------- /examples/apps/Catalog/TestHarness/AppDelegate.swift: -------------------------------------------------------------------------------- 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 | import UIKit 18 | 19 | @UIApplicationMain 20 | class AppDelegate: UIResponder, UIApplicationDelegate { 21 | 22 | var window: UIWindow? 23 | 24 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 25 | let window = UIWindow(frame: UIScreen.main.bounds) 26 | self.window = window 27 | window.rootViewController = UINavigationController(rootViewController: UIViewController()) 28 | window.makeKeyAndVisible() 29 | return true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/apps/Catalog/TestHarness/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /examples/apps/Catalog/TestHarness/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/apps/Catalog/TestHarness/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/apps/Catalog/UnitTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/supplemental/ExampleViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import UIKit 18 | 19 | struct ExampleInfo { 20 | let title: String 21 | let instructions: String 22 | } 23 | 24 | class ExampleViewController: UIViewController { 25 | 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | view.backgroundColor = .backgroundColor 29 | } 30 | 31 | func exampleInformation() -> ExampleInfo { 32 | return ExampleInfo(title: "Uninitialized", instructions: "") 33 | } 34 | 35 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 36 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 37 | 38 | self.title = exampleInformation().title 39 | } 40 | 41 | required init?(coder aDecoder: NSCoder) { 42 | fatalError("init(coder:) has not been implemented") 43 | } 44 | } 45 | 46 | class ExampleTableViewController: UITableViewController { 47 | 48 | func exampleInformation() -> ExampleInfo { 49 | return ExampleInfo(title: "Uninitialized", instructions: "") 50 | } 51 | 52 | convenience init() { 53 | self.init(style: .plain) 54 | } 55 | 56 | override init(style: UITableView.Style) { 57 | super.init(style: style) 58 | 59 | self.title = exampleInformation().title 60 | } 61 | 62 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 63 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 64 | 65 | self.title = exampleInformation().title 66 | } 67 | 68 | required init?(coder aDecoder: NSCoder) { 69 | fatalError("init(coder:) has not been implemented") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /examples/supplemental/ExampleViews.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import UIKit 18 | 19 | func createExampleView() -> UIView { 20 | let view = UIView(frame: .init(x: 0, y: 0, width: 128, height: 128)) 21 | view.backgroundColor = .primaryColor 22 | view.layer.cornerRadius = view.bounds.width / 2 23 | return view 24 | } 25 | 26 | func createExampleSquareView() -> UIView { 27 | let view = UIView(frame: .init(x: 0, y: 0, width: 128, height: 128)) 28 | view.backgroundColor = .primaryColor 29 | return view 30 | } 31 | -------------------------------------------------------------------------------- /examples/supplemental/HexColor.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import Foundation 18 | import UIKit 19 | 20 | extension UIColor { 21 | private convenience init(red: Int, green: Int, blue: Int) { 22 | assert(red >= 0 && red <= 255, "Invalid red component") 23 | assert(green >= 0 && green <= 255, "Invalid green component") 24 | assert(blue >= 0 && blue <= 255, "Invalid blue component") 25 | 26 | self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) 27 | } 28 | 29 | convenience init(hexColor: Int) { 30 | self.init(red: (hexColor >> 16) & 0xff, green: (hexColor >> 8) & 0xff, blue: hexColor & 0xff) 31 | } 32 | 33 | static var primaryColor: UIColor { 34 | return UIColor(hexColor: 0xFF80AB) 35 | } 36 | 37 | static var secondaryColor: UIColor { 38 | return UIColor(hexColor: 0xC51162) 39 | } 40 | 41 | static var backgroundColor: UIColor { 42 | return UIColor(hexColor: 0x212121) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/supplemental/Layout.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import UIKit 18 | 19 | func center(_ view: UIView, within containerView: UIView) -> UIView { 20 | let x = (containerView.bounds.width - view.bounds.width) / 2 21 | let y = (containerView.bounds.height - view.bounds.height) / 2 22 | view.frame = .init(origin: .init(x: x, y: y), size: view.bounds.size) 23 | view.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleLeftMargin] 24 | return view 25 | } 26 | -------------------------------------------------------------------------------- /examples/supplemental/ModalViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import Foundation 18 | import UIKit 19 | 20 | class ModalViewController: ExampleViewController { 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | view.backgroundColor = .primaryColor 26 | 27 | view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTap))) 28 | 29 | let label = UILabel(frame: view.bounds) 30 | label.numberOfLines = 0 31 | label.lineBreakMode = .byWordWrapping 32 | label.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In aliquam dolor eget orci condimentum, eu blandit metus dictum. Suspendisse vitae metus pellentesque, sagittis massa vel, sodales velit. Aliquam placerat nibh et posuere interdum. Etiam fermentum purus vel turpis lobortis auctor. Curabitur auctor maximus purus, ac iaculis mi. In ac hendrerit sapien, eget porttitor risus. Integer placerat cursus viverra. Proin mollis nulla vitae nisi posuere, eu rutrum mauris condimentum. Nullam in faucibus nulla, non tincidunt lectus. Maecenas mollis massa purus, in viverra elit molestie eu. Nunc volutpat magna eget mi vestibulum pharetra. Suspendisse nulla ligula, laoreet non ante quis, vehicula facilisis libero. Morbi faucibus, sapien a convallis sodales, leo quam scelerisque leo, ut tincidunt diam velit laoreet nulla. Proin at quam vel nibh varius ultrices porta id diam. Pellentesque pretium consequat neque volutpat tristique. Sed placerat a purus ut molestie. Nullam laoreet venenatis urna non pulvinar. Proin a vestibulum nulla, eu placerat est. Morbi molestie aliquam justo, ut aliquet neque tristique consectetur. In hac habitasse platea dictumst. Fusce vehicula justo in euismod elementum. Ut vel malesuada est. Aliquam mattis, ex vel viverra eleifend, mauris nibh faucibus nibh, in fringilla sem purus vitae elit. Donec sed dapibus orci, ut vulputate sapien. Integer eu magna efficitur est pellentesque tempor. Sed ac imperdiet ex. Maecenas congue quis lacus vel dictum. Phasellus dictum mi at sollicitudin euismod. Mauris laoreet, eros vitae euismod commodo, libero ligula pretium massa, in scelerisque eros dui eu metus. Fusce elementum mauris velit, eu tempor nulla congue ut. In at tellus id quam feugiat semper eget ut felis. Nulla quis varius quam. Nullam tincidunt laoreet risus, ut aliquet nisl gravida id. Nulla iaculis mauris velit, vitae feugiat nunc scelerisque ac. Vivamus eget ligula porta, pulvinar ex vitae, sollicitudin erat. Maecenas semper ornare suscipit. Ut et neque condimentum lectus pulvinar maximus in sit amet odio. Aliquam congue purus erat, eu rutrum risus placerat a." 33 | label.autoresizingMask = [.flexibleWidth, .flexibleHeight] 34 | view.addSubview(label) 35 | } 36 | 37 | override var preferredStatusBarStyle: UIStatusBarStyle { 38 | return .lightContent 39 | } 40 | 41 | @objc func didTap() { 42 | dismiss(animated: true) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /img/motion-interchange-banner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-motion/motion-interchange-objc/835474053336d2004c079f7d6580f582a7a2b85a/img/motion-interchange-banner.gif -------------------------------------------------------------------------------- /resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /scripts/v1_to_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2017-present The Material Motion Authors. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Migration script from v1 to v2 interchange APIs. 18 | 19 | if [ "$#" -ne 1 ]; then 20 | echo "Usage: $(basename $0) " 21 | exit 1 22 | fi 23 | 24 | search_path="$1" 25 | 26 | replace_objc() { 27 | find "$search_path" -type f -name "*.h" | xargs sed -i '' "$1" 28 | find "$search_path" -type f -name "*.m" | xargs sed -i '' "$1" 29 | } 30 | 31 | replace_swift() { 32 | find "$search_path" -type f -name "*.swift" | xargs sed -i '' "$1" 33 | } 34 | 35 | replace_all() { 36 | replace_objc "$1" 37 | replace_swift "$1" 38 | } 39 | 40 | replace_all "s/timing.curve/traits.timingCurve/g" 41 | replace_all "s/traits.curve/traits.timingCurve/g" 42 | replace_objc "s/MDMMotionTiming/MDMAnimationTraits */g" 43 | replace_swift "s/MotionTiming/MDMAnimationTraits/g" 44 | -------------------------------------------------------------------------------- /src/CAMediaTimingFunction+MDMTimingCurve.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | 20 | #import "MDMTimingCurve.h" 21 | 22 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 23 | ios(12, API_TO_BE_DEPRECATED)) 24 | 25 | // A CAMediaTimingFunction is a timing curve - we simply define its conformity to our protocol here. 26 | @interface CAMediaTimingFunction () 27 | @end 28 | 29 | @interface CAMediaTimingFunction (MotionInterchangeExtension) 30 | 31 | /** 32 | Returns a instance of the timing function with its control points reversed. 33 | */ 34 | - (nonnull CAMediaTimingFunction *)mdm_reversed; 35 | 36 | /** 37 | Returns the first control point of the timing function. 38 | */ 39 | @property(nonatomic, assign, readonly) CGPoint mdm_point1; 40 | 41 | /** 42 | Returns the second control point of the timing function. 43 | */ 44 | @property(nonatomic, assign, readonly) CGPoint mdm_point2; 45 | 46 | @end 47 | 48 | API_DEPRECATED_END 49 | -------------------------------------------------------------------------------- /src/CAMediaTimingFunction+MDMTimingCurve.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import "CAMediaTimingFunction+MDMTimingCurve.h" 18 | 19 | @implementation CAMediaTimingFunction (MotionInterchangeExtension) 20 | 21 | - (CAMediaTimingFunction *)mdm_reversed { 22 | float pt1[2]; 23 | float pt2[2]; 24 | [self getControlPointAtIndex:1 values:pt1]; 25 | [self getControlPointAtIndex:2 values:pt2]; 26 | 27 | float reversedPt1[2]; 28 | float reversedPt2[2]; 29 | reversedPt1[0] = 1 - pt2[0]; 30 | reversedPt1[1] = 1 - pt2[1]; 31 | reversedPt2[0] = 1 - pt1[0]; 32 | reversedPt2[1] = 1 - pt1[1]; 33 | return [CAMediaTimingFunction functionWithControlPoints:reversedPt1[0] :reversedPt1[1] 34 | :reversedPt2[0] :reversedPt2[1]]; 35 | } 36 | 37 | - (CGPoint)mdm_point1 { 38 | float point[2]; 39 | [self getControlPointAtIndex:1 values:point]; 40 | return CGPointMake(point[0], point[1]); 41 | } 42 | 43 | - (CGPoint)mdm_point2 { 44 | float point[2]; 45 | [self getControlPointAtIndex:2 values:point]; 46 | return CGPointMake(point[0], point[1]); 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /src/MDMAnimationTraits.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | #import 20 | 21 | #import "MDMMotionTiming.h" 22 | #import "MDMRepetitionTraits.h" 23 | #import "MDMSubclassingRestricted.h" 24 | #import "MDMTimingCurve.h" 25 | 26 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 27 | ios(12, API_TO_BE_DEPRECATED)) 28 | 29 | /** 30 | A generic representation of animation traits. 31 | */ 32 | MDM_SUBCLASSING_RESTRICTED 33 | @interface MDMAnimationTraits: NSObject 34 | 35 | /** 36 | Initializes the instance with the provided duration and kCAMediaTimingFunctionEaseInEaseOut timing 37 | curve. 38 | 39 | @param duration The animation will occur over this length of time, in seconds. 40 | */ 41 | - (nonnull instancetype)initWithDuration:(NSTimeInterval)duration; 42 | 43 | /** 44 | Initializes the instance with the provided duration and named bezier timing curve. 45 | 46 | @param duration The animation will occur over this length of time, in seconds. 47 | @param animationCurve A UIKit bezier animation curve type. 48 | */ 49 | - (nonnull instancetype)initWithDuration:(NSTimeInterval)duration 50 | animationCurve:(UIViewAnimationCurve)animationCurve; 51 | 52 | /** 53 | Initializes the instance with the provided duration, delay, and 54 | kCAMediaTimingFunctionEaseInEaseOut timing curve. 55 | 56 | @param delay The amount of time, in seconds, to wait before starting the animation. 57 | @param duration The animation will occur over this length of time, in seconds, after the delay time 58 | has passed. 59 | */ 60 | - (nonnull instancetype)initWithDelay:(NSTimeInterval)delay duration:(NSTimeInterval)duration; 61 | 62 | /** 63 | Initializes the instance with the provided duration, delay, and named bezier timing curve. 64 | 65 | This is a convenience API for defining a timing curve using the Core Animation timing function 66 | names. See the documentation for CAMediaTimingFunction for more details. 67 | 68 | @param delay The amount of time, in seconds, to wait before starting the animation. 69 | @param duration The animation will occur over this length of time, in seconds, after the delay time 70 | has passed. 71 | @param animationCurve A UIKit bezier animation curve type. 72 | */ 73 | - (nonnull instancetype)initWithDelay:(NSTimeInterval)delay 74 | duration:(NSTimeInterval)duration 75 | animationCurve:(UIViewAnimationCurve)animationCurve; 76 | 77 | /** 78 | Initializes the instance with the provided duration, delay, and timing curve. 79 | 80 | @param delay The amount of time, in seconds, to wait before starting the animation. 81 | @param duration The animation will occur over this length of time, in seconds, after the delay time 82 | has passed. 83 | @param timingCurve If provided, defines the acceleration timing for the animation. If nil, the 84 | animation will be treated as instant and the duration/delay will be ignored. 85 | */ 86 | - (nonnull instancetype)initWithDelay:(NSTimeInterval)delay 87 | duration:(NSTimeInterval)duration 88 | timingCurve:(nullable id)timingCurve; 89 | 90 | /** 91 | Initializes an animation trait with the provided timing curve, duration, delay, and repetition. 92 | 93 | @param duration The animation will occur over this length of time, in seconds, after the delay time 94 | has passed. 95 | @param delay The amount of time, in seconds, to wait before starting the animation. 96 | @param timingCurve If provided, defines the acceleration timing for the animation. If nil, the 97 | animation will be treated as instant and the duration/delay will be ignored. 98 | @param repetition The repetition traits of the animation. Most often an instance of MDMRepetition 99 | or MDMRepetitionOverTime. If nil, the animation will not repeat. 100 | */ 101 | - (nonnull instancetype)initWithDelay:(NSTimeInterval)delay 102 | duration:(NSTimeInterval)duration 103 | timingCurve:(nullable id)timingCurve 104 | repetition:(nullable id)repetition 105 | NS_DESIGNATED_INITIALIZER; 106 | 107 | #pragma mark - Traits 108 | 109 | /** 110 | The amount of time, in seconds, before this animation's value interpolation should begin. 111 | */ 112 | @property(nonatomic, assign) NSTimeInterval delay; 113 | 114 | /** 115 | The amount of time, in seconds, over which this animation should interpolate between its values. 116 | */ 117 | @property(nonatomic, assign) NSTimeInterval duration; 118 | 119 | /** 120 | The velocity and acceleration of the animation over time. 121 | 122 | If the timing curve is nil then the timing is assumed to be "instant", regardless of duration and 123 | delay. 124 | */ 125 | @property(nonatomic, strong, nullable) id timingCurve; 126 | 127 | /** 128 | The repetition characteristics of the animation. 129 | 130 | If the repetition is nil then no repetition should occur. 131 | */ 132 | @property(nonatomic, strong, nullable) id repetition; 133 | 134 | #pragma mark - Unavailable 135 | 136 | /** 137 | Unavailable. 138 | */ 139 | - (nonnull instancetype)init NS_UNAVAILABLE; 140 | 141 | @end 142 | 143 | @interface MDMAnimationTraits (SystemTraits) 144 | 145 | /** 146 | Animation traits for an iOS modal presentation slide animation. 147 | */ 148 | @property(nonatomic, class, strong, nonnull, readonly) MDMAnimationTraits *systemModalMovement; 149 | 150 | @end 151 | 152 | @interface MDMAnimationTraits (Legacy) 153 | 154 | /** 155 | Initializes the instance with the provided legacy C-style animation trait structure. 156 | 157 | @param timing A legacy C-style representation of animation traits. 158 | */ 159 | - (nonnull instancetype)initWithMotionTiming:(MDMMotionTiming)timing; 160 | 161 | @end 162 | 163 | API_DEPRECATED_END 164 | -------------------------------------------------------------------------------- /src/MDMAnimationTraits.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import "MDMAnimationTraits.h" 18 | 19 | #import "CAMediaTimingFunction+MDMTimingCurve.h" 20 | #import "MDMRepetition.h" 21 | #import "MDMRepetitionOverTime.h" 22 | #import "MDMSpringTimingCurve.h" 23 | 24 | @implementation MDMAnimationTraits 25 | 26 | - (instancetype)init { 27 | [self doesNotRecognizeSelector:_cmd]; 28 | return nil; 29 | } 30 | 31 | - (nonnull instancetype)initWithDuration:(NSTimeInterval)duration { 32 | return [self initWithDelay:0 duration:duration]; 33 | } 34 | 35 | - (instancetype)initWithDuration:(NSTimeInterval)duration 36 | animationCurve:(UIViewAnimationCurve)animationCurve { 37 | return [self initWithDelay:0 duration:duration animationCurve:animationCurve]; 38 | } 39 | 40 | - (instancetype)initWithDelay:(NSTimeInterval)delay duration:(NSTimeInterval)duration { 41 | return [self initWithDelay:delay duration:duration animationCurve:UIViewAnimationCurveEaseInOut]; 42 | } 43 | 44 | - (instancetype)initWithDelay:(NSTimeInterval)delay 45 | duration:(NSTimeInterval)duration 46 | animationCurve:(UIViewAnimationCurve)animationCurve { 47 | CAMediaTimingFunction *timingCurve; 48 | switch (animationCurve) { 49 | case UIViewAnimationCurveEaseInOut: 50 | timingCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 51 | break; 52 | case UIViewAnimationCurveEaseIn: 53 | timingCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; 54 | break; 55 | case UIViewAnimationCurveEaseOut: 56 | timingCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 57 | break; 58 | case UIViewAnimationCurveLinear: 59 | timingCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 60 | break; 61 | } 62 | return [self initWithDelay:delay duration:duration timingCurve:timingCurve]; 63 | } 64 | 65 | - (instancetype)initWithDelay:(NSTimeInterval)delay 66 | duration:(NSTimeInterval)duration 67 | timingCurve:(id)timingCurve { 68 | return [self initWithDelay:delay duration:duration timingCurve:timingCurve repetition:nil]; 69 | } 70 | 71 | - (instancetype)initWithDelay:(NSTimeInterval)delay 72 | duration:(NSTimeInterval)duration 73 | timingCurve:(id)timingCurve 74 | repetition:(id)repetition { 75 | self = [super init]; 76 | if (self) { 77 | _duration = duration; 78 | _delay = delay; 79 | _timingCurve = timingCurve; 80 | _repetition = repetition; 81 | } 82 | return self; 83 | } 84 | 85 | - (nonnull instancetype)initWithMotionTiming:(MDMMotionTiming)timing { 86 | id timingCurve; 87 | switch (timing.curve.type) { 88 | case MDMMotionCurveTypeInstant: 89 | timingCurve = nil; 90 | break; 91 | #pragma clang diagnostic push 92 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 93 | case MDMMotionCurveTypeDefault: 94 | #pragma clang diagnostic pop 95 | case MDMMotionCurveTypeBezier: 96 | timingCurve = [CAMediaTimingFunction functionWithControlPoints:(float)timing.curve.data[0] 97 | :(float)timing.curve.data[1] 98 | :(float)timing.curve.data[2] 99 | :(float)timing.curve.data[3]]; 100 | break; 101 | case MDMMotionCurveTypeSpring: { 102 | CGFloat *data = timing.curve.data; 103 | timingCurve = 104 | [[MDMSpringTimingCurve alloc] initWithMass:data[MDMSpringMotionCurveDataIndexMass] 105 | tension:data[MDMSpringMotionCurveDataIndexTension] 106 | friction:data[MDMSpringMotionCurveDataIndexFriction] 107 | initialVelocity:data[MDMSpringMotionCurveDataIndexInitialVelocity]]; 108 | break; 109 | } 110 | } 111 | id repetition; 112 | switch (timing.repetition.type) { 113 | case MDMMotionRepetitionTypeNone: 114 | repetition = nil; 115 | break; 116 | 117 | case MDMMotionRepetitionTypeCount: 118 | repetition = [[MDMRepetition alloc] initWithNumberOfRepetitions:timing.repetition.amount 119 | autoreverses:timing.repetition.autoreverses]; 120 | break; 121 | case MDMMotionRepetitionTypeDuration: 122 | repetition = [[MDMRepetitionOverTime alloc] initWithDuration:timing.repetition.amount 123 | autoreverses:timing.repetition.autoreverses]; 124 | break; 125 | } 126 | return [self initWithDelay:timing.delay 127 | duration:timing.duration 128 | timingCurve:timingCurve 129 | repetition:repetition]; 130 | } 131 | 132 | #pragma mark - NSCopying 133 | 134 | - (id)copyWithZone:(NSZone *)zone { 135 | return [[[self class] alloc] initWithDelay:self.delay 136 | duration:self.duration 137 | timingCurve:[self.timingCurve copyWithZone:zone] 138 | repetition:[self.repetition copyWithZone:zone]]; 139 | } 140 | 141 | @end 142 | 143 | @implementation MDMAnimationTraits (SystemTraits) 144 | 145 | + (MDMAnimationTraits *)systemModalMovement { 146 | MDMSpringTimingCurve *timingCurve = [[MDMSpringTimingCurve alloc] initWithMass:3 147 | tension:1000 148 | friction:500]; 149 | return [[MDMAnimationTraits alloc] initWithDelay:0 duration:0.500 timingCurve:timingCurve]; 150 | } 151 | 152 | @end 153 | 154 | -------------------------------------------------------------------------------- /src/MDMMotionCurve.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | #import 20 | 21 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 22 | ios(12, API_TO_BE_DEPRECATED)) 23 | 24 | /** The possible kinds of motion curves that can be used to describe an animation. */ 25 | typedef NS_ENUM(NSUInteger, MDMMotionCurveType) { 26 | /** The value will be instantly set with no animation. */ 27 | MDMMotionCurveTypeInstant, 28 | 29 | /** The value will be animated using a cubic bezier curve to model its velocity. */ 30 | MDMMotionCurveTypeBezier, 31 | 32 | /** 33 | The value will be animated using a spring simulation. 34 | 35 | A spring will treat the duration property of the motion timing as a suggestion and may choose to 36 | ignore it altogether. 37 | */ 38 | MDMMotionCurveTypeSpring, 39 | 40 | /** The default curve will be used. */ 41 | MDMMotionCurveTypeDefault __deprecated_enum_msg("Use MDMMotionCurveTypeBezier instead."), 42 | 43 | } NS_SWIFT_NAME(MotionCurveType); 44 | 45 | /** 46 | A generalized representation of a motion curve. 47 | */ 48 | struct MDMMotionCurve { 49 | /** 50 | The type defines how to interpret the data values. 51 | */ 52 | MDMMotionCurveType type; 53 | 54 | /** 55 | The data values corresponding with this curve. 56 | */ 57 | CGFloat data[4]; 58 | } NS_SWIFT_NAME(MotionCurve); 59 | typedef struct MDMMotionCurve MDMMotionCurve; 60 | 61 | /** 62 | Creates a bezier motion curve with the provided control points. 63 | 64 | A cubic bezier has four control points in total. We assume that the first control point is 0, 0 and 65 | the last control point is 1, 1. This method requires that you provide the second and third control 66 | points. 67 | 68 | See the documentation for CAMediaTimingFunction for more information. 69 | */ 70 | // clang-format off 71 | FOUNDATION_EXTERN 72 | MDMMotionCurve MDMMotionCurveMakeBezier(CGFloat p1x, CGFloat p1y, CGFloat p2x, CGFloat p2y) 73 | NS_SWIFT_NAME(MotionCurveMakeBezier(p1x:p1y:p2x:p2y:)); 74 | // clang-format on 75 | 76 | // clang-format off 77 | FOUNDATION_EXTERN 78 | MDMMotionCurve MDMMotionCurveFromTimingFunction(CAMediaTimingFunction * _Nonnull timingFunction) 79 | NS_SWIFT_NAME(MotionCurve(fromTimingFunction:)); 80 | // clang-format on 81 | 82 | /** 83 | Creates a spring curve with the provided configuration. 84 | 85 | Tension and friction map to Core Animation's stiffness and damping, respectively. 86 | 87 | See the documentation for CASpringAnimation for more information. 88 | */ 89 | // clang-format off 90 | FOUNDATION_EXTERN MDMMotionCurve MDMMotionCurveMakeSpring(CGFloat mass, 91 | CGFloat tension, 92 | CGFloat friction) 93 | NS_SWIFT_NAME(MotionCurveMakeSpring(mass:tension:friction:)); 94 | // clang-format on 95 | 96 | /** 97 | Creates a spring curve with the provided configuration. 98 | 99 | Tension and friction map to Core Animation's stiffness and damping, respectively. 100 | 101 | See the documentation for CASpringAnimation for more information. 102 | */ 103 | // clang-format off 104 | FOUNDATION_EXTERN 105 | MDMMotionCurve MDMMotionCurveMakeSpringWithInitialVelocity(CGFloat mass, 106 | CGFloat tension, 107 | CGFloat friction, 108 | CGFloat initialVelocity) 109 | NS_SWIFT_NAME(MotionCurveMakeSpring(mass:tension:friction:initialVelocity:)); 110 | // clang-format on 111 | 112 | /** 113 | For cubic bezier curves, returns a reversed cubic bezier curve. For all other curve types, a copy 114 | of the original curve is returned. 115 | */ 116 | // clang-format off 117 | FOUNDATION_EXTERN MDMMotionCurve MDMMotionCurveReversedBezier(MDMMotionCurve motionCurve) 118 | NS_SWIFT_NAME(MotionCurveReversedBezier(fromMotionCurve:)); 119 | // clang-format on 120 | 121 | /** 122 | Named indices for the bezier motion curve's data array. 123 | */ 124 | typedef NS_ENUM(NSUInteger, MDMBezierMotionCurveDataIndex) { 125 | MDMBezierMotionCurveDataIndexP1X, 126 | MDMBezierMotionCurveDataIndexP1Y, 127 | MDMBezierMotionCurveDataIndexP2X, 128 | MDMBezierMotionCurveDataIndexP2Y 129 | } NS_SWIFT_NAME(BezierMotionCurveDataIndex); 130 | 131 | /** 132 | Named indices for the spring motion curve's data array. 133 | */ 134 | typedef NS_ENUM(NSUInteger, MDMSpringMotionCurveDataIndex) { 135 | MDMSpringMotionCurveDataIndexMass, 136 | MDMSpringMotionCurveDataIndexTension, 137 | MDMSpringMotionCurveDataIndexFriction, 138 | 139 | /** 140 | The initial velocity of the animation. 141 | 142 | A value of zero indicates no initial velocity. 143 | A positive value indicates movement toward the destination. 144 | A negative value indicates movement away from the destination. 145 | 146 | The value's units are dependent on the context and the value being animated. 147 | */ 148 | MDMSpringMotionCurveDataIndexInitialVelocity 149 | } NS_SWIFT_NAME(SpringMotionCurveDataIndex); 150 | 151 | // Objective-C-specific macros 152 | 153 | #define _MDMBezier(p1x, p1y, p2x, p2y) \ 154 | ((MDMMotionCurve) { \ 155 | .type = MDMMotionCurveTypeBezier, \ 156 | .data = { p1x, \ 157 | p1y, \ 158 | p2x, \ 159 | p2y } \ 160 | }) 161 | 162 | #define _MDMSpring(mass, tension, friction) \ 163 | ((MDMMotionCurve) { \ 164 | .type = MDMMotionCurveTypeSpring, \ 165 | .data = { mass, \ 166 | tension, \ 167 | friction } \ 168 | }) 169 | 170 | #define _MDMSpringWithInitialVelocity(mass, tension, friction, initialVelocity) \ 171 | ((MDMMotionCurve) { \ 172 | .type = MDMMotionCurveTypeSpring, \ 173 | .data = { mass, \ 174 | tension, \ 175 | friction, \ 176 | initialVelocity } \ 177 | }) 178 | 179 | /** 180 | A linear bezier motion curve. 181 | */ 182 | #define MDMLinearMotionCurve _MDMBezier(0, 0, 1, 1) 183 | 184 | /** 185 | Timing information for an iOS modal presentation slide animation. 186 | */ 187 | #define MDMModalMovementTiming { \ 188 | .delay = 0.000, .duration = 0.500, .curve = _MDMSpring(3, 1000, 500) \ 189 | } 190 | 191 | API_DEPRECATED_END 192 | -------------------------------------------------------------------------------- /src/MDMMotionCurve.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import "MDMMotionCurve.h" 18 | 19 | MDMMotionCurve MDMMotionCurveMakeBezier(CGFloat p1x, CGFloat p1y, CGFloat p2x, CGFloat p2y) { 20 | return _MDMBezier(p1x, p1y, p2x, p2y); 21 | } 22 | 23 | MDMMotionCurve MDMMotionCurveMakeSpring(CGFloat mass, CGFloat tension, CGFloat friction) { 24 | return MDMMotionCurveMakeSpringWithInitialVelocity(mass, tension, friction, 0); 25 | } 26 | 27 | MDMMotionCurve MDMMotionCurveMakeSpringWithInitialVelocity(CGFloat mass, 28 | CGFloat tension, 29 | CGFloat friction, 30 | CGFloat initialVelocity) { 31 | return _MDMSpringWithInitialVelocity(mass, tension, friction, initialVelocity); 32 | } 33 | 34 | MDMMotionCurve MDMMotionCurveFromTimingFunction(CAMediaTimingFunction *timingFunction) { 35 | float pt1[2]; 36 | float pt2[2]; 37 | [timingFunction getControlPointAtIndex:1 values:pt1]; 38 | [timingFunction getControlPointAtIndex:2 values:pt2]; 39 | return MDMMotionCurveMakeBezier(pt1[0], pt1[1], pt2[0], pt2[1]); 40 | } 41 | 42 | MDMMotionCurve MDMMotionCurveReversedBezier(MDMMotionCurve motionCurve) { 43 | MDMMotionCurve reversed = motionCurve; 44 | if (motionCurve.type == MDMMotionCurveTypeBezier) { 45 | reversed.data[0] = 1 - motionCurve.data[2]; 46 | reversed.data[1] = 1 - motionCurve.data[3]; 47 | reversed.data[2] = 1 - motionCurve.data[0]; 48 | reversed.data[3] = 1 - motionCurve.data[1]; 49 | } 50 | return reversed; 51 | } 52 | -------------------------------------------------------------------------------- /src/MDMMotionRepetition.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | 20 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 21 | ios(12, API_TO_BE_DEPRECATED)) 22 | 23 | /** 24 | The possible kinds of repetition that can be used to describe an animation. 25 | */ 26 | typedef NS_ENUM(NSUInteger, MDMMotionRepetitionType) { 27 | /** 28 | The animation will be not be repeated. 29 | */ 30 | MDMMotionRepetitionTypeNone, 31 | 32 | /** 33 | The animation will be repeated a given number of times. 34 | */ 35 | MDMMotionRepetitionTypeCount, 36 | 37 | /** 38 | The animation will be repeated for a given number of seconds. 39 | */ 40 | MDMMotionRepetitionTypeDuration, 41 | 42 | } NS_SWIFT_NAME(MotionReptitionType); 43 | 44 | /** 45 | A generalized representation of a motion curve. 46 | */ 47 | struct MDMMotionRepetition { 48 | /** 49 | The type defines how to interpret the amount. 50 | */ 51 | MDMMotionRepetitionType type; 52 | 53 | /** 54 | The amount of repetition. 55 | */ 56 | double amount; 57 | 58 | /** 59 | Whether the animation should animate backwards after animating forwards. 60 | */ 61 | BOOL autoreverses; 62 | 63 | } NS_SWIFT_NAME(MotionRepetition); 64 | typedef struct MDMMotionRepetition MDMMotionRepetition; 65 | 66 | // Objective-C-specific macros 67 | 68 | #define _MDMNoRepetition \ 69 | (MDMMotionRepetition) { \ 70 | .type = MDMMotionRepetitionTypeNone, \ 71 | .amount = 0, \ 72 | .autoreverses = false \ 73 | } 74 | 75 | API_DEPRECATED_END 76 | -------------------------------------------------------------------------------- /src/MDMMotionTiming.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | 20 | #import "MDMMotionCurve.h" 21 | #import "MDMMotionRepetition.h" 22 | 23 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 24 | ios(12, API_TO_BE_DEPRECATED)) 25 | 26 | /** 27 | A representation of timing for an animation. 28 | */ 29 | struct MDMMotionTiming { 30 | /** 31 | The amount of time, in seconds, before this animation's value interpolation should begin. 32 | */ 33 | CFTimeInterval delay; 34 | 35 | /** 36 | The amount of time, in seconds, over which this animation should interpolate between its values. 37 | */ 38 | CFTimeInterval duration; 39 | 40 | /** 41 | The velocity and acceleration of the animation over time. 42 | */ 43 | MDMMotionCurve curve; 44 | 45 | /** 46 | The repetition characteristics of the animation. 47 | */ 48 | MDMMotionRepetition repetition; 49 | 50 | } NS_SWIFT_NAME(MotionTiming); 51 | typedef struct MDMMotionTiming MDMMotionTiming; 52 | 53 | API_DEPRECATED_END 54 | -------------------------------------------------------------------------------- /src/MDMRepetition.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | 19 | #import "MDMRepetitionTraits.h" 20 | #import "MDMSubclassingRestricted.h" 21 | 22 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 23 | ios(12, API_TO_BE_DEPRECATED)) 24 | 25 | /** 26 | Represents repetition that repeats a specific number of times. 27 | */ 28 | MDM_SUBCLASSING_RESTRICTED 29 | @interface MDMRepetition: NSObject 30 | 31 | /** 32 | Initializes the instance with the given number of repetitions. 33 | 34 | Autoreversing is disabled. 35 | 36 | @param numberOfRepetitions May be fractional. Initializing with greatestFiniteMagnitude will cause 37 | the animation to repeat forever. 38 | */ 39 | - (nonnull instancetype)initWithNumberOfRepetitions:(double)numberOfRepetitions; 40 | 41 | /** 42 | Initializes the instance with the given number of repetitions and autoreversal behavior. 43 | 44 | @param numberOfRepetitions May be fractional. Initializing with greatestFiniteMagnitude will cause 45 | the animation to repeat forever. 46 | @param autoreverses Whether the animation should animate backwards after animating forwards. 47 | */ 48 | - (nonnull instancetype)initWithNumberOfRepetitions:(double)numberOfRepetitions 49 | autoreverses:(BOOL)autoreverses 50 | NS_DESIGNATED_INITIALIZER; 51 | 52 | #pragma mark - Traits 53 | 54 | /** 55 | The number of repetitions that will occur before this animation stops repeating. 56 | */ 57 | @property(nonatomic, assign) double numberOfRepetitions; 58 | 59 | /** 60 | Unavailable. 61 | */ 62 | - (nonnull instancetype)init NS_UNAVAILABLE; 63 | 64 | @end 65 | 66 | API_DEPRECATED_END 67 | -------------------------------------------------------------------------------- /src/MDMRepetition.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import "MDMRepetition.h" 18 | 19 | @implementation MDMRepetition 20 | 21 | @synthesize autoreverses = _autoreverses; 22 | 23 | - (instancetype)init { 24 | [self doesNotRecognizeSelector:_cmd]; 25 | return nil; 26 | } 27 | 28 | - (instancetype)initWithNumberOfRepetitions:(double)numberOfRepetitions { 29 | return [self initWithNumberOfRepetitions:numberOfRepetitions autoreverses:NO]; 30 | } 31 | 32 | - (instancetype)initWithNumberOfRepetitions:(double)numberOfRepetitions 33 | autoreverses:(BOOL)autoreverses { 34 | self = [super init]; 35 | if (self) { 36 | _numberOfRepetitions = numberOfRepetitions; 37 | _autoreverses = autoreverses; 38 | } 39 | return self; 40 | } 41 | 42 | #pragma mark - NSCopying 43 | 44 | - (id)copyWithZone:(__unused NSZone *)zone { 45 | return [[[self class] alloc] initWithNumberOfRepetitions:self.numberOfRepetitions 46 | autoreverses:self.autoreverses]; 47 | } 48 | 49 | @end 50 | 51 | -------------------------------------------------------------------------------- /src/MDMRepetitionOverTime.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | 19 | #import "MDMRepetitionTraits.h" 20 | #import "MDMSubclassingRestricted.h" 21 | 22 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 23 | ios(12, API_TO_BE_DEPRECATED)) 24 | 25 | /** 26 | Represents repetition that repeats until a specific duration has passed. 27 | */ 28 | MDM_SUBCLASSING_RESTRICTED 29 | @interface MDMRepetitionOverTime: NSObject 30 | 31 | /** 32 | Initializes the instance with the given duration. 33 | 34 | @param duration The amount of time, in seconds, over which the animation will repeat. 35 | */ 36 | - (nonnull instancetype)initWithDuration:(double)duration; 37 | 38 | /** 39 | Initializes the instance with the given duration and autoreversal behavior. 40 | 41 | @param duration The amount of time, in seconds, over which the animation will repeat. 42 | @param autoreverses Whether the animation should animate backwards after animating forwards. 43 | */ 44 | - (nonnull instancetype)initWithDuration:(double)duration autoreverses:(BOOL)autoreverses 45 | NS_DESIGNATED_INITIALIZER; 46 | 47 | #pragma mark - Traits 48 | 49 | /** 50 | The amount of time, in seconds, that will pass before this animation stops repeating. 51 | */ 52 | @property(nonatomic, assign) double duration; 53 | 54 | /** 55 | Unavailable. 56 | */ 57 | - (nonnull instancetype)init NS_UNAVAILABLE; 58 | 59 | @end 60 | 61 | API_DEPRECATED_END 62 | -------------------------------------------------------------------------------- /src/MDMRepetitionOverTime.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import "MDMRepetitionOverTime.h" 18 | 19 | @implementation MDMRepetitionOverTime 20 | 21 | @synthesize autoreverses = _autoreverses; 22 | 23 | - (instancetype)init { 24 | [self doesNotRecognizeSelector:_cmd]; 25 | return nil; 26 | } 27 | 28 | - (instancetype)initWithDuration:(double)duration { 29 | return [self initWithDuration:duration autoreverses:NO]; 30 | } 31 | 32 | - (instancetype)initWithDuration:(double)duration autoreverses:(BOOL)autoreverses { 33 | self = [super init]; 34 | if (self) { 35 | _duration = duration; 36 | _autoreverses = autoreverses; 37 | } 38 | return self; 39 | } 40 | 41 | #pragma mark - NSCopying 42 | 43 | - (id)copyWithZone:(__unused NSZone *)zone { 44 | return [[[self class] alloc] initWithDuration:self.duration autoreverses:self.autoreverses]; 45 | } 46 | 47 | @end 48 | 49 | -------------------------------------------------------------------------------- /src/MDMRepetitionTraits.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | 19 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 20 | ios(12, API_TO_BE_DEPRECATED)) 21 | 22 | /** 23 | A generalized representation of a repetition traits. 24 | */ 25 | @protocol MDMRepetitionTraits 26 | 27 | /** 28 | Whether the animation should animate backwards after animating forwards. 29 | */ 30 | @property(nonatomic, assign) BOOL autoreverses; 31 | 32 | @end 33 | 34 | API_DEPRECATED_END 35 | -------------------------------------------------------------------------------- /src/MDMSpringTimingCurve.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | 20 | #import "MDMSubclassingRestricted.h" 21 | #import "MDMTimingCurve.h" 22 | 23 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 24 | ios(12, API_TO_BE_DEPRECATED)) 25 | 26 | /** 27 | A timing curve that represents the motion of a single-dimensional attached spring. 28 | */ 29 | MDM_SUBCLASSING_RESTRICTED 30 | @interface MDMSpringTimingCurve: NSObject 31 | 32 | /** 33 | Initializes the timing curve with the given parameters and an initial velocity of zero. 34 | 35 | @param mass The mass of the spring simulation. Affects the animation's momentum. 36 | @param tension The tension of the spring simulation. Affects how quickly the animation moves 37 | toward its destination. 38 | @param friction The friction of the spring simulation. Affects how quickly the animation starts 39 | and stops. 40 | */ 41 | - (nonnull instancetype)initWithMass:(CGFloat)mass 42 | tension:(CGFloat)tension 43 | friction:(CGFloat)friction; 44 | 45 | /** 46 | Initializes the timing curve with the given parameters. 47 | 48 | @param mass The mass of the spring simulation. Affects the animation's momentum. 49 | @param tension The tension of the spring simulation. Affects how quickly the animation moves 50 | toward its destination. 51 | @param friction The friction of the spring simulation. Affects how quickly the animation starts 52 | and stops. 53 | @param initialVelocity The initial velocity of the spring simulation. Measured in units of 54 | translation per second. For example, if the property being animated is positional, then this value 55 | is in screen units per second. 56 | */ 57 | - (nonnull instancetype)initWithMass:(CGFloat)mass 58 | tension:(CGFloat)tension 59 | friction:(CGFloat)friction 60 | initialVelocity:(CGFloat)initialVelocity 61 | NS_DESIGNATED_INITIALIZER; 62 | 63 | #pragma mark - Traits 64 | 65 | /** 66 | The mass of the spring simulation. 67 | 68 | Affects the animation's momentum. This is usually 1. 69 | */ 70 | @property(nonatomic, assign) CGFloat mass; 71 | 72 | /** 73 | The tension of the spring simulation. 74 | 75 | Affects how quickly the animation moves toward its destination. 76 | */ 77 | @property(nonatomic, assign) CGFloat tension; 78 | 79 | /** 80 | The friction of the spring simulation. 81 | 82 | Affects how quickly the animation starts and stops. 83 | */ 84 | @property(nonatomic, assign) CGFloat friction; 85 | 86 | /** 87 | The initial velocity of the spring simulation. 88 | 89 | Measured in units of translation per second. 90 | 91 | If this timing curve was initialized using a damping ratio then setting a new initial velocity 92 | will also change the the mass/tension/friction values according to the new UIKit damping 93 | coefficient calculation. 94 | */ 95 | @property(nonatomic, assign) CGFloat initialVelocity; 96 | 97 | /** Unavailable. */ 98 | - (nonnull instancetype)init NS_UNAVAILABLE; 99 | 100 | @end 101 | 102 | API_DEPRECATED_END 103 | -------------------------------------------------------------------------------- /src/MDMSpringTimingCurve.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import "MDMSpringTimingCurve.h" 18 | 19 | @implementation MDMSpringTimingCurve 20 | 21 | - (instancetype)init { 22 | [self doesNotRecognizeSelector:_cmd]; 23 | return nil; 24 | } 25 | 26 | - (instancetype)initWithMass:(CGFloat)mass tension:(CGFloat)tension friction:(CGFloat)friction { 27 | return [self initWithMass:mass tension:tension friction:friction initialVelocity:0]; 28 | } 29 | 30 | - (instancetype)initWithMass:(CGFloat)mass 31 | tension:(CGFloat)tension 32 | friction:(CGFloat)friction 33 | initialVelocity:(CGFloat)initialVelocity { 34 | self = [super init]; 35 | if (self) { 36 | _mass = mass; 37 | _tension = tension; 38 | _friction = friction; 39 | _initialVelocity = initialVelocity; 40 | } 41 | return self; 42 | } 43 | 44 | #pragma mark - NSCopying 45 | 46 | - (id)copyWithZone:(NSZone *)zone { 47 | return [[[self class] allocWithZone:zone] initWithMass:self.mass 48 | tension:self.tension 49 | friction:self.friction 50 | initialVelocity:self.initialVelocity];; 51 | } 52 | 53 | #pragma mark - Private 54 | 55 | @end 56 | 57 | -------------------------------------------------------------------------------- /src/MDMSpringTimingCurveGenerator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | 20 | #import "MDMSubclassingRestricted.h" 21 | #import "MDMTimingCurve.h" 22 | 23 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 24 | ios(12, API_TO_BE_DEPRECATED)) 25 | 26 | @class MDMSpringTimingCurve; 27 | 28 | /** 29 | A spring timing curve generator based on UIKit duration/dampingRatio-based coefficients. 30 | */ 31 | MDM_SUBCLASSING_RESTRICTED 32 | @interface MDMSpringTimingCurveGenerator : NSObject 33 | 34 | /** 35 | Initializes the timing curve with the given UIKit spring damping ratio. 36 | 37 | @param duration The desired duration of the spring animation. 38 | @param dampingRatio From the UIKit documentation: "When `dampingRatio` is 1, the animation will 39 | smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will 40 | oscillate more and more before coming to a complete stop." 41 | */ 42 | - (nonnull instancetype)initWithDuration:(NSTimeInterval)duration 43 | dampingRatio:(CGFloat)dampingRatio; 44 | 45 | /** 46 | Initializes the timing curve with the given UIKit spring damping ratio and initial velocity. 47 | 48 | @param duration The desired duration of the spring animation. 49 | @param dampingRatio From the UIKit documentation: "When `dampingRatio` is 1, the animation will 50 | smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will 51 | oscillate more and more before coming to a complete stop." 52 | @param initialVelocity From the UIKit documentation: "You can use the initial spring velocity to 53 | specify how fast the object at the end of the simulated spring was moving before it was attached. 54 | It's a unit coordinate system, where 1 is defined as travelling the total animation distance in a 55 | second. So if you're changing an object's position by 200pt in this animation, and you want the 56 | animation to behave as if the object was moving at 100pt/s before the animation started, you'd 57 | pass 0.5. You'll typically want to pass 0 for the velocity." 58 | */ 59 | - (nonnull instancetype)initWithDuration:(NSTimeInterval)duration 60 | dampingRatio:(CGFloat)dampingRatio 61 | initialVelocity:(CGFloat)initialVelocity 62 | NS_DESIGNATED_INITIALIZER; 63 | 64 | #pragma mark - Traits 65 | 66 | /** 67 | The desired duration of the spring animation. 68 | */ 69 | @property(nonatomic, assign) NSTimeInterval duration; 70 | 71 | /** 72 | From the UIKit documentation: "When `dampingRatio` is 1, the animation will 73 | smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will 74 | oscillate more and more before coming to a complete stop." 75 | */ 76 | @property(nonatomic, assign) CGFloat dampingRatio; 77 | 78 | /** 79 | From the UIKit documentation: "You can use the initial spring velocity to 80 | specify how fast the object at the end of the simulated spring was moving before it was attached. 81 | It's a unit coordinate system, where 1 is defined as travelling the total animation distance in a 82 | second. So if you're changing an object's position by 200pt in this animation, and you want the 83 | animation to behave as if the object was moving at 100pt/s before the animation started, you'd 84 | pass 0.5. You'll typically want to pass 0 for the velocity." 85 | */ 86 | @property(nonatomic, assign) CGFloat initialVelocity; 87 | 88 | /** 89 | Creates and returns a new spring timing curve instance with the current configuration. 90 | */ 91 | - (nonnull MDMSpringTimingCurve *)springTimingCurve; 92 | 93 | /** Unavailable. */ 94 | - (nonnull instancetype)init NS_UNAVAILABLE; 95 | 96 | @end 97 | 98 | API_DEPRECATED_END 99 | -------------------------------------------------------------------------------- /src/MDMSpringTimingCurveGenerator.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import "MDMSpringTimingCurveGenerator.h" 18 | 19 | #import "MDMSpringTimingCurve.h" 20 | 21 | #import 22 | 23 | @implementation MDMSpringTimingCurveGenerator 24 | 25 | - (instancetype)initWithDuration:(NSTimeInterval)duration dampingRatio:(CGFloat)dampingRatio { 26 | return [self initWithDuration:duration dampingRatio:dampingRatio initialVelocity:0]; 27 | } 28 | 29 | - (nonnull instancetype)initWithDuration:(NSTimeInterval)duration 30 | dampingRatio:(CGFloat)dampingRatio 31 | initialVelocity:(CGFloat)initialVelocity { 32 | self = [super init]; 33 | if (self) { 34 | _duration = duration; 35 | _dampingRatio = dampingRatio; 36 | _initialVelocity = initialVelocity; 37 | } 38 | return self; 39 | } 40 | 41 | #pragma mark - NSCopying 42 | 43 | - (id)copyWithZone:(NSZone *)zone { 44 | return [[[self class] allocWithZone:zone] initWithDuration:self.duration 45 | dampingRatio:self.dampingRatio 46 | initialVelocity:self.initialVelocity]; 47 | } 48 | 49 | - (MDMSpringTimingCurve *)springTimingCurve { 50 | UIView *view = [[UIView alloc] init]; 51 | [UIView animateWithDuration:self.duration 52 | delay:0 53 | usingSpringWithDamping:self.dampingRatio 54 | initialSpringVelocity:self.initialVelocity 55 | options:0 56 | animations:^{ 57 | view.center = CGPointMake(100, 100); 58 | } completion:nil]; 59 | 60 | NSString *animationKey = [view.layer.animationKeys firstObject]; 61 | NSAssert(animationKey != nil, @"Unable to extract animation timing curve: no animation found."); 62 | #pragma clang diagnostic push 63 | // CASpringAnimation is a private API on iOS 8 - we're able to make use of it because we're 64 | // linking against the public API on iOS 9+. 65 | #pragma clang diagnostic ignored "-Wpartial-availability" 66 | CASpringAnimation *springAnimation = 67 | (CASpringAnimation *)[view.layer animationForKey:animationKey]; 68 | NSAssert([springAnimation isKindOfClass:[CASpringAnimation class]], 69 | @"Unable to extract animation timing curve: unexpected animation type."); 70 | #pragma clang diagnostic pop 71 | 72 | return [[MDMSpringTimingCurve alloc] initWithMass:springAnimation.mass 73 | tension:springAnimation.stiffness 74 | friction:springAnimation.damping 75 | initialVelocity:self.initialVelocity]; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /src/MDMSubclassingRestricted.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | 19 | #ifndef MDM_SUBCLASSING_RESTRICTED 20 | #if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) 21 | #define MDM_SUBCLASSING_RESTRICTED __attribute__((objc_subclassing_restricted)) 22 | #else 23 | #define MDM_SUBCLASSING_RESTRICTED 24 | #endif 25 | #endif // #ifndef MDM_SUBCLASSING_RESTRICTED 26 | 27 | -------------------------------------------------------------------------------- /src/MDMTimingCurve.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | #import 19 | 20 | API_DEPRECATED_BEGIN("Use standard UIKit/CALayer animation APIs instead.", 21 | ios(12, API_TO_BE_DEPRECATED)) 22 | 23 | /** 24 | A generalized representation of a timing curve. 25 | */ 26 | @protocol MDMTimingCurve 27 | @end 28 | 29 | API_DEPRECATED_END 30 | -------------------------------------------------------------------------------- /src/MotionInterchange.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | // V2 APIs 18 | #import "CAMediaTimingFunction+MDMTimingCurve.h" 19 | #import "MDMAnimationTraits.h" 20 | #import "MDMRepetitionTraits.h" 21 | #import "MDMRepetition.h" 22 | #import "MDMRepetitionOverTime.h" 23 | #import "MDMTimingCurve.h" 24 | #import "MDMSpringTimingCurve.h" 25 | #import "MDMSpringTimingCurveGenerator.h" 26 | 27 | // V1 APIs 28 | #import "MDMMotionCurve.h" 29 | #import "MDMMotionRepetition.h" 30 | #import "MDMMotionTiming.h" 31 | -------------------------------------------------------------------------------- /tests/unit/CAMediaTimingFunctionTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import XCTest 18 | import MotionInterchange 19 | 20 | class CAMediaTimingFunctionTests: XCTestCase { 21 | func testReversalAlgorithm() { 22 | let curve = CAMediaTimingFunction(controlPoints: 0.1, 0.2, 0.3, 0.4) 23 | let reversed = curve.mdm_reversed() 24 | XCTAssertEqual(curve.mdm_point1.x, 1 - reversed.mdm_point2.x, accuracy: 0.001) 25 | XCTAssertEqual(curve.mdm_point1.y, 1 - reversed.mdm_point2.y, accuracy: 0.001) 26 | XCTAssertEqual(curve.mdm_point2.x, 1 - reversed.mdm_point1.x, accuracy: 0.001) 27 | XCTAssertEqual(curve.mdm_point2.y, 1 - reversed.mdm_point1.y, accuracy: 0.001) 28 | } 29 | 30 | func testReversingBezierCurveTwiceGivesSameResult() { 31 | let curve = CAMediaTimingFunction(controlPoints: 0.1, 0.2, 0.3, 0.4) 32 | let reversed = curve.mdm_reversed() 33 | let reversedAgain = reversed.mdm_reversed() 34 | XCTAssertEqual(curve.mdm_point1.x, reversedAgain.mdm_point1.x, accuracy: 0.001) 35 | XCTAssertEqual(curve.mdm_point1.y, reversedAgain.mdm_point1.y, accuracy: 0.001) 36 | XCTAssertEqual(curve.mdm_point2.x, reversedAgain.mdm_point2.x, accuracy: 0.001) 37 | XCTAssertEqual(curve.mdm_point2.y, reversedAgain.mdm_point2.y, accuracy: 0.001) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/unit/MDMAnimationTraitsTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import XCTest 18 | import MotionInterchange 19 | 20 | class MDMAnimationTraitsTests: XCTestCase { 21 | 22 | func testInitializerValuesWithDuration() { 23 | let traits = MDMAnimationTraits(duration: 0.5) 24 | 25 | XCTAssertEqual(traits.duration, 0.5, accuracy: 0.001) 26 | XCTAssertEqual(traits.delay, 0, accuracy: 0.001) 27 | XCTAssertTrue(traits.timingCurve is CAMediaTimingFunction) 28 | if let timingCurve = traits.timingCurve as? CAMediaTimingFunction { 29 | let easeInOut = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 30 | XCTAssertEqual(timingCurve.mdm_point1.x, easeInOut.mdm_point1.x, accuracy: 0.001) 31 | XCTAssertEqual(timingCurve.mdm_point1.y, easeInOut.mdm_point1.y, accuracy: 0.001) 32 | XCTAssertEqual(timingCurve.mdm_point2.x, easeInOut.mdm_point2.x, accuracy: 0.001) 33 | XCTAssertEqual(timingCurve.mdm_point2.y, easeInOut.mdm_point2.y, accuracy: 0.001) 34 | } 35 | XCTAssertNil(traits.repetition) 36 | } 37 | 38 | func testInitializerValuesWithDurationAndEaseInCurve() { 39 | let traits = MDMAnimationTraits(duration: 0.5, animationCurve: .easeIn) 40 | 41 | XCTAssertEqual(traits.duration, 0.5, accuracy: 0.001) 42 | XCTAssertEqual(traits.delay, 0, accuracy: 0.001) 43 | XCTAssertTrue(traits.timingCurve is CAMediaTimingFunction) 44 | if let timingCurve = traits.timingCurve as? CAMediaTimingFunction { 45 | let easeInOut = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) 46 | XCTAssertEqual(timingCurve.mdm_point1.x, easeInOut.mdm_point1.x, accuracy: 0.001) 47 | XCTAssertEqual(timingCurve.mdm_point1.y, easeInOut.mdm_point1.y, accuracy: 0.001) 48 | XCTAssertEqual(timingCurve.mdm_point2.x, easeInOut.mdm_point2.x, accuracy: 0.001) 49 | XCTAssertEqual(timingCurve.mdm_point2.y, easeInOut.mdm_point2.y, accuracy: 0.001) 50 | } 51 | XCTAssertNil(traits.repetition) 52 | } 53 | 54 | func testInitializerValuesWithDurationDelay() { 55 | let traits = MDMAnimationTraits(delay: 0.2, duration: 0.5) 56 | 57 | XCTAssertEqual(traits.duration, 0.5, accuracy: 0.001) 58 | XCTAssertEqual(traits.delay, 0.2, accuracy: 0.001) 59 | XCTAssertTrue(traits.timingCurve is CAMediaTimingFunction) 60 | if let timingCurve = traits.timingCurve as? CAMediaTimingFunction { 61 | let easeInOut = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 62 | XCTAssertEqual(timingCurve.mdm_point1.x, easeInOut.mdm_point1.x, accuracy: 0.001) 63 | XCTAssertEqual(timingCurve.mdm_point1.y, easeInOut.mdm_point1.y, accuracy: 0.001) 64 | XCTAssertEqual(timingCurve.mdm_point2.x, easeInOut.mdm_point2.x, accuracy: 0.001) 65 | XCTAssertEqual(timingCurve.mdm_point2.y, easeInOut.mdm_point2.y, accuracy: 0.001) 66 | } 67 | XCTAssertNil(traits.repetition) 68 | } 69 | 70 | func testInitializerValuesWithDurationDelayNilTimingCurve() { 71 | let traits = MDMAnimationTraits(delay: 0.2, duration: 0.5, timingCurve: nil) 72 | 73 | XCTAssertEqual(traits.duration, 0.5, accuracy: 0.001) 74 | XCTAssertEqual(traits.delay, 0.2, accuracy: 0.001) 75 | XCTAssertNil(traits.timingCurve) 76 | XCTAssertNil(traits.repetition) 77 | } 78 | 79 | func testInitializerValuesWithDurationDelayLinearTimingCurve() { 80 | let linear = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) 81 | let traits = MDMAnimationTraits(delay: 0.2, duration: 0.5, timingCurve: linear) 82 | 83 | XCTAssertEqual(traits.duration, 0.5, accuracy: 0.001) 84 | XCTAssertEqual(traits.delay, 0.2, accuracy: 0.001) 85 | XCTAssertTrue(traits.timingCurve is CAMediaTimingFunction) 86 | if let timingCurve = traits.timingCurve as? CAMediaTimingFunction { 87 | XCTAssertEqual(timingCurve.mdm_point1.x, linear.mdm_point1.x, accuracy: 0.001) 88 | XCTAssertEqual(timingCurve.mdm_point1.y, linear.mdm_point1.y, accuracy: 0.001) 89 | XCTAssertEqual(timingCurve.mdm_point2.x, linear.mdm_point2.x, accuracy: 0.001) 90 | XCTAssertEqual(timingCurve.mdm_point2.y, linear.mdm_point2.y, accuracy: 0.001) 91 | } 92 | XCTAssertNil(traits.repetition) 93 | } 94 | 95 | func testInitializerValuesWithDurationDelaySpringTimingCurve() { 96 | let spring = MDMSpringTimingCurve(mass: 0.7, tension: 0.8, friction: 0.9) 97 | let traits = MDMAnimationTraits(delay: 0.2, duration: 0.5, timingCurve: spring) 98 | 99 | XCTAssertEqual(traits.duration, 0.5, accuracy: 0.001) 100 | XCTAssertEqual(traits.delay, 0.2, accuracy: 0.001) 101 | XCTAssertTrue(traits.timingCurve is MDMSpringTimingCurve) 102 | if let timingCurve = traits.timingCurve as? MDMSpringTimingCurve { 103 | XCTAssertEqual(timingCurve.mass, spring.mass, accuracy: 0.001) 104 | XCTAssertEqual(timingCurve.friction, spring.friction, accuracy: 0.001) 105 | XCTAssertEqual(timingCurve.tension, spring.tension, accuracy: 0.001) 106 | XCTAssertEqual(timingCurve.initialVelocity, spring.initialVelocity, 107 | accuracy: 0.001) 108 | } 109 | XCTAssertNil(traits.repetition) 110 | } 111 | 112 | func testInitializerValuesWithDurationDelayNilTimingCurveRepetition() { 113 | let repetition = MDMRepetition(numberOfRepetitions: 5) 114 | let traits = MDMAnimationTraits(delay: 0.2, 115 | duration: 0.5, 116 | timingCurve: nil, 117 | repetition: repetition) 118 | 119 | XCTAssertEqual(traits.duration, 0.5, accuracy: 0.001) 120 | XCTAssertEqual(traits.delay, 0.2, accuracy: 0.001) 121 | XCTAssertNil(traits.timingCurve) 122 | XCTAssertTrue(traits.repetition is MDMRepetition) 123 | if let setRepetition = traits.repetition as? MDMRepetition { 124 | XCTAssertEqual(setRepetition.numberOfRepetitions, repetition.numberOfRepetitions, 125 | accuracy: 0.001) 126 | XCTAssertEqual(setRepetition.autoreverses, repetition.autoreverses) 127 | } 128 | } 129 | 130 | func testModifyingACopyDoesNotModifyTheOriginal() { 131 | let spring = MDMSpringTimingCurve(mass: 0.7, tension: 0.8, friction: 0.9) 132 | let repetition = MDMRepetition(numberOfRepetitions: 5) 133 | let traits = MDMAnimationTraits(delay: 0.2, 134 | duration: 0.5, 135 | timingCurve: spring, 136 | repetition: repetition) 137 | 138 | let copy = traits.copy() as! MDMAnimationTraits 139 | copy.delay = copy.delay + 1 140 | copy.duration = copy.duration + 1 141 | if let springCopy = copy.timingCurve as? MDMSpringTimingCurve { 142 | springCopy.friction = springCopy.friction + 1 143 | springCopy.tension = springCopy.tension + 1 144 | springCopy.mass = springCopy.mass + 1 145 | springCopy.initialVelocity = springCopy.initialVelocity + 1 146 | 147 | XCTAssertNotEqual(springCopy.friction, spring.friction, accuracy: 0.001) 148 | XCTAssertNotEqual(springCopy.tension, spring.tension, accuracy: 0.001) 149 | XCTAssertNotEqual(springCopy.mass, spring.mass, accuracy: 0.001) 150 | XCTAssertNotEqual(springCopy.initialVelocity, spring.initialVelocity, accuracy: 0.001) 151 | } 152 | if let repetitionCopy = copy.repetition as? MDMRepetition { 153 | repetitionCopy.autoreverses = !repetitionCopy.autoreverses 154 | repetitionCopy.numberOfRepetitions = repetitionCopy.numberOfRepetitions + 1 155 | 156 | XCTAssertNotEqual(repetitionCopy.autoreverses, repetition.autoreverses) 157 | XCTAssertNotEqual(repetitionCopy.numberOfRepetitions, repetition.numberOfRepetitions) 158 | } 159 | 160 | XCTAssertNotEqual(copy.duration, traits.duration, accuracy: 0.001) 161 | XCTAssertNotEqual(copy.delay, traits.delay, accuracy: 0.001) 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /tests/unit/MDMLegacyAPITests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import XCTest 18 | import MotionInterchange 19 | 20 | class MDMLegacyAPITests: XCTestCase { 21 | 22 | func testTimingValuesMatchTraitValues() { 23 | let timing = MotionTiming(delay: 0.1, 24 | duration: 0.2, 25 | curve: MotionCurveMakeBezier(p1x: 0.3, p1y: 0.4, p2x: 0.5, p2y: 0.6), 26 | repetition: .init(type: .duration, amount: 0.7, autoreverses: true)) 27 | 28 | let traits = MDMAnimationTraits(motionTiming: timing) 29 | 30 | XCTAssertEqual(traits.duration, timing.duration, accuracy: 0.001) 31 | XCTAssertEqual(traits.delay, timing.delay, accuracy: 0.001) 32 | XCTAssertTrue(traits.timingCurve is CAMediaTimingFunction) 33 | if let timingCurve = traits.timingCurve as? CAMediaTimingFunction { 34 | XCTAssertEqual(timingCurve.mdm_point1.x, timing.curve.data.0, accuracy: 0.001) 35 | XCTAssertEqual(timingCurve.mdm_point1.y, timing.curve.data.1, accuracy: 0.001) 36 | XCTAssertEqual(timingCurve.mdm_point2.x, timing.curve.data.2, accuracy: 0.001) 37 | XCTAssertEqual(timingCurve.mdm_point2.y, timing.curve.data.3, accuracy: 0.001) 38 | } 39 | XCTAssertTrue(traits.repetition is MDMRepetitionOverTime) 40 | if let repetition = traits.repetition as? MDMRepetitionOverTime { 41 | XCTAssertEqual(repetition.duration, timing.repetition.amount, accuracy: 0.001) 42 | XCTAssertEqual(repetition.autoreverses, timing.repetition.autoreverses.boolValue) 43 | } 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /tests/unit/MDMModalMovementTimingTests.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | 19 | #import "MotionInterchange.h" 20 | 21 | @interface MDMAnimationTraitsSystemModalMovementTests : XCTestCase 22 | @property(nonatomic, strong) UIWindow *window; 23 | @end 24 | 25 | @interface ModalPresentationExtractionViewController : UIViewController 26 | @property(nonatomic, strong) CAAnimation *presentationPositionAnimation; 27 | @end 28 | 29 | @implementation ModalPresentationExtractionViewController 30 | 31 | - (void)viewDidLayoutSubviews { 32 | [super viewDidLayoutSubviews]; 33 | 34 | // We just want the first position key path animation that affects this view controller. 35 | if (!self.presentationPositionAnimation) { 36 | UIView *iterator = self.view; 37 | while (iterator != nil && self.presentationPositionAnimation == nil) { 38 | self.presentationPositionAnimation = [iterator.layer animationForKey:@"position"]; 39 | iterator = iterator.superview; 40 | } 41 | } 42 | } 43 | 44 | @end 45 | 46 | @implementation MDMAnimationTraitsSystemModalMovementTests 47 | 48 | - (void)setUp { 49 | [super setUp]; 50 | 51 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 52 | self.window.rootViewController = [[UIViewController alloc] initWithNibName:nil bundle:nil]; 53 | [self.window makeKeyAndVisible]; 54 | } 55 | 56 | - (void)tearDown { 57 | self.window = nil; 58 | 59 | [super tearDown]; 60 | } 61 | 62 | - (void)testSystemModalMovementTimingCurveMatchesModalMovementTiming { 63 | ModalPresentationExtractionViewController *presentedViewController = 64 | [[ModalPresentationExtractionViewController alloc] initWithNibName:nil bundle:nil]; 65 | XCTestExpectation *didComplete = [self expectationWithDescription:@"Animation completed"]; 66 | [self.window.rootViewController presentViewController:presentedViewController 67 | animated:YES 68 | completion:^{ 69 | [didComplete fulfill]; 70 | }]; 71 | 72 | [self waitForExpectationsWithTimeout:1 handler:nil]; 73 | 74 | XCTAssertTrue([presentedViewController.presentationPositionAnimation 75 | isKindOfClass:[CASpringAnimation class]]); 76 | CASpringAnimation *springAnimation = 77 | (CASpringAnimation *)presentedViewController.presentationPositionAnimation; 78 | 79 | MDMAnimationTraits *traits = [MDMAnimationTraits systemModalMovement]; 80 | XCTAssertTrue([traits.timingCurve isKindOfClass:[MDMSpringTimingCurve class]], 81 | @"Expected the system timing curve to be a %@ type, but it was '%@' instead.", 82 | NSStringFromClass([MDMSpringTimingCurve class]), 83 | NSStringFromClass([traits.timingCurve class])); 84 | if ([traits.timingCurve isKindOfClass:[MDMSpringTimingCurve class]]) { 85 | MDMSpringTimingCurve *spring = (MDMSpringTimingCurve *)traits.timingCurve; 86 | 87 | XCTAssertEqualWithAccuracy(spring.mass, springAnimation.mass, 0.001); 88 | XCTAssertEqualWithAccuracy(spring.tension, springAnimation.stiffness, 0.001); 89 | XCTAssertEqualWithAccuracy(spring.friction, springAnimation.damping, 0.001); 90 | if ([springAnimation respondsToSelector:@selector(initialVelocity)]) { 91 | XCTAssertEqualWithAccuracy(spring.initialVelocity, springAnimation.initialVelocity, 0.001); 92 | } 93 | } 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /tests/unit/MDMMotionCurveTests.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | #import 18 | 19 | #import "MotionInterchange.h" 20 | 21 | @interface MDMMotionCurveTests : XCTestCase 22 | @end 23 | 24 | @implementation MDMMotionCurveTests 25 | 26 | - (void)testLinearCurveConstantMatchesSystemLinearCurve { 27 | MDMMotionCurve curve = MDMLinearMotionCurve; 28 | CAMediaTimingFunction *linearTimingFunction = 29 | [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 30 | MDMMotionCurve systemLinearCurve = MDMMotionCurveFromTimingFunction(linearTimingFunction); 31 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP1X], 32 | systemLinearCurve.data[MDMBezierMotionCurveDataIndexP1X], 33 | 0.001); 34 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP1Y], 35 | systemLinearCurve.data[MDMBezierMotionCurveDataIndexP1Y], 36 | 0.001); 37 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP2X], 38 | systemLinearCurve.data[MDMBezierMotionCurveDataIndexP2X], 39 | 0.001); 40 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP2Y], 41 | systemLinearCurve.data[MDMBezierMotionCurveDataIndexP2Y], 42 | 0.001); 43 | } 44 | 45 | - (void)testBezierCurveData { 46 | MDMMotionCurve curve = MDMMotionCurveMakeBezier(0.1f, 0.2f, 0.3f, 0.4f); 47 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP1X], 0.1, 0.001); 48 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP1Y], 0.2, 0.001); 49 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP2X], 0.3, 0.001); 50 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP2Y], 0.4, 0.001); 51 | } 52 | 53 | - (void)testSpringCurveData { 54 | MDMMotionCurve curve = MDMMotionCurveMakeSpring(0.1f, 0.2f, 0.3f); 55 | XCTAssertEqualWithAccuracy(curve.data[MDMSpringMotionCurveDataIndexMass], 0.1, 0.001); 56 | XCTAssertEqualWithAccuracy(curve.data[MDMSpringMotionCurveDataIndexTension], 0.2, 0.001); 57 | XCTAssertEqualWithAccuracy(curve.data[MDMSpringMotionCurveDataIndexFriction], 0.3, 0.001); 58 | } 59 | 60 | - (void)testBezierCurveDataWithMacro { 61 | MDMMotionCurve curve = _MDMBezier(0.1, 0.2, 0.3, 0.4); 62 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP1X], 0.1, 0.001); 63 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP1Y], 0.2, 0.001); 64 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP2X], 0.3, 0.001); 65 | XCTAssertEqualWithAccuracy(curve.data[MDMBezierMotionCurveDataIndexP2Y], 0.4, 0.001); 66 | } 67 | 68 | - (void)testSpringCurveDataWithMacro { 69 | MDMMotionCurve curve = _MDMSpring(0.1, 0.2, 0.3); 70 | XCTAssertEqualWithAccuracy(curve.data[MDMSpringMotionCurveDataIndexMass], 0.1, 0.001); 71 | XCTAssertEqualWithAccuracy(curve.data[MDMSpringMotionCurveDataIndexTension], 0.2, 0.001); 72 | XCTAssertEqualWithAccuracy(curve.data[MDMSpringMotionCurveDataIndexFriction], 0.3, 0.001); 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /tests/unit/MDMMotionCurveTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import XCTest 18 | import MotionInterchange 19 | 20 | class MDMMotionCurveTests: XCTestCase { 21 | 22 | func testBezierCurveData() { 23 | let curve = MotionCurveMakeBezier(p1x: 0.1, p1y: 0.2, p2x: 0.3, p2y: 0.4) 24 | XCTAssertEqual(curve.data.0, 0.1, accuracy: 0.001) 25 | XCTAssertEqual(curve.data.1, 0.2, accuracy: 0.001) 26 | XCTAssertEqual(curve.data.2, 0.3, accuracy: 0.001) 27 | XCTAssertEqual(curve.data.3, 0.4, accuracy: 0.001) 28 | } 29 | 30 | func testBezierCurveFromTimingFunction() { 31 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.1, 0.2, 0.3, 0.4) 32 | let curve = MotionCurve(fromTimingFunction: timingFunction) 33 | XCTAssertEqual(curve.data.0, 0.1, accuracy: 0.001) 34 | XCTAssertEqual(curve.data.1, 0.2, accuracy: 0.001) 35 | XCTAssertEqual(curve.data.2, 0.3, accuracy: 0.001) 36 | XCTAssertEqual(curve.data.3, 0.4, accuracy: 0.001) 37 | } 38 | 39 | func testSpringCurveData() { 40 | let curve = MotionCurveMakeSpring(mass: 0.1, tension: 0.2, friction: 0.3) 41 | XCTAssertEqual(curve.data.0, 0.1, accuracy: 0.001) // mass 42 | XCTAssertEqual(curve.data.1, 0.2, accuracy: 0.001) // tension 43 | XCTAssertEqual(curve.data.2, 0.3, accuracy: 0.001) // friction 44 | XCTAssertEqual(curve.data.3, 0.0, accuracy: 0.001) 45 | } 46 | 47 | func testReversedBezierCurve() { 48 | let curve = MotionCurveMakeBezier(p1x: 0.1, p1y: 0.2, p2x: 0.3, p2y: 0.4) 49 | let reversed = MotionCurveReversedBezier(fromMotionCurve: curve) 50 | XCTAssertEqual(curve.data.0, 1 - reversed.data.2, accuracy: 0.001) 51 | XCTAssertEqual(curve.data.1, 1 - reversed.data.3, accuracy: 0.001) 52 | XCTAssertEqual(curve.data.2, 1 - reversed.data.0, accuracy: 0.001) 53 | XCTAssertEqual(curve.data.3, 1 - reversed.data.1, accuracy: 0.001) 54 | } 55 | 56 | func testReversingBezierCurveTwiceGivesSameResult() { 57 | let curve = MotionCurveMakeBezier(p1x: 0.1, p1y: 0.2, p2x: 0.3, p2y: 0.4) 58 | let reversed = MotionCurveReversedBezier(fromMotionCurve: curve) 59 | let reversedAgain = MotionCurveReversedBezier(fromMotionCurve: reversed) 60 | XCTAssertEqual(curve.data.0, reversedAgain.data.0, accuracy: 0.001) 61 | XCTAssertEqual(curve.data.1, reversedAgain.data.1, accuracy: 0.001) 62 | XCTAssertEqual(curve.data.2, reversedAgain.data.2, accuracy: 0.001) 63 | XCTAssertEqual(curve.data.3, reversedAgain.data.3, accuracy: 0.001) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/unit/MDMRepetitionOverTimeTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import XCTest 18 | import MotionInterchange 19 | 20 | class MDMRepetitionOverTimeTests: XCTestCase { 21 | 22 | func testInitializationWithDuration() { 23 | let repetition = MDMRepetitionOverTime(duration: 5.5) 24 | XCTAssertEqual(repetition.duration, 5.5, accuracy: 0.001) 25 | XCTAssertFalse(repetition.autoreverses) 26 | } 27 | 28 | func testInitializationWithDurationAndAutoreversed() { 29 | let repetition = MDMRepetitionOverTime(duration: 5.5, autoreverses: true) 30 | XCTAssertEqual(repetition.duration, 5.5, accuracy: 0.001) 31 | XCTAssertTrue(repetition.autoreverses) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/unit/MDMRepetitionTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import XCTest 18 | import MotionInterchange 19 | 20 | class MDMRepetitionTests: XCTestCase { 21 | 22 | func testInitializationWithNumberOfRepetitions() { 23 | let repetition = MDMRepetition(numberOfRepetitions: 5.5) 24 | XCTAssertEqual(repetition.numberOfRepetitions, 5.5, accuracy: 0.001) 25 | XCTAssertFalse(repetition.autoreverses) 26 | } 27 | 28 | func testInitializationWithNumberOfRepetitionsAndAutoreversed() { 29 | let repetition = MDMRepetition(numberOfRepetitions: 5.5, autoreverses: true) 30 | XCTAssertEqual(repetition.numberOfRepetitions, 5.5, accuracy: 0.001) 31 | XCTAssertTrue(repetition.autoreverses) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/unit/MDMSpringTimingCurve.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017-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 | import XCTest 18 | import MotionInterchange 19 | 20 | class MDMTimingCurveTests: XCTestCase { 21 | 22 | func testInitializerValuesWithNoInitialVelocity() { 23 | let curve = MDMSpringTimingCurve(mass: 0.1, tension: 0.2, friction: 0.3) 24 | XCTAssertEqual(curve.mass, 0.1, accuracy: 0.001) 25 | XCTAssertEqual(curve.tension, 0.2, accuracy: 0.001) 26 | XCTAssertEqual(curve.friction, 0.3, accuracy: 0.001) 27 | XCTAssertEqual(curve.initialVelocity, 0.0, accuracy: 0.001) 28 | } 29 | 30 | func testInitializerValuesWithInitialVelocity() { 31 | let curve = MDMSpringTimingCurve(mass: 0.1, tension: 0.2, friction: 0.3, initialVelocity: 0.4) 32 | XCTAssertEqual(curve.mass, 0.1, accuracy: 0.001) 33 | XCTAssertEqual(curve.tension, 0.2, accuracy: 0.001) 34 | XCTAssertEqual(curve.friction, 0.3, accuracy: 0.001) 35 | XCTAssertEqual(curve.initialVelocity, 0.4, accuracy: 0.001) 36 | } 37 | 38 | @available(iOS 9.0, *) 39 | func testInitializerValuesWithDampingCoefficient() { 40 | for duration in stride(from: TimeInterval(0.1), to: TimeInterval(3), by: TimeInterval(0.5)) { 41 | for dampingRatio in stride(from: CGFloat(0.1), to: CGFloat(2), by: CGFloat(0.4)) { 42 | for initialVel in stride(from: CGFloat(-2), to: CGFloat(2), by: CGFloat(0.8)) { 43 | let generator = MDMSpringTimingCurveGenerator(duration: duration, 44 | dampingRatio: dampingRatio, 45 | initialVelocity: initialVel) 46 | let view = UIView() 47 | 48 | UIView.animate(withDuration: duration, 49 | delay: 0, 50 | usingSpringWithDamping: dampingRatio, 51 | initialSpringVelocity: initialVel, 52 | options: [], 53 | animations: { 54 | view.center = CGPoint(x: initialVel * 5, y: dampingRatio * 10) 55 | }, completion: nil) 56 | 57 | if let animationKey = view.layer.animationKeys()?.first, 58 | let animation = view.layer.animation(forKey: animationKey) as? CASpringAnimation { 59 | 60 | let curve = generator.springTimingCurve() 61 | XCTAssertEqual(curve.mass, animation.mass, accuracy: 0.001) 62 | XCTAssertEqual(curve.tension, animation.stiffness, accuracy: 0.001) 63 | XCTAssertEqual(curve.friction, animation.damping, accuracy: 0.001) 64 | if animation.responds(to: #selector(initialVelocity)) { 65 | XCTAssertEqual(curve.initialVelocity, animation.initialVelocity, accuracy: 0.001) 66 | } 67 | } 68 | } 69 | } 70 | } 71 | } 72 | 73 | // Dummy getter for #selector(initialVelocity) reference. 74 | func initialVelocity() { 75 | } 76 | } 77 | --------------------------------------------------------------------------------