Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
Material
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
Material
Commits
fc98f8b5
Unverified
Commit
fc98f8b5
authored
Jun 10, 2017
by
Daniel Dahan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
development: added Motion submodule
parent
0c31a0a6
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
105 additions
and
2040 deletions
+105
-2040
.gitmodules
+3
-0
Frameworks/External/Motion
+1
-0
Material.xcodeproj/project.pbxproj
+93
-26
Sources/iOS/Button.swift
+1
-0
Sources/iOS/Capture/Capture.swift
+1
-1
Sources/iOS/CollectionReusableView.swift
+1
-0
Sources/iOS/CollectionViewCell.swift
+1
-0
Sources/iOS/Material+Motion.swift
+0
-996
Sources/iOS/Material+MotionAnimation.swift
+0
-852
Sources/iOS/Material+MotionDynamics.swift
+0
-165
Sources/iOS/PulseAnimation.swift
+1
-0
Sources/iOS/PulseView.swift
+1
-0
Sources/iOS/SnackbarController.swift
+1
-0
Sources/iOS/TableViewCell.swift
+1
-0
No files found.
.gitmodules
0 → 100644
View file @
fc98f8b5
[submodule "Frameworks/External/Motion"]
path = Frameworks/External/Motion
url = https://github.com/CosmicMind/Motion.git
Motion
@
f371f1db
Subproject commit f371f1db0f6f0044d60e3c136eb7831190bb39d7
Material.xcodeproj/project.pbxproj
View file @
fc98f8b5
...
...
@@ -8,7 +8,6 @@
/* Begin PBXBuildFile section */
9606CFAC1E957AC3006B4E74
/* TabsController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9606CFAB1E957AC3006B4E74
/* TabsController.swift */
;
};
960E35061EB0FC5700EB124A
/* Material+MotionDynamics.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
960E35051EB0FC5700EB124A
/* Material+MotionDynamics.swift */
;
};
961409B01E43D15C00E7BA99
/* CollectionViewCard.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
961730591E145DE900A9A297
/* CollectionViewCard.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
961409B11E43D15C00E7BA99
/* FABMenu.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96A183621E0C6CE200083C30
/* FABMenu.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
961409B21E43D15C00E7BA99
/* FABMenuController.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96A183641E0C6DD400083C30
/* FABMenuController.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
...
...
@@ -44,7 +43,6 @@
9639526D1EC3882F004BA9DE
/* EventsController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9639526B1EC3882F004BA9DE
/* EventsController.swift */
;
};
964335B71EC9432400FA9954
/* Events.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9639526A1EC3882F004BA9DE
/* Events.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
964335B81EC9432400FA9954
/* EventsController.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9639526B1EC3882F004BA9DE
/* EventsController.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
964335B91EC9432400FA9954
/* Material+MotionDynamics.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
960E35051EB0FC5700EB124A
/* Material+MotionDynamics.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
964335BA1EC9432400FA9954
/* TabsController.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9606CFAB1E957AC3006B4E74
/* TabsController.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
965E80CC1DD4C50600D61E4B
/* Bar.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BCB7981CB40DC500C806FE
/* Bar.swift */
;
};
965E80CD1DD4C50600D61E4B
/* Button.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BCB7701CB40DC500C806FE
/* Button.swift */
;
};
...
...
@@ -176,10 +174,6 @@
96BCB8561CB4115200C806FE
/* Switch.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BCB7881CB40DC500C806FE
/* Switch.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96BCB8571CB4115200C806FE
/* View.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BCB78C1CB40DC500C806FE
/* View.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96BFC1541E5E486F0075DE1F
/* SpringAnimation.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
965532281E47E388005C2792
/* SpringAnimation.swift */
;
};
96BFC1681E61D9FD0075DE1F
/* Material+Motion.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BFC1671E61D9FD0075DE1F
/* Material+Motion.swift */
;
};
96BFC16A1E61DAA10075DE1F
/* Material+MotionAnimation.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BFC1691E61DAA10075DE1F
/* Material+MotionAnimation.swift */
;
};
96BFC16D1E63C10A0075DE1F
/* Material+Motion.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BFC1671E61D9FD0075DE1F
/* Material+Motion.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96BFC16E1E63C10A0075DE1F
/* Material+MotionAnimation.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BFC1691E61DAA10075DE1F
/* Material+MotionAnimation.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96BFC16F1E63C10A0075DE1F
/* SpringAnimation.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
965532281E47E388005C2792
/* SpringAnimation.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96D88C321C1328D800B91418
/* Material.h in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96D88C091C1328D800B91418
/* Material.h */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
96E3C3951D3A1CC20086A024
/* IconButton.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9658F2161CD6FA4700B902C1
/* IconButton.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
...
...
@@ -190,9 +184,25 @@
96E3C39C1D3A1CC20086A024
/* Offset.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
968C99461D377849000074FF
/* Offset.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
966A7F141EEC5B3500A2DAAC
/* PBXContainerItemProxy */
=
{
isa
=
PBXContainerItemProxy
;
containerPortal
=
966A7F101EEC5B3500A2DAAC
/* Motion.xcodeproj */
;
proxyType
=
2
;
remoteGlobalIDString
=
96C98DD11E424AB000B22906
;
remoteInfo
=
"Motion iOS"
;
};
966A7F161EEC5B6300A2DAAC
/* PBXContainerItemProxy */
=
{
isa
=
PBXContainerItemProxy
;
containerPortal
=
966A7F101EEC5B3500A2DAAC
/* Motion.xcodeproj */
;
proxyType
=
1
;
remoteGlobalIDString
=
96C98DD01E424AB000B22906
;
remoteInfo
=
"Motion iOS"
;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
9606CFAB1E957AC3006B4E74
/* TabsController.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
TabsController.swift
;
sourceTree
=
"<group>"
;
};
960E35051EB0FC5700EB124A
/* Material+MotionDynamics.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"Material+MotionDynamics.swift"
;
sourceTree
=
"<group>"
;
};
961276621DCD8B1800A7D920
/* CharacterAttribute.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CharacterAttribute.swift
;
sourceTree
=
"<group>"
;
};
961730591E145DE900A9A297
/* CollectionViewCard.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CollectionViewCard.swift
;
sourceTree
=
"<group>"
;
};
961E6BDE1DDA2A95004E6C93
/* Application.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Application.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -215,6 +225,7 @@
963FBEFC1D669510008F8512
/* Snackbar.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Snackbar.swift
;
sourceTree
=
"<group>"
;
};
965532281E47E388005C2792
/* SpringAnimation.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
SpringAnimation.swift
;
sourceTree
=
"<group>"
;
};
9658F2161CD6FA4700B902C1
/* IconButton.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
IconButton.swift
;
sourceTree
=
"<group>"
;
};
966A7F101EEC5B3500A2DAAC
/* Motion.xcodeproj */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
"wrapper.pb-project"
;
name
=
Motion.xcodeproj
;
path
=
Frameworks/External/Motion/Motion.xcodeproj
;
sourceTree
=
"<group>"
;
};
966ECF291CF4C20100BB0BDF
/* CollectionReusableView.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CollectionReusableView.swift
;
sourceTree
=
"<group>"
;
};
96717B0D1DBE6AF600DA84DB
/* Capture.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Capture.swift
;
sourceTree
=
"<group>"
;
};
96717B0E1DBE6AF600DA84DB
/* CaptureController.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CaptureController.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -280,8 +291,6 @@
96BCB7F01CB40DE900C806FE
/* Roboto-Medium.ttf */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
file
;
path
=
"Roboto-Medium.ttf"
;
sourceTree
=
"<group>"
;
};
96BCB7F11CB40DE900C806FE
/* Roboto-Regular.ttf */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
file
;
path
=
"Roboto-Regular.ttf"
;
sourceTree
=
"<group>"
;
};
96BCB7F21CB40DE900C806FE
/* Roboto-Thin.ttf */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
file
;
path
=
"Roboto-Thin.ttf"
;
sourceTree
=
"<group>"
;
};
96BFC1671E61D9FD0075DE1F
/* Material+Motion.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"Material+Motion.swift"
;
sourceTree
=
"<group>"
;
};
96BFC1691E61DAA10075DE1F
/* Material+MotionAnimation.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"Material+MotionAnimation.swift"
;
sourceTree
=
"<group>"
;
};
96C1C8801D42C62800E6608F
/* Material+Array.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"Material+Array.swift"
;
sourceTree
=
"<group>"
;
};
96D88BFC1C1328D800B91418
/* Info.plist */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text.plist.xml
;
path
=
Info.plist
;
sourceTree
=
"<group>"
;
};
96D88BFD1C1328D800B91418
/* LICENSE */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text
;
path
=
LICENSE
;
sourceTree
=
"<group>"
;
};
...
...
@@ -385,6 +394,7 @@
9638322C1B88DFD80015F710
=
{
isa
=
PBXGroup
;
children
=
(
966A7F0D1EEC5AF400A2DAAC
/* Frameworks */
,
96D88BF41C1328D800B91418
/* Sources */
,
963832371B88DFD80015F710
/* Products */
,
);
...
...
@@ -452,6 +462,38 @@
name
=
SearchBar
;
sourceTree
=
"<group>"
;
};
966A7F0D1EEC5AF400A2DAAC
/* Frameworks */
=
{
isa
=
PBXGroup
;
children
=
(
966A7F0E1EEC5AFD00A2DAAC
/* External */
,
);
name
=
Frameworks
;
sourceTree
=
"<group>"
;
};
966A7F0E1EEC5AFD00A2DAAC
/* External */
=
{
isa
=
PBXGroup
;
children
=
(
966A7F0F1EEC5B0F00A2DAAC
/* Motion */
,
);
name
=
External
;
sourceTree
=
"<group>"
;
};
966A7F0F1EEC5B0F00A2DAAC
/* Motion */
=
{
isa
=
PBXGroup
;
children
=
(
966A7F101EEC5B3500A2DAAC
/* Motion.xcodeproj */
,
);
name
=
Motion
;
sourceTree
=
"<group>"
;
};
966A7F111EEC5B3500A2DAAC
/* Products */
=
{
isa
=
PBXGroup
;
children
=
(
966A7F151EEC5B3500A2DAAC
/* Motion.framework */
,
);
name
=
Products
;
sourceTree
=
"<group>"
;
};
966ECF2B1CF4C21B00BB0BDF
/* Table */
=
{
isa
=
PBXGroup
;
children
=
(
...
...
@@ -521,7 +563,6 @@
96BCB8081CB4105E00C806FE
/* Icon */
,
96BCB80D1CB410FD00C806FE
/* Layer */
,
96BCB8041CB40F6C00C806FE
/* Layout */
,
96BCB8091CB4107700C806FE
/* Motion */
,
96BCB8011CB40F1700C806FE
/* Navigation */
,
961E6BEF1DDA4B04004E6C93
/* NavigationDrawer */
,
96717B151DBE6B1800DA84DB
/* Photos */
,
...
...
@@ -656,16 +697,6 @@
name
=
Icon
;
sourceTree
=
"<group>"
;
};
96BCB8091CB4107700C806FE
/* Motion */
=
{
isa
=
PBXGroup
;
children
=
(
96BFC1671E61D9FD0075DE1F
/* Material+Motion.swift */
,
96BFC1691E61DAA10075DE1F
/* Material+MotionAnimation.swift */
,
960E35051EB0FC5700EB124A
/* Material+MotionDynamics.swift */
,
);
name
=
Motion
;
sourceTree
=
"<group>"
;
};
96BCB80A1CB410A100C806FE
/* Extension */
=
{
isa
=
PBXGroup
;
children
=
(
...
...
@@ -826,12 +857,9 @@
961409B01E43D15C00E7BA99
/* CollectionViewCard.swift in Headers */
,
961409B11E43D15C00E7BA99
/* FABMenu.swift in Headers */
,
961409B21E43D15C00E7BA99
/* FABMenuController.swift in Headers */
,
96BFC16D1E63C10A0075DE1F
/* Material+Motion.swift in Headers */
,
96BFC16E1E63C10A0075DE1F
/* Material+MotionAnimation.swift in Headers */
,
96BFC16F1E63C10A0075DE1F
/* SpringAnimation.swift in Headers */
,
964335B71EC9432400FA9954
/* Events.swift in Headers */
,
964335B81EC9432400FA9954
/* EventsController.swift in Headers */
,
964335B91EC9432400FA9954
/* Material+MotionDynamics.swift in Headers */
,
964335BA1EC9432400FA9954
/* TabsController.swift in Headers */
,
);
runOnlyForDeploymentPostprocessing
=
0
;
...
...
@@ -846,10 +874,12 @@
963832311B88DFD80015F710
/* Sources */
,
963832331B88DFD80015F710
/* Headers */
,
963832341B88DFD80015F710
/* Resources */
,
966A7F0C1EEC582F00A2DAAC
/* ShellScript */
,
);
buildRules
=
(
);
dependencies
=
(
966A7F171EEC5B6300A2DAAC
/* PBXTargetDependency */
,
);
name
=
"Material iOS"
;
productName
=
FocusKit
;
...
...
@@ -886,6 +916,12 @@
mainGroup
=
9638322C1B88DFD80015F710
;
productRefGroup
=
963832371B88DFD80015F710
/* Products */
;
projectDirPath
=
""
;
projectReferences
=
(
{
ProductGroup
=
966A7F111EEC5B3500A2DAAC
/* Products */
;
ProjectRef
=
966A7F101EEC5B3500A2DAAC
/* Motion.xcodeproj */
;
},
);
projectRoot
=
""
;
targets
=
(
963832351B88DFD80015F710
/* Material iOS */
,
...
...
@@ -893,6 +929,16 @@
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
966A7F151EEC5B3500A2DAAC
/* Motion.framework */
=
{
isa
=
PBXReferenceProxy
;
fileType
=
wrapper.framework
;
path
=
Motion.framework
;
remoteRef
=
966A7F141EEC5B3500A2DAAC
/* PBXContainerItemProxy */
;
sourceTree
=
BUILT_PRODUCTS_DIR
;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
963832341B88DFD80015F710
/* Resources */
=
{
isa
=
PBXResourcesBuildPhase
;
...
...
@@ -909,6 +955,22 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
966A7F0C1EEC582F00A2DAAC
/* ShellScript */
=
{
isa
=
PBXShellScriptBuildPhase
;
buildActionMask
=
2147483647
;
files
=
(
);
inputPaths
=
(
);
outputPaths
=
(
);
runOnlyForDeploymentPostprocessing
=
0
;
shellPath
=
/bin/sh
;
shellScript
=
"git submodule update --init --recursive"
;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
963832311B88DFD80015F710
/* Sources */
=
{
isa
=
PBXSourcesBuildPhase
;
...
...
@@ -925,7 +987,6 @@
965E81041DD4D5C800D61E4B
/* CollectionViewCell.swift in Sources */
,
965E81071DD4D5C800D61E4B
/* CollectionViewLayout.swift in Sources */
,
965E81081DD4D5C800D61E4B
/* CollectionReusableView.swift in Sources */
,
96BFC1681E61D9FD0075DE1F
/* Material+Motion.swift in Sources */
,
965E81091DD4D5C800D61E4B
/* DataSourceItem.swift in Sources */
,
965E810A1DD4D5C800D61E4B
/* Font.swift in Sources */
,
965E810B1DD4D5C800D61E4B
/* RobotoFont.swift in Sources */
,
...
...
@@ -953,7 +1014,6 @@
965E81221DD4D5C800D61E4B
/* TextView.swift in Sources */
,
965E80E61DD4C55200D61E4B
/* Material+Obj-C.swift in Sources */
,
965E80E71DD4C55200D61E4B
/* Material+UIView.swift in Sources */
,
960E35061EB0FC5700EB124A
/* Material+MotionDynamics.swift in Sources */
,
965E80E81DD4C55200D61E4B
/* Material+CALayer.swift in Sources */
,
965E80E91DD4C55200D61E4B
/* Material+String.swift in Sources */
,
965E80F71DD4D59500D61E4B
/* Card.swift in Sources */
,
...
...
@@ -993,7 +1053,6 @@
965E80DB1DD4C50600D61E4B
/* InterimSpace.swift in Sources */
,
965E80DC1DD4C50600D61E4B
/* Depth.swift in Sources */
,
965E80DD1DD4C50600D61E4B
/* EdgeInsets.swift in Sources */
,
96BFC16A1E61DAA10075DE1F
/* Material+MotionAnimation.swift in Sources */
,
965E80DE1DD4C50600D61E4B
/* Gravity.swift in Sources */
,
965E80DF1DD4C50600D61E4B
/* CornerRadius.swift in Sources */
,
965E80FB1DD4D59500D61E4B
/* SearchBar.swift in Sources */
,
...
...
@@ -1006,6 +1065,14 @@
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
966A7F171EEC5B6300A2DAAC
/* PBXTargetDependency */
=
{
isa
=
PBXTargetDependency
;
name
=
"Motion iOS"
;
targetProxy
=
966A7F161EEC5B6300A2DAAC
/* PBXContainerItemProxy */
;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
9638324A1B88DFD80015F710
/* Debug */
=
{
isa
=
XCBuildConfiguration
;
...
...
Sources/iOS/Button.swift
View file @
fc98f8b5
...
...
@@ -29,6 +29,7 @@
*/
import
UIKit
import
Motion
open
class
Button
:
UIButton
,
Pulseable
,
PulseableLayer
{
/**
...
...
Sources/iOS/Capture/Capture.swift
View file @
fc98f8b5
...
...
@@ -474,7 +474,7 @@ open class Capture: View {
}
/// The session quality preset.
open
var
capturePreset
=
CapturePreset
.
preset
High
{
open
var
capturePreset
=
CapturePreset
.
preset
Photo
{
didSet
{
session
.
sessionPreset
=
CapturePresetToString
(
preset
:
capturePreset
)
}
...
...
Sources/iOS/CollectionReusableView.swift
View file @
fc98f8b5
...
...
@@ -29,6 +29,7 @@
*/
import
UIKit
import
Motion
@objc(CollectionReusableView)
open
class
CollectionReusableView
:
UICollectionReusableView
,
Pulseable
,
PulseableLayer
{
...
...
Sources/iOS/CollectionViewCell.swift
View file @
fc98f8b5
...
...
@@ -29,6 +29,7 @@
*/
import
UIKit
import
Motion
@objc(CollectionViewCell)
open
class
CollectionViewCell
:
UICollectionViewCell
,
Pulseable
,
PulseableLayer
{
...
...
Sources/iOS/Material+Motion.swift
deleted
100644 → 0
View file @
0c31a0a6
/*
* Copyright (C) 2015 - 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import
UIKit
@objc(MotionAnimationFillMode)
public
enum
MotionAnimationFillMode
:
Int
{
case
forwards
case
backwards
case
both
case
removed
}
/**
Converts the MotionAnimationFillMode enum value to a corresponding String.
- Parameter mode: An MotionAnimationFillMode enum value.
*/
public
func
MotionAnimationFillModeToValue
(
mode
:
MotionAnimationFillMode
)
->
String
{
switch
mode
{
case
.
forwards
:
return
kCAFillModeForwards
case
.
backwards
:
return
kCAFillModeBackwards
case
.
both
:
return
kCAFillModeBoth
case
.
removed
:
return
kCAFillModeRemoved
}
}
@objc(MotionAnimationTimingFunction)
public
enum
MotionAnimationTimingFunction
:
Int
{
case
`
default
`
case
linear
case
easeIn
case
easeOut
case
easeInEaseOut
}
/**
Converts the MotionAnimationTimingFunction enum value to a corresponding CAMediaTimingFunction.
- Parameter function: An MotionAnimationTimingFunction enum value.
- Returns: A CAMediaTimingFunction.
*/
public
func
MotionAnimationTimingFunctionToValue
(
timingFunction
:
MotionAnimationTimingFunction
)
->
CAMediaTimingFunction
{
switch
timingFunction
{
case
.
default
:
return
CAMediaTimingFunction
(
name
:
kCAMediaTimingFunctionDefault
)
case
.
linear
:
return
CAMediaTimingFunction
(
name
:
kCAMediaTimingFunctionLinear
)
case
.
easeIn
:
return
CAMediaTimingFunction
(
name
:
kCAMediaTimingFunctionEaseIn
)
case
.
easeOut
:
return
CAMediaTimingFunction
(
name
:
kCAMediaTimingFunctionEaseOut
)
case
.
easeInEaseOut
:
return
CAMediaTimingFunction
(
name
:
kCAMediaTimingFunctionEaseInEaseOut
)
}
}
public
typealias
MotionDelayCancelBlock
=
(
Bool
)
->
Void
fileprivate
var
MotionInstanceKey
:
UInt8
=
0
fileprivate
var
MotionInstanceControllerKey
:
UInt8
=
0
fileprivate
struct
MotionInstance
{
fileprivate
var
identifier
:
String
fileprivate
var
animations
:
[
MotionAnimation
]
/// A reference to the panGesture for interactive transitions.
fileprivate
var
panGesture
:
UIPanGestureRecognizer
?
}
fileprivate
struct
MotionInstanceController
{
fileprivate
var
isMotionEnabled
:
Bool
fileprivate
var
isInteractiveMotionEnabled
:
Bool
fileprivate
weak
var
delegate
:
MotionDelegate
?
}
extension
UIViewController
:
MotionDelegate
,
UIViewControllerTransitioningDelegate
,
UINavigationControllerDelegate
,
UITabBarControllerDelegate
{
/// MotionInstanceController reference.
fileprivate
var
motionInstanceController
:
MotionInstanceController
{
get
{
return
AssociatedObject
(
base
:
self
,
key
:
&
MotionInstanceControllerKey
)
{
return
MotionInstanceController
(
isMotionEnabled
:
false
,
isInteractiveMotionEnabled
:
false
,
delegate
:
nil
)
}
}
set
(
value
)
{
AssociateObject
(
base
:
self
,
key
:
&
MotionInstanceControllerKey
,
value
:
value
)
}
}
/// A boolean that indicates whether motion is enabled.
open
var
isMotionEnabled
:
Bool
{
get
{
return
motionInstanceController
.
isMotionEnabled
}
set
(
value
)
{
if
value
{
prepareMotionDelegation
()
}
motionInstanceController
.
isMotionEnabled
=
value
}
}
/// A boolean that indicates whether interactive motion is enabled.
open
var
isInteractiveMotionEnabled
:
Bool
{
get
{
return
motionInstanceController
.
isInteractiveMotionEnabled
}
set
(
value
)
{
if
value
{
prepareMotionDelegation
()
view
.
prepareInteractiveTransitionPanGesture
()
motionInstanceController
.
isMotionEnabled
=
true
}
motionInstanceController
.
isInteractiveMotionEnabled
=
value
}
}
/// A reference to the MotionDelegate.
open
weak
var
motionDelegate
:
MotionDelegate
?
{
get
{
return
motionInstanceController
.
delegate
}
set
(
value
)
{
motionInstanceController
.
delegate
=
value
}
}
}
extension
UIViewController
{
/// Prepares the motionDelegate.
fileprivate
func
prepareMotionDelegation
()
{
modalPresentationStyle
=
.
custom
transitioningDelegate
=
self
motionDelegate
=
self
(
self
as?
UINavigationController
)?
.
delegate
=
self
(
self
as?
UITabBarController
)?
.
delegate
=
self
}
}
extension
UIViewController
{
/**
Determines whether to use a Motion instance for transitions.
- Parameter forPresented presented: A UIViewController.
- Parameter presenting: A UIViewController.
- Parameter source: A UIViewController.
- Returns: An optional UIViewControllerAnimatedTransitioning.
*/
open
func
animationController
(
forPresented
presented
:
UIViewController
,
presenting
:
UIViewController
,
source
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
print
(
"animationController(forPresented"
)
return
isMotionEnabled
?
PresentingMotion
(
isPresenting
:
true
,
isInteractive
:
isInteractiveMotionEnabled
)
:
nil
}
/**
Determines whether to use a Motion instance for transitions.
- Parameter forDismissed dismissed: A UIViewController.
- Returns: An optional UIViewControllerAnimatedTransitioning.
*/
open
func
animationController
(
forDismissed
dismissed
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
print
(
"animationController(forDismissed"
)
return
isMotionEnabled
?
DismissingMotion
(
isPresenting
:
true
,
isInteractive
:
isInteractiveMotionEnabled
)
:
nil
}
/**
Determines whether to use a MotionPresentationController for transitions.
- Parameter forPresented presented: A UIViewController.
- Parameter presenting: A UIViewController.
- Parameter source: A UIViewController.
- Returns: An optional UIPresentationController.
*/
open
func
presentationController
(
forPresented
presented
:
UIViewController
,
presenting
:
UIViewController
?,
source
:
UIViewController
)
->
UIPresentationController
?
{
print
(
"presentationController:forPresented"
)
return
isMotionEnabled
?
MotionPresentationController
(
presentedViewController
:
presented
,
presenting
:
presenting
)
:
nil
}
open
func
interactionControllerForPresentation
(
using
animator
:
UIViewControllerAnimatedTransitioning
)
->
UIViewControllerInteractiveTransitioning
?
{
print
(
"interactionControllerForPresentation"
)
return
isInteractiveMotionEnabled
?
InteractivePresentingMotion
(
animator
:
animator
)
:
nil
}
open
func
interactionControllerForDismissal
(
using
animator
:
UIViewControllerAnimatedTransitioning
)
->
UIViewControllerInteractiveTransitioning
?
{
print
(
"interactionControllerForDismissal"
)
return
isInteractiveMotionEnabled
?
InteractiveDismissingMotion
(
animator
:
animator
)
:
nil
}
}
extension
UIViewController
{
/**
Determines whether to use a Motion instance for transitions.
- Parameter _ navigationController: A UINavigationController.
- Parameter animationControllerFor operation: A UINavigationControllerOperation.
- Parameter from fromVC: A UIViewController that is being transitioned from.
- Parameter to toVC: A UIViewController that is being transitioned to.
- Returns: An optional UIViewControllerAnimatedTransitioning.
*/
open
func
navigationController
(
_
navigationController
:
UINavigationController
,
animationControllerFor
operation
:
UINavigationControllerOperation
,
from
fromVC
:
UIViewController
,
to
toVC
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
print
(
"navigationController(_ navigationController"
)
return
fromVC
.
isMotionEnabled
?
Motion
(
isPresenting
:
operation
==
.
push
,
isInteractive
:
fromVC
.
isInteractiveMotionEnabled
)
:
nil
}
/**
Determines whether to use a Motion instance for transitions.
- Parameter _ tabBarController: A UITabBarController.
- Parameter animationControllerForTransitionFrom fromVC: A UIViewController that is being transitioned from.
- Parameter to toVC: A UIViewController that is being transitioned to.
- Returns: An optional UIViewControllerAnimatedTransitioning.
*/
open
func
tabBarController
(
_
tabBarController
:
UITabBarController
,
animationControllerForTransitionFrom
fromVC
:
UIViewController
,
to
toVC
:
UIViewController
)
->
UIViewControllerAnimatedTransitioning
?
{
print
(
"tabBarController(_ tabBarController"
)
return
fromVC
.
isMotionEnabled
?
Motion
(
isPresenting
:
true
,
isInteractive
:
fromVC
.
isInteractiveMotionEnabled
)
:
nil
}
}
extension
UIView
{
/// MotionInstance reference.
fileprivate
var
motionInstance
:
MotionInstance
{
get
{
return
AssociatedObject
(
base
:
self
,
key
:
&
MotionInstanceKey
)
{
return
MotionInstance
(
identifier
:
""
,
animations
:
[],
panGesture
:
nil
)
}
}
set
(
value
)
{
AssociateObject
(
base
:
self
,
key
:
&
MotionInstanceKey
,
value
:
value
)
}
}
/// An identifier value used to connect views across UIViewControllers.
open
var
motionIdentifier
:
String
{
get
{
return
motionInstance
.
identifier
}
set
(
value
)
{
motionInstance
.
identifier
=
value
}
}
/// The animations to run while in transition.
open
var
motionAnimations
:
[
MotionAnimation
]
{
get
{
return
motionInstance
.
animations
}
set
(
value
)
{
motionInstance
.
animations
=
value
}
}
}
extension
UIView
{
/// Prepares the interactive pan gesture.
fileprivate
func
prepareInteractiveTransitionPanGesture
()
{
motionInstance
.
panGesture
=
UIPanGestureRecognizer
()
motionInstance
.
panGesture
?
.
maximumNumberOfTouches
=
1
addGestureRecognizer
(
motionInstance
.
panGesture
!
)
}
}
extension
UIView
{
/**
Snapshots the view instance for animations during transitions.
- Parameter afterUpdates: A boolean indicating whether to snapshot the view
after a render update, or as is.
- Parameter shouldHide: A boolean indicating whether the view should be hidden
after the snapshot is taken.
- Returns: A UIView instance that is a snapshot of the given UIView.
*/
open
func
transitionSnapshot
(
afterUpdates
:
Bool
,
shouldHide
:
Bool
=
true
)
->
UIView
{
isHidden
=
false
// Material specific.
(
self
as?
PulseableLayer
)?
.
pulseLayer
?
.
isHidden
=
true
let
oldCornerRadius
=
layer
.
cornerRadius
layer
.
cornerRadius
=
0
var
oldBackgroundColor
:
UIColor
?
if
shouldHide
{
oldBackgroundColor
=
backgroundColor
backgroundColor
=
.
clear
}
let
oldTransform
=
motionTransform
motionTransform
=
CATransform3DIdentity
let
v
=
snapshotView
(
afterScreenUpdates
:
afterUpdates
)
!
layer
.
cornerRadius
=
oldCornerRadius
if
shouldHide
{
backgroundColor
=
oldBackgroundColor
}
motionTransform
=
oldTransform
let
contentView
=
v
.
subviews
.
first
!
contentView
.
layer
.
cornerRadius
=
layer
.
cornerRadius
contentView
.
layer
.
masksToBounds
=
true
v
.
motionIdentifier
=
motionIdentifier
v
.
layer
.
position
=
motionPosition
v
.
bounds
=
bounds
v
.
layer
.
cornerRadius
=
layer
.
cornerRadius
v
.
layer
.
zPosition
=
layer
.
zPosition
v
.
layer
.
opacity
=
layer
.
opacity
v
.
isOpaque
=
isOpaque
v
.
layer
.
anchorPoint
=
layer
.
anchorPoint
v
.
layer
.
masksToBounds
=
layer
.
masksToBounds
v
.
layer
.
borderColor
=
layer
.
borderColor
v
.
layer
.
borderWidth
=
layer
.
borderWidth
v
.
layer
.
shadowRadius
=
layer
.
shadowRadius
v
.
layer
.
shadowOpacity
=
layer
.
shadowOpacity
v
.
layer
.
shadowColor
=
layer
.
shadowColor
v
.
layer
.
shadowOffset
=
layer
.
shadowOffset
v
.
contentMode
=
contentMode
v
.
motionTransform
=
motionTransform
v
.
backgroundColor
=
backgroundColor
// Material specific.
(
self
as?
PulseableLayer
)?
.
pulseLayer
?
.
isHidden
=
false
isHidden
=
shouldHide
return
v
}
}
open
class
MotionPresentationController
:
UIPresentationController
{
open
override
func
presentationTransitionWillBegin
()
{
guard
nil
!=
containerView
else
{
return
}
presentedViewController
.
transitionCoordinator
?
.
animate
(
alongsideTransition
:
{
(
context
)
in
})
}
open
override
func
presentationTransitionDidEnd
(
_
completed
:
Bool
)
{}
open
override
func
dismissalTransitionWillBegin
()
{
guard
nil
!=
containerView
else
{
return
}
presentedViewController
.
transitionCoordinator
?
.
animate
(
alongsideTransition
:
{
(
context
)
in
})
}
open
override
func
dismissalTransitionDidEnd
(
_
completed
:
Bool
)
{}
open
override
var
frameOfPresentedViewInContainerView
:
CGRect
{
return
containerView
?
.
bounds
??
.
zero
}
}
@objc(MotionDelegate)
public
protocol
MotionDelegate
{
@objc
optional
func
motion
(
motion
:
Motion
,
willTransition
fromView
:
UIView
,
toView
:
UIView
)
@objc
optional
func
motion
(
motion
:
Motion
,
didTransition
fromView
:
UIView
,
toView
:
UIView
)
@objc
optional
func
motionDelayTransitionByTimeInterval
(
motion
:
Motion
)
->
TimeInterval
@objc
optional
func
motionWillBeginPresentation
(
presentationController
:
UIPresentationController
)
@objc
optional
func
motionAnimateAlongsideTransition
(
presentationController
:
UIPresentationController
)
}
open
class
MotionAnimator
:
NSObject
{
/// A boolean indicating whether Motion is presenting a view controller.
open
fileprivate
(
set
)
var
isPresenting
:
Bool
/// A boolean indicating whether Motion is interactive.
open
fileprivate
(
set
)
var
isInteractive
:
Bool
/**
An Array of UIView pairs with common motionIdentifiers in
the from and to view controllers.
*/
open
fileprivate
(
set
)
var
transitionPairs
=
[(
UIView
,
UIView
)]()
/// A reference to the transition snapshot.
open
var
transitionSnapshot
:
UIView
!
/// A reference to the transition background view.
open
let
transitionBackgroundView
=
UIView
()
/// The transition context for the current transition.
open
fileprivate
(
set
)
var
transitionContext
:
UIViewControllerContextTransitioning
!
/// The transition delay time.
open
fileprivate
(
set
)
var
delay
:
TimeInterval
=
0
/// The transition duration time.
open
fileprivate
(
set
)
var
duration
:
TimeInterval
=
0.35
/// The transition container view.
open
fileprivate
(
set
)
var
containerView
:
UIView
!
/// The view that is used to animate the transitions between view controllers.
open
fileprivate
(
set
)
var
transitionView
=
UIView
()
/// A reference to the view controller that is being transitioned to.
open
var
toViewController
:
UIViewController
{
return
transitionContext
.
viewController
(
forKey
:
.
to
)
!
}
/// A reference to the view controller that is being transitioned from.
open
var
fromViewController
:
UIViewController
{
return
transitionContext
.
viewController
(
forKey
:
.
from
)
!
}
/// The view that is being transitioned to.
open
var
toView
:
UIView
{
return
toViewController
.
view
}
/// The subviews of the view being transitioned to.
open
var
toSubviews
:
[
UIView
]
{
return
Motion
.
subviews
(
of
:
toView
)
}
/// The view that is being transitioned from.
open
var
fromView
:
UIView
{
return
fromViewController
.
view
}
/// The subviews of the view being transitioned from.
open
var
fromSubviews
:
[
UIView
]
{
return
Motion
.
subviews
(
of
:
fromView
)
}
/// The default initializer.
public
override
init
()
{
isPresenting
=
false
isInteractive
=
false
super
.
init
()
}
/**
An initializer to modify the presenting and container state.
- Parameter isPresenting: A boolean value indicating if the
Motion instance is presenting the view controller.
- Parameter isInteractive: A boolean value indicating if the
Motion instance is an interactive animation.
*/
public
init
(
isPresenting
:
Bool
,
isInteractive
:
Bool
)
{
self
.
isPresenting
=
isPresenting
self
.
isInteractive
=
isInteractive
super
.
init
()
}
/// Returns an Array of subviews for a given subview.
fileprivate
class
func
subviews
(
of
view
:
UIView
)
->
[
UIView
]
{
var
views
:
[
UIView
]
=
[]
Motion
.
subviews
(
of
:
view
,
views
:
&
views
)
return
views
}
/// Populates an Array of views that are subviews of a given view.
fileprivate
class
func
subviews
(
of
view
:
UIView
,
views
:
inout
[
UIView
])
{
for
v
in
view
.
subviews
{
if
0
<
v
.
motionIdentifier
.
utf16
.
count
{
views
.
append
(
v
)
}
subviews
(
of
:
v
,
views
:
&
views
)
}
}
/**
Executes a block of code after a time delay.
- Parameter duration: An animation duration time.
- Parameter animations: An animation block.
- Parameter execute block: A completion block that is executed once
the animations have completed.
*/
@discardableResult
open
class
func
delay
(
_
time
:
TimeInterval
,
execute
block
:
@escaping
()
->
Void
)
->
MotionDelayCancelBlock
?
{
func
asyncAfter
(
completion
:
@escaping
()
->
Void
)
{
DispatchQueue
.
main
.
asyncAfter
(
deadline
:
.
now
()
+
time
,
execute
:
completion
)
}
var
cancelable
:
MotionDelayCancelBlock
?
let
delayed
:
MotionDelayCancelBlock
=
{
if
!
$0
{
DispatchQueue
.
main
.
async
(
execute
:
block
)
}
cancelable
=
nil
}
cancelable
=
delayed
asyncAfter
{
cancelable
?(
false
)
}
return
cancelable
}
/**
Cancels the delayed MotionDelayCancelBlock.
- Parameter delayed completion: An MotionDelayCancelBlock.
*/
open
class
func
cancel
(
delayed
completion
:
MotionDelayCancelBlock
)
{
completion
(
true
)
}
/**
Disables the default animations set on CALayers.
- Parameter animations: A callback that wraps the animations to disable.
*/
open
class
func
disable
(
_
animations
:
(()
->
Void
))
{
animate
(
duration
:
0
,
animations
:
animations
)
}
/**
Runs an animation with a specified duration.
- Parameter duration: An animation duration time.
- Parameter animations: An animation block.
- Parameter timingFunction: An MotionAnimationTimingFunction value.
- Parameter completion: A completion block that is executed once
the animations have completed.
*/
open
class
func
animate
(
duration
:
CFTimeInterval
,
timingFunction
:
MotionAnimationTimingFunction
=
.
easeInEaseOut
,
animations
:
(()
->
Void
),
completion
:
(()
->
Void
)?
=
nil
)
{
CATransaction
.
begin
()
CATransaction
.
setAnimationDuration
(
duration
)
CATransaction
.
setCompletionBlock
(
completion
)
CATransaction
.
setAnimationTimingFunction
(
MotionAnimationTimingFunctionToValue
(
timingFunction
:
timingFunction
))
animations
()
CATransaction
.
commit
()
}
}
extension
MotionAnimator
:
UIViewControllerAnimatedTransitioning
{
/**
The animation method that is used to coordinate the transition.
- Parameter using transitionContext: A UIViewControllerContextTransitioning.
*/
@objc(animateTransition:)
open
func
animateTransition
(
using
transitionContext
:
UIViewControllerContextTransitioning
)
{
self
.
transitionContext
=
transitionContext
}
/**
Returns the transition duration time interval.
- Parameter using transitionContext: An optional UIViewControllerContextTransitioning.
- Returns: A TimeInterval that is the total animation time including delays.
*/
@objc(transitionDuration:)
open
func
transitionDuration
(
using
transitionContext
:
UIViewControllerContextTransitioning
?)
->
TimeInterval
{
return
delay
+
duration
}
}
extension
MotionAnimator
{
/// Adds the available transition animations.
fileprivate
func
addTransitionAnimations
()
{
for
(
from
,
to
)
in
transitionPairs
{
var
snapshotAnimations
=
[
CABasicAnimation
]()
var
snapshotChildAnimations
=
[
CABasicAnimation
]()
let
sizeAnimation
=
MotionBasicAnimation
.
size
(
to
.
bounds
.
size
)
let
cornerRadiusAnimation
=
MotionBasicAnimation
.
corner
(
radius
:
to
.
layer
.
cornerRadius
)
snapshotAnimations
.
append
(
sizeAnimation
)
snapshotAnimations
.
append
(
cornerRadiusAnimation
)
snapshotAnimations
.
append
(
MotionBasicAnimation
.
position
(
to
:
to
.
motionPosition
))
snapshotAnimations
.
append
(
MotionBasicAnimation
.
transform
(
transform
:
to
.
motionTransform
))
snapshotAnimations
.
append
(
MotionBasicAnimation
.
background
(
color
:
to
.
backgroundColor
??
.
clear
))
snapshotAnimations
.
append
(
MotionBasicAnimation
.
border
(
color
:
to
.
borderColor
??
.
clear
))
snapshotAnimations
.
append
(
MotionBasicAnimation
.
border
(
width
:
to
.
borderWidth
))
if
let
path
=
to
.
layer
.
shadowPath
{
let
shadowPath
=
MotionBasicAnimation
.
shadow
(
path
:
path
)
shadowPath
.
fromValue
=
fromView
.
layer
.
shadowPath
snapshotAnimations
.
append
(
shadowPath
)
}
let
shadowOffset
=
MotionBasicAnimation
.
shadow
(
offset
:
to
.
layer
.
shadowOffset
)
shadowOffset
.
fromValue
=
fromView
.
layer
.
shadowOffset
snapshotAnimations
.
append
(
shadowOffset
)
let
shadowOpacity
=
MotionBasicAnimation
.
shadow
(
opacity
:
to
.
layer
.
shadowOpacity
)
shadowOpacity
.
fromValue
=
fromView
.
layer
.
shadowOpacity
snapshotAnimations
.
append
(
shadowOpacity
)
let
shadowRadius
=
MotionBasicAnimation
.
shadow
(
radius
:
to
.
layer
.
shadowRadius
)
shadowRadius
.
fromValue
=
fromView
.
layer
.
shadowRadius
snapshotAnimations
.
append
(
shadowRadius
)
snapshotChildAnimations
.
append
(
cornerRadiusAnimation
)
snapshotChildAnimations
.
append
(
sizeAnimation
)
snapshotChildAnimations
.
append
(
MotionBasicAnimation
.
position
(
x
:
to
.
bounds
.
width
/
2
,
y
:
to
.
bounds
.
height
/
2
))
let
d
=
calculateAnimationTransitionDuration
(
animations
:
to
.
motionAnimations
)
let
snapshot
=
from
.
transitionSnapshot
(
afterUpdates
:
true
)
transitionView
.
addSubview
(
snapshot
)
Motion
.
delay
(
calculateAnimationDelayTimeInterval
(
animations
:
to
.
motionAnimations
))
{
[
weak
self
,
weak
to
]
in
guard
let
s
=
self
else
{
return
}
guard
let
v
=
to
else
{
return
}
let
tf
=
s
.
calculateAnimationTimingFunction
(
animations
:
v
.
motionAnimations
)
let
snapshotGroup
=
Motion
.
animate
(
group
:
snapshotAnimations
,
duration
:
d
)
snapshotGroup
.
fillMode
=
MotionAnimationFillModeToValue
(
mode
:
.
forwards
)
snapshotGroup
.
isRemovedOnCompletion
=
false
snapshotGroup
.
timingFunction
=
MotionAnimationTimingFunctionToValue
(
timingFunction
:
tf
)
if
s
.
isInteractive
{
snapshotGroup
.
speed
=
0
}
let
snapshotChildGroup
=
Motion
.
animate
(
group
:
snapshotChildAnimations
,
duration
:
d
)
snapshotChildGroup
.
fillMode
=
MotionAnimationFillModeToValue
(
mode
:
.
forwards
)
snapshotChildGroup
.
isRemovedOnCompletion
=
false
snapshotChildGroup
.
timingFunction
=
MotionAnimationTimingFunctionToValue
(
timingFunction
:
tf
)
if
s
.
isInteractive
{
snapshotChildGroup
.
speed
=
0
}
snapshot
.
animate
(
snapshotGroup
)
snapshot
.
subviews
.
first
?
.
animate
(
snapshotChildGroup
)
}
}
}
/// Adds the background animation.
fileprivate
func
addBackgroundAnimation
()
{
transitionBackgroundView
.
motion
(
.
backgroundColor
(
isPresenting
?
toView
.
backgroundColor
??
.
clear
:
.
clear
),
.
duration
(
transitionDuration
(
using
:
transitionContext
)))
}
}
extension
MotionAnimator
{
/**
Calculates the animation delay time based on the given Array of MotionAnimations.
- Parameter animations: An Array of MotionAnimations.
- Returns: A TimeInterval.
*/
fileprivate
func
calculateAnimationDelayTimeInterval
(
animations
:
[
MotionAnimation
])
->
TimeInterval
{
var
t
:
TimeInterval
=
0
for
a
in
animations
{
switch
a
{
case
let
.
delay
(
time
):
if
time
>
delay
{
delay
=
time
}
t
=
time
default
:
break
}
}
return
t
}
/**
Calculates the animation transition duration based on the given Array of MotionAnimations.
- Parameter animations: An Array of MotionAnimations.
- Returns: A TimeInterval.
*/
fileprivate
func
calculateAnimationTransitionDuration
(
animations
:
[
MotionAnimation
])
->
TimeInterval
{
var
t
:
TimeInterval
=
0.35
for
a
in
animations
{
switch
a
{
case
let
.
duration
(
time
):
if
time
>
duration
{
duration
=
time
}
t
=
time
default
:
break
}
}
return
t
}
/**
Calculates the animation timing function based on the given Array of MotionAnimations.
- Parameter animations: An Array of MotionAnimations.
- Returns: A MotionAnimationTimingFunction.
*/
fileprivate
func
calculateAnimationTimingFunction
(
animations
:
[
MotionAnimation
])
->
MotionAnimationTimingFunction
{
var
t
=
MotionAnimationTimingFunction
.
easeInEaseOut
for
a
in
animations
{
switch
a
{
case
let
.
timingFunction
(
timingFunction
):
t
=
timingFunction
default
:
break
}
}
return
t
}
}
open
class
Motion
:
MotionAnimator
{
/// A time value to delay the transition animation by.
fileprivate
var
delayTransitionByTimeInterval
:
TimeInterval
{
return
fromViewController
.
motionDelegate
?
.
motionDelayTransitionByTimeInterval
?(
motion
:
self
)
??
0
}
/**
The animation method that is used to coordinate the transition.
- Parameter using transitionContext: A UIViewControllerContextTransitioning.
*/
@objc(animateTransition:)
open
override
func
animateTransition
(
using
transitionContext
:
UIViewControllerContextTransitioning
)
{
super
.
animateTransition
(
using
:
transitionContext
)
fromViewController
.
motionDelegate
?
.
motion
?(
motion
:
self
,
willTransition
:
fromView
,
toView
:
toView
)
Motion
.
delay
(
delayTransitionByTimeInterval
)
{
[
weak
self
]
in
guard
let
s
=
self
else
{
return
}
s
.
prepareContainerView
()
s
.
prepareTransitionSnapshot
()
s
.
prepareTransitionPairs
()
s
.
prepareTransitionView
()
s
.
prepareTransitionBackgroundView
()
s
.
prepareToView
()
s
.
prepareTransitionAnimation
()
}
}
/// Prepares the toView.
fileprivate
func
prepareToView
()
{
toView
.
isHidden
=
isPresenting
containerView
.
insertSubview
(
toView
,
belowSubview
:
transitionView
)
toView
.
frame
=
fromView
.
frame
toView
.
updateConstraints
()
toView
.
setNeedsLayout
()
toView
.
layoutIfNeeded
()
}
}
extension
Motion
{
/// Prepares the containerView.
fileprivate
func
prepareContainerView
()
{
containerView
=
transitionContext
.
containerView
}
/// Prepares the transitionSnapshot.
fileprivate
func
prepareTransitionSnapshot
()
{
transitionSnapshot
=
fromView
.
transitionSnapshot
(
afterUpdates
:
true
,
shouldHide
:
false
)
transitionSnapshot
.
frame
=
fromView
.
frame
containerView
.
addSubview
(
transitionSnapshot
)
}
/// Prepares the transitionPairs.
fileprivate
func
prepareTransitionPairs
()
{
for
from
in
fromSubviews
{
for
to
in
toSubviews
{
guard
to
.
motionIdentifier
==
from
.
motionIdentifier
else
{
continue
}
transitionPairs
.
append
((
from
,
to
))
}
}
}
/// Prepares the transitionView.
fileprivate
func
prepareTransitionView
()
{
transitionView
.
frame
=
toView
.
bounds
transitionView
.
isUserInteractionEnabled
=
false
containerView
.
insertSubview
(
transitionView
,
belowSubview
:
transitionSnapshot
)
}
/// Prepares the transitionBackgroundView.
fileprivate
func
prepareTransitionBackgroundView
()
{
transitionBackgroundView
.
backgroundColor
=
isPresenting
?
.
clear
:
fromView
.
backgroundColor
??
.
clear
transitionBackgroundView
.
frame
=
transitionView
.
bounds
transitionView
.
addSubview
(
transitionBackgroundView
)
}
/// Prepares the transition animation.
fileprivate
func
prepareTransitionAnimation
()
{
addTransitionAnimations
()
addBackgroundAnimation
()
cleanUpAnimation
()
removeTransitionSnapshot
()
}
}
extension
Motion
{
/**
Creates a CAAnimationGroup.
- Parameter animations: An Array of CAAnimation objects.
- Parameter timingFunction: An MotionAnimationTimingFunction value.
- Parameter duration: An animation duration time for the group.
- Returns: A CAAnimationGroup.
*/
open
class
func
animate
(
group
animations
:
[
CAAnimation
],
timingFunction
:
MotionAnimationTimingFunction
=
.
easeInEaseOut
,
duration
:
CFTimeInterval
=
0.5
)
->
CAAnimationGroup
{
let
group
=
CAAnimationGroup
()
group
.
fillMode
=
MotionAnimationFillModeToValue
(
mode
:
.
forwards
)
group
.
isRemovedOnCompletion
=
false
group
.
animations
=
animations
group
.
duration
=
duration
group
.
timingFunction
=
MotionAnimationTimingFunctionToValue
(
timingFunction
:
timingFunction
)
return
group
}
}
extension
Motion
{
/// Cleans up the animation transition.
fileprivate
func
cleanUpAnimation
()
{
guard
!
isInteractive
else
{
return
}
Motion
.
delay
(
transitionDuration
(
using
:
transitionContext
)
+
delayTransitionByTimeInterval
)
{
[
weak
self
]
in
guard
let
s
=
self
else
{
return
}
s
.
showToSubviews
()
s
.
removeTransitionView
()
s
.
clearTransitionPairs
()
s
.
completeTransition
()
}
}
/// Removes the transitionSnapshot from its superview.
fileprivate
func
removeTransitionSnapshot
()
{
guard
!
isInteractive
else
{
return
}
Motion
.
delay
(
delay
)
{
[
weak
self
]
in
self
?
.
transitionSnapshot
.
removeFromSuperview
()
}
}
/// Shows the toView and its subviews.
fileprivate
func
showToSubviews
()
{
toSubviews
.
forEach
{
$0
.
isHidden
=
false
}
toView
.
isHidden
=
false
}
/// Clears the transitionPairs Array.
fileprivate
func
clearTransitionPairs
()
{
transitionPairs
.
removeAll
()
}
/// Removes the transitionView.
fileprivate
func
removeTransitionView
()
{
transitionView
.
removeFromSuperview
()
}
/// Calls the completionTransition method.
fileprivate
func
completeTransition
()
{
toViewController
.
motionDelegate
?
.
motion
?(
motion
:
self
,
didTransition
:
fromView
,
toView
:
toView
)
transitionContext
.
completeTransition
(
!
transitionContext
.
transitionWasCancelled
)
}
}
open
class
PresentingMotion
:
Motion
{}
open
class
DismissingMotion
:
Motion
{
/// Prepares the toView.
fileprivate
override
func
prepareToView
()
{
toView
.
isHidden
=
true
toView
.
frame
=
fromView
.
frame
toView
.
updateConstraints
()
toView
.
setNeedsLayout
()
toView
.
layoutIfNeeded
()
}
}
open
class
InteractiveMotion
:
UIPercentDrivenInteractiveTransition
{
/// A reference to the view controller that is being transitioned to.
open
var
toViewController
:
UIViewController
{
return
transitionContext
.
viewController
(
forKey
:
.
to
)
!
}
/// A reference to the view controller that is being transitioned from.
open
var
fromViewController
:
UIViewController
{
return
transitionContext
.
viewController
(
forKey
:
.
from
)
!
}
/// The transition context for the current transition.
open
fileprivate
(
set
)
var
transitionContext
:
UIViewControllerContextTransitioning
!
/// A reference to the panGesture for transitions.
open
fileprivate
(
set
)
var
panGesture
:
UIPanGestureRecognizer
!
/// The transition container view.
open
fileprivate
(
set
)
var
containerView
:
UIView
!
open
fileprivate
(
set
)
var
animator
:
UIViewControllerAnimatedTransitioning
!
/**
An initializer that accepts an animator object.
- Parameter animator: UIViewControllerAnimatedTransitioning.
*/
public
init
(
animator
:
UIViewControllerAnimatedTransitioning
)
{
super
.
init
()
self
.
animator
=
animator
}
open
override
func
startInteractiveTransition
(
_
transitionContext
:
UIViewControllerContextTransitioning
)
{
super
.
startInteractiveTransition
(
transitionContext
)
self
.
transitionContext
=
transitionContext
preparePanGesture
()
}
//
//
// optional public var completionSpeed: CGFloat { get }
//
// optional public var completionCurve: UIViewAnimationCurve { get }
//
//
// /// In 10.0, if an object conforming to UIViewControllerAnimatedTransitioning is
// /// known to be interruptible, it is possible to start it as if it was not
// /// interactive and then interrupt the transition and interact with it. In this
// /// case, implement this method and return NO. If an interactor does not
// /// implement this method, YES is assumed.
// @available(iOS 10.0, *)
// optional public var wantsInteractiveStart: Bool { get }
}
extension
InteractiveMotion
{
fileprivate
func
preparePanGesture
()
{
(
animator
as?
PresentingMotion
)?
.
fromView
.
motionInstance
.
panGesture
?
.
addTarget
(
self
,
action
:
#selector(
handleInteractiveTransition(gestureRecognizer:)
)
)
}
}
extension
InteractiveMotion
{
@objc
fileprivate
func
handleInteractiveTransition
(
gestureRecognizer
:
UIGestureRecognizer
)
{
switch
gestureRecognizer
.
state
{
case
.
began
:
panGesture
.
setTranslation
(
.
zero
,
in
:
containerView
)
print
(
"began"
)
case
.
changed
:
let
translation
=
panGesture
.
translation
(
in
:
containerView
)
let
percentage
=
fabs
(
translation
.
y
/
containerView
.
bounds
.
height
)
update
(
percentage
)
print
(
"changed"
,
percentage
)
case
.
ended
:
finish
()
containerView
.
removeGestureRecognizer
(
panGesture
)
print
(
"ended"
)
default
:
break
}
}
}
open
class
InteractivePresentingMotion
:
InteractiveMotion
{
}
open
class
InteractiveDismissingMotion
:
InteractiveMotion
{
}
Sources/iOS/Material+MotionAnimation.swift
deleted
100644 → 0
View file @
0c31a0a6
/*
* Copyright (C) 2015 - 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import
UIKit
public
enum
MotionAnimationKeyPath
:
String
{
case
backgroundColor
case
barTintColor
case
borderColor
case
borderWidth
case
cornerRadius
case
transform
case
rotation
=
"transform.rotation"
case
rotationX
=
"transform.rotation.x"
case
rotationY
=
"transform.rotation.y"
case
rotationZ
=
"transform.rotation.z"
case
scale
=
"transform.scale"
case
scaleX
=
"transform.scale.x"
case
scaleY
=
"transform.scale.y"
case
scaleZ
=
"transform.scale.z"
case
translation
=
"transform.translation"
case
translationX
=
"transform.translation.x"
case
translationY
=
"transform.translation.y"
case
translationZ
=
"transform.translation.z"
case
position
case
opacity
case
zPosition
case
width
=
"bounds.size.width"
case
height
=
"bounds.size.height"
case
size
=
"bounds.size"
case
shadowPath
case
shadowOffset
case
shadowOpacity
case
shadowRadius
}
public
enum
MotionAnimation
{
case
delay
(
TimeInterval
)
case
timingFunction
(
MotionAnimationTimingFunction
)
case
duration
(
TimeInterval
)
case
custom
(
CABasicAnimation
)
case
backgroundColor
(
UIColor
)
case
barTintColor
(
UIColor
)
case
borderColor
(
UIColor
)
case
borderWidth
(
CGFloat
)
case
cornerRadius
(
CGFloat
)
case
transform
(
CATransform3D
)
case
rotationAngle
(
CGFloat
)
case
rotationAngleX
(
CGFloat
)
case
rotationAngleY
(
CGFloat
)
case
rotationAngleZ
(
CGFloat
)
case
spin
(
CGFloat
)
case
spinX
(
CGFloat
)
case
spinY
(
CGFloat
)
case
spinZ
(
CGFloat
)
case
scale
(
CGFloat
)
case
scaleX
(
CGFloat
)
case
scaleY
(
CGFloat
)
case
scaleZ
(
CGFloat
)
case
translate
(
x
:
CGFloat
,
y
:
CGFloat
)
case
translateX
(
CGFloat
)
case
translateY
(
CGFloat
)
case
translateZ
(
CGFloat
)
case
x
(
CGFloat
)
case
y
(
CGFloat
)
case
point
(
x
:
CGFloat
,
y
:
CGFloat
)
case
position
(
x
:
CGFloat
,
y
:
CGFloat
)
case
fade
(
Double
)
case
zPosition
(
Int
)
case
width
(
CGFloat
)
case
height
(
CGFloat
)
case
size
(
width
:
CGFloat
,
height
:
CGFloat
)
case
shadowPath
(
CGPath
)
case
shadowOffset
(
CGSize
)
case
shadowOpacity
(
Float
)
case
shadowRadius
(
CGFloat
)
case
depth
(
shadowOffset
:
CGSize
,
shadowOpacity
:
Float
,
shadowRadius
:
CGFloat
)
}
@available(iOS 10, *)
extension
CALayer
:
CAAnimationDelegate
{}
extension
CALayer
{
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
open
func
animate
(
_
animations
:
CAAnimation
...
)
{
animate
(
animations
)
}
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animation: A CAAnimation instance.
*/
open
func
animate
(
_
animations
:
[
CAAnimation
])
{
for
animation
in
animations
{
if
nil
==
animation
.
delegate
{
animation
.
delegate
=
self
}
if
let
a
=
animation
as?
CABasicAnimation
{
a
.
fromValue
=
(
presentation
()
??
self
)
.
value
(
forKeyPath
:
a
.
keyPath
!
)
}
if
let
a
=
animation
as?
CAPropertyAnimation
{
add
(
a
,
forKey
:
a
.
keyPath
!
)
}
else
if
let
a
=
animation
as?
CAAnimationGroup
{
add
(
a
,
forKey
:
nil
)
}
else
if
let
a
=
animation
as?
CATransition
{
add
(
a
,
forKey
:
kCATransition
)
}
}
}
open
func
animationDidStart
(
_
anim
:
CAAnimation
)
{}
/**
A delegation function that is executed when the backing layer stops
running an animation.
- Parameter animation: The CAAnimation instance that stopped running.
- Parameter flag: A boolean that indicates if the animation stopped
because it was completed or interrupted. True if completed, false
if interrupted.
*/
open
func
animationDidStop
(
_
anim
:
CAAnimation
,
finished
flag
:
Bool
)
{
guard
let
a
=
anim
as?
CAPropertyAnimation
else
{
if
let
a
=
(
anim
as?
CAAnimationGroup
)?
.
animations
{
for
x
in
a
{
animationDidStop
(
x
,
finished
:
true
)
}
}
return
}
guard
let
b
=
a
as?
CABasicAnimation
else
{
return
}
guard
let
v
=
b
.
toValue
else
{
return
}
guard
let
k
=
b
.
keyPath
else
{
return
}
setValue
(
v
,
forKeyPath
:
k
)
removeAnimation
(
forKey
:
k
)
}
/**
A function that accepts a list of MotionAnimation values and executes them.
- Parameter animations: A list of MotionAnimation values.
*/
open
func
motion
(
_
animations
:
MotionAnimation
...
)
{
motion
(
animations
)
}
/**
A function that accepts an Array of MotionAnimation values and executes them.
- Parameter animations: An Array of MotionAnimation values.
- Parameter completion: An optional completion block.
*/
open
func
motion
(
_
animations
:
[
MotionAnimation
],
completion
:
(()
->
Void
)?
=
nil
)
{
motion
(
delay
:
0
,
duration
:
0.35
,
timingFunction
:
.
easeInEaseOut
,
animations
:
animations
,
completion
:
completion
)
}
/**
A function that executes an Array of MotionAnimation values.
- Parameter delay: The animation delay TimeInterval.
- Parameter duration: The animation duration TimeInterval.
- Parameter timingFunction: The animation MotionAnimationTimingFunction.
- Parameter animations: An Array of MotionAnimations.
- Parameter completion: An optional completion block.
*/
fileprivate
func
motion
(
delay
:
TimeInterval
,
duration
:
TimeInterval
,
timingFunction
:
MotionAnimationTimingFunction
,
animations
:
[
MotionAnimation
],
completion
:
(()
->
Void
)?
=
nil
)
{
var
t
=
delay
for
v
in
animations
{
switch
v
{
case
let
.
delay
(
time
):
t
=
time
default
:
break
}
}
Motion
.
delay
(
t
)
{
[
weak
self
]
in
guard
let
s
=
self
else
{
return
}
var
a
=
[
CABasicAnimation
]()
var
tf
=
timingFunction
var
d
=
duration
var
w
:
CGFloat
=
s
.
bounds
.
width
var
h
:
CGFloat
=
s
.
bounds
.
height
for
v
in
animations
{
switch
v
{
case
let
.
width
(
width
):
w
=
width
case
let
.
height
(
height
):
h
=
height
case
let
.
size
(
width
,
height
):
w
=
width
h
=
height
default
:
break
}
}
var
px
:
CGFloat
=
s
.
position
.
x
var
py
:
CGFloat
=
s
.
position
.
y
for
v
in
animations
{
switch
v
{
case
let
.
x
(
x
):
px
=
x
+
w
/
2
case
let
.
y
(
y
):
py
=
y
+
h
/
2
case
let
.
point
(
x
,
y
):
px
=
x
+
w
/
2
py
=
y
+
h
/
2
default
:
break
}
}
for
v
in
animations
{
switch
v
{
case
let
.
timingFunction
(
timingFunction
):
tf
=
timingFunction
case
let
.
duration
(
duration
):
d
=
duration
case
let
.
custom
(
animation
):
a
.
append
(
animation
)
case
let
.
backgroundColor
(
color
):
a
.
append
(
MotionBasicAnimation
.
background
(
color
:
color
))
case
let
.
barTintColor
(
color
):
a
.
append
(
MotionBasicAnimation
.
barTint
(
color
:
color
))
case
let
.
borderColor
(
color
):
a
.
append
(
MotionBasicAnimation
.
border
(
color
:
color
))
case
let
.
borderWidth
(
width
):
a
.
append
(
MotionBasicAnimation
.
border
(
width
:
width
))
case
let
.
cornerRadius
(
radius
):
a
.
append
(
MotionBasicAnimation
.
corner
(
radius
:
radius
))
case
let
.
transform
(
transform
):
a
.
append
(
MotionBasicAnimation
.
transform
(
transform
:
transform
))
case
let
.
rotationAngle
(
angle
):
let
rotate
=
MotionBasicAnimation
.
rotation
(
angle
:
angle
)
a
.
append
(
rotate
)
case
let
.
rotationAngleX
(
angle
):
a
.
append
(
MotionBasicAnimation
.
rotationX
(
angle
:
angle
))
case
let
.
rotationAngleY
(
angle
):
a
.
append
(
MotionBasicAnimation
.
rotationY
(
angle
:
angle
))
case
let
.
rotationAngleZ
(
angle
):
a
.
append
(
MotionBasicAnimation
.
rotationZ
(
angle
:
angle
))
case
let
.
spin
(
rotations
):
a
.
append
(
MotionBasicAnimation
.
spin
(
rotations
:
rotations
))
case
let
.
spinX
(
rotations
):
a
.
append
(
MotionBasicAnimation
.
spinX
(
rotations
:
rotations
))
case
let
.
spinY
(
rotations
):
a
.
append
(
MotionBasicAnimation
.
spinY
(
rotations
:
rotations
))
case
let
.
spinZ
(
rotations
):
a
.
append
(
MotionBasicAnimation
.
spinZ
(
rotations
:
rotations
))
case
let
.
scale
(
to
):
a
.
append
(
MotionBasicAnimation
.
scale
(
to
:
to
))
case
let
.
scaleX
(
to
):
a
.
append
(
MotionBasicAnimation
.
scaleX
(
to
:
to
))
case
let
.
scaleY
(
to
):
a
.
append
(
MotionBasicAnimation
.
scaleY
(
to
:
to
))
case
let
.
scaleZ
(
to
):
a
.
append
(
MotionBasicAnimation
.
scaleZ
(
to
:
to
))
case
let
.
translate
(
x
,
y
):
a
.
append
(
MotionBasicAnimation
.
translate
(
to
:
CGPoint
(
x
:
x
,
y
:
y
)))
case
let
.
translateX
(
to
):
a
.
append
(
MotionBasicAnimation
.
translateX
(
to
:
to
))
case
let
.
translateY
(
to
):
a
.
append
(
MotionBasicAnimation
.
translateY
(
to
:
to
))
case
let
.
translateZ
(
to
):
a
.
append
(
MotionBasicAnimation
.
translateZ
(
to
:
to
))
case
.
x
(
_
),
.
y
(
_
),
.
point
(
_
,
_
):
let
position
=
MotionBasicAnimation
.
position
(
to
:
CGPoint
(
x
:
px
,
y
:
py
))
a
.
append
(
position
)
case
let
.
position
(
x
,
y
):
a
.
append
(
MotionBasicAnimation
.
position
(
to
:
CGPoint
(
x
:
x
,
y
:
y
)))
case
let
.
fade
(
opacity
):
let
fade
=
MotionBasicAnimation
.
fade
(
opacity
:
opacity
)
fade
.
fromValue
=
s
.
value
(
forKey
:
MotionAnimationKeyPath
.
opacity
.
rawValue
)
??
NSNumber
(
floatLiteral
:
1
)
a
.
append
(
fade
)
case
let
.
zPosition
(
index
):
let
zPosition
=
MotionBasicAnimation
.
zPosition
(
index
:
index
)
zPosition
.
fromValue
=
s
.
value
(
forKey
:
MotionAnimationKeyPath
.
zPosition
.
rawValue
)
??
NSNumber
(
integerLiteral
:
0
)
a
.
append
(
zPosition
)
case
.
width
(
_
),
.
height
(
_
),
.
size
(
_
,
_
):
a
.
append
(
MotionBasicAnimation
.
size
(
CGSize
(
width
:
w
,
height
:
h
)))
case
let
.
shadowPath
(
path
):
let
shadowPath
=
MotionBasicAnimation
.
shadow
(
path
:
path
)
shadowPath
.
fromValue
=
s
.
shadowPath
a
.
append
(
shadowPath
)
case
let
.
shadowOffset
(
offset
):
let
shadowOffset
=
MotionBasicAnimation
.
shadow
(
offset
:
offset
)
shadowOffset
.
fromValue
=
s
.
shadowOffset
a
.
append
(
shadowOffset
)
case
let
.
shadowOpacity
(
opacity
):
let
shadowOpacity
=
MotionBasicAnimation
.
shadow
(
opacity
:
opacity
)
shadowOpacity
.
fromValue
=
s
.
shadowOpacity
a
.
append
(
shadowOpacity
)
case
let
.
shadowRadius
(
radius
):
let
shadowRadius
=
MotionBasicAnimation
.
shadow
(
radius
:
radius
)
shadowRadius
.
fromValue
=
s
.
shadowRadius
a
.
append
(
shadowRadius
)
case
let
.
depth
(
offset
,
opacity
,
radius
):
if
let
path
=
s
.
shadowPath
{
let
shadowPath
=
MotionBasicAnimation
.
shadow
(
path
:
path
)
shadowPath
.
fromValue
=
s
.
shadowPath
a
.
append
(
shadowPath
)
}
let
shadowOffset
=
MotionBasicAnimation
.
shadow
(
offset
:
offset
)
shadowOffset
.
fromValue
=
s
.
shadowOffset
a
.
append
(
shadowOffset
)
let
shadowOpacity
=
MotionBasicAnimation
.
shadow
(
opacity
:
opacity
)
shadowOpacity
.
fromValue
=
s
.
shadowOpacity
a
.
append
(
shadowOpacity
)
let
shadowRadius
=
MotionBasicAnimation
.
shadow
(
radius
:
radius
)
shadowRadius
.
fromValue
=
s
.
shadowRadius
a
.
append
(
shadowRadius
)
default
:
break
}
}
let
g
=
Motion
.
animate
(
group
:
a
,
duration
:
d
)
g
.
fillMode
=
MotionAnimationFillModeToValue
(
mode
:
.
forwards
)
g
.
isRemovedOnCompletion
=
false
g
.
timingFunction
=
MotionAnimationTimingFunctionToValue
(
timingFunction
:
tf
)
s
.
animate
(
g
)
guard
let
execute
=
completion
else
{
return
}
Motion
.
delay
(
d
,
execute
:
execute
)
}
}
}
extension
UIView
{
/// Computes the rotation of the view.
open
var
motionRotationAngle
:
CGFloat
{
get
{
return
CGFloat
(
atan2f
(
Float
(
transform
.
b
),
Float
(
transform
.
a
)))
*
180
/
CGFloat
(
Double
.
pi
)
}
set
(
value
)
{
transform
=
CGAffineTransform
(
rotationAngle
:
CGFloat
(
Double
.
pi
)
*
value
/
180
)
}
}
/// The global position of a view.
open
var
motionPosition
:
CGPoint
{
return
superview
?
.
convert
(
layer
.
position
,
to
:
nil
)
??
layer
.
position
}
/// The layer.transform of a view.
open
var
motionTransform
:
CATransform3D
{
get
{
return
layer
.
transform
}
set
(
value
)
{
layer
.
transform
=
value
}
}
/// Computes the scale X axis value of the view.
open
var
motionScaleX
:
CGFloat
{
return
transform
.
a
}
/// Computes the scale Y axis value of the view.
open
var
motionScaleY
:
CGFloat
{
return
transform
.
b
}
/**
A function that accepts CAAnimation objects and executes them on the
view's backing layer.
- Parameter animations: A list of CAAnimations.
*/
open
func
animate
(
_
animations
:
CAAnimation
...
)
{
layer
.
animate
(
animations
)
}
/**
A function that accepts an Array of CAAnimation objects and executes
them on the view's backing layer.
- Parameter animations: An Array of CAAnimations.
*/
open
func
animate
(
_
animations
:
[
CAAnimation
])
{
layer
.
animate
(
animations
)
}
/**
A function that accepts a list of MotionAnimation values and executes
them on the view's backing layer.
- Parameter animations: A list of MotionAnimation values.
*/
open
func
motion
(
_
animations
:
MotionAnimation
...
)
{
layer
.
motion
(
animations
)
}
/**
A function that accepts an Array of MotionAnimation values and executes
them on the view's backing layer.
- Parameter animations: An Array of MotionAnimation values.
- Parameter completion: An optional completion block.
*/
open
func
motion
(
_
animations
:
[
MotionAnimation
],
completion
:
(()
->
Void
)?
=
nil
)
{
layer
.
motion
(
animations
,
completion
:
completion
)
}
}
extension
CABasicAnimation
{
/**
A convenience initializer that takes a given MotionAnimationKeyPath.
- Parameter keyPath: An MotionAnimationKeyPath.
*/
public
convenience
init
(
keyPath
:
MotionAnimationKeyPath
)
{
self
.
init
(
keyPath
:
keyPath
.
rawValue
)
}
}
extension
CAKeyframeAnimation
{
/**
A convenience initializer that takes a given MotionAnimationKeyPath.
- Parameter keyPath: An MotionAnimationKeyPath.
*/
public
convenience
init
(
keyPath
:
MotionAnimationKeyPath
)
{
self
.
init
(
keyPath
:
keyPath
.
rawValue
)
}
}
public
struct
MotionKeyframeAnimation
{
/**
Creates a CABasicAnimation for the backgroundColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public
static
func
background
(
color
:
UIColor
)
->
CAKeyframeAnimation
{
let
animation
=
CAKeyframeAnimation
(
keyPath
:
.
backgroundColor
)
animation
.
values
=
[
color
.
cgColor
]
return
animation
}
}
public
struct
MotionBasicAnimation
{
/**
Creates a CABasicAnimation for the backgroundColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public
static
func
background
(
color
:
UIColor
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
backgroundColor
)
animation
.
toValue
=
color
.
cgColor
return
animation
}
/**
Creates a CABasicAnimation for the barTintColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public
static
func
barTint
(
color
:
UIColor
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
barTintColor
)
animation
.
toValue
=
color
.
cgColor
return
animation
}
/**
Creates a CABasicAnimation for the borderColor key path.
- Parameter color: A UIColor.
- Returns: A CABasicAnimation.
*/
public
static
func
border
(
color
:
UIColor
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
borderColor
)
animation
.
toValue
=
color
.
cgColor
return
animation
}
/**
Creates a CABasicAnimation for the borderWidth key path.
- Parameter width: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
border
(
width
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
borderWidth
)
animation
.
toValue
=
width
return
animation
}
/**
Creates a CABasicAnimation for the cornerRadius key path.
- Parameter radius: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
corner
(
radius
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
cornerRadius
)
animation
.
toValue
=
radius
return
animation
}
/**
Creates a CABasicAnimation for the transform key path.
- Parameter transform: A CATransform3D object.
- Returns: A CABasicAnimation.
*/
public
static
func
transform
(
transform
:
CATransform3D
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
transform
)
animation
.
toValue
=
NSValue
(
caTransform3D
:
transform
)
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
rotation
(
angle
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotation
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
angle
/
180
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation.x key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
rotationX
(
angle
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotationX
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
angle
/
180
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation.y key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
rotationY
(
angle
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotationY
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
angle
/
180
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation.z key path.
- Parameter angle: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
rotationZ
(
angle
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotationZ
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
angle
/
180
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
spin
(
rotations
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotation
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
2
*
rotations
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation.x key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
spinX
(
rotations
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotationX
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
2
*
rotations
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation.y key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
spinY
(
rotations
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotationY
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
2
*
rotations
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.rotation.z key path.
- Parameter rotations: An optional CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
spinZ
(
rotations
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
rotationZ
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
CGFloat
(
Double
.
pi
)
*
2
*
rotations
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.scale key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
scale
(
to
scale
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
scale
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
scale
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.scale.x key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
scaleX
(
to
scale
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
scaleX
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
scale
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.scale.y key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
scaleY
(
to
scale
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
scaleY
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
scale
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.scale.z key path.
- Parameter to scale: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
scaleZ
(
to
scale
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
scaleZ
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
scale
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.translation key path.
- Parameter point: A CGPoint.
- Returns: A CABasicAnimation.
*/
public
static
func
translate
(
to
point
:
CGPoint
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
translation
)
animation
.
toValue
=
NSValue
(
cgPoint
:
point
)
return
animation
}
/**
Creates a CABasicAnimation for the transform.translation.x key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
translateX
(
to
translation
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
translationX
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
translation
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.translation.y key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
translateY
(
to
translation
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
translationY
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
translation
))
return
animation
}
/**
Creates a CABasicAnimation for the transform.translation.z key path.
- Parameter to translation: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
translateZ
(
to
translation
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
translationZ
)
animation
.
toValue
=
NSNumber
(
value
:
Double
(
translation
))
return
animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter x: A CGFloat.
- Parameter y: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
position
(
x
:
CGFloat
,
y
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
position
)
animation
.
toValue
=
NSValue
(
cgPoint
:
CGPoint
(
x
:
x
,
y
:
y
))
return
animation
}
/**
Creates a CABasicAnimation for the position key path.
- Parameter to point: A CGPoint.
- Returns: A CABasicAnimation.
*/
public
static
func
position
(
to
point
:
CGPoint
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
position
)
animation
.
toValue
=
NSValue
(
cgPoint
:
point
)
return
animation
}
/**
Creates a CABasicAnimation for the opacity key path.
- Parameter opacity: A Double.
- Returns: A CABasicAnimation.
*/
public
static
func
fade
(
opacity
:
Double
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
opacity
)
animation
.
toValue
=
NSNumber
(
floatLiteral
:
opacity
)
return
animation
}
/**
Creates a CABasicaAnimation for the zPosition key path.
- Parameter index: An Int.
- Returns: A CABasicAnimation.
*/
public
static
func
zPosition
(
index
:
Int
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
zPosition
)
animation
.
toValue
=
NSNumber
(
integerLiteral
:
index
)
return
animation
}
/**
Creates a CABasicaAnimation for the width key path.
- Parameter width: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
width
(
_
width
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
width
)
animation
.
toValue
=
NSNumber
(
floatLiteral
:
Double
(
width
))
return
animation
}
/**
Creates a CABasicaAnimation for the height key path.
- Parameter height: A CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
height
(
_
height
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
height
)
animation
.
toValue
=
NSNumber
(
floatLiteral
:
Double
(
height
))
return
animation
}
/**
Creates a CABasicaAnimation for the height key path.
- Parameter size: A CGSize.
- Returns: A CABasicAnimation.
*/
public
static
func
size
(
_
size
:
CGSize
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
size
)
animation
.
toValue
=
NSValue
(
cgSize
:
size
)
return
animation
}
/**
Creates a CABasicAnimation for the shadowPath key path.
- Parameter path: A CGPath.
- Returns: A CABasicAnimation.
*/
public
static
func
shadow
(
path
:
CGPath
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
shadowPath
)
animation
.
toValue
=
path
return
animation
}
/**
Creates a CABasicAnimation for the shadowOffset key path.
- Parameter offset: CGSize.
- Returns: A CABasicAnimation.
*/
public
static
func
shadow
(
offset
:
CGSize
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
shadowOffset
)
animation
.
toValue
=
NSValue
(
cgSize
:
offset
)
return
animation
}
/**
Creates a CABasicAnimation for the shadowOpacity key path.
- Parameter opacity: Float.
- Returns: A CABasicAnimation.
*/
public
static
func
shadow
(
opacity
:
Float
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
shadowOpacity
)
animation
.
toValue
=
NSNumber
(
floatLiteral
:
Double
(
opacity
))
return
animation
}
/**
Creates a CABasicAnimation for the shadowRadius key path.
- Parameter radius: CGFloat.
- Returns: A CABasicAnimation.
*/
public
static
func
shadow
(
radius
:
CGFloat
)
->
CABasicAnimation
{
let
animation
=
CABasicAnimation
(
keyPath
:
.
shadowRadius
)
animation
.
toValue
=
NSNumber
(
floatLiteral
:
Double
(
radius
))
return
animation
}
}
Sources/iOS/Material+MotionDynamics.swift
deleted
100644 → 0
View file @
0c31a0a6
/*
* Copyright (C) 2015 - 2017, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import
UIKit
open
class
MotionDynamics
:
UIDynamicBehavior
{
open
var
targetPoint
:
CGPoint
{
get
{
return
attachmentBehavior
.
anchorPoint
}
set
(
value
)
{
attachmentBehavior
.
anchorPoint
=
value
}
}
open
var
velocity
:
CGPoint
{
get
{
return
dynamicItemBehavior
.
linearVelocity
(
for
:
item
)
}
set
(
value
)
{
let
v
=
velocity
dynamicItemBehavior
.
addLinearVelocity
(
CGPoint
(
x
:
value
.
x
-
v
.
x
,
y
:
value
.
y
-
v
.
y
),
for
:
item
)
}
}
open
fileprivate
(
set
)
var
item
:
UIDynamicItem
open
fileprivate
(
set
)
var
attachmentBehavior
:
UIAttachmentBehavior
!
open
fileprivate
(
set
)
var
dynamicItemBehavior
:
UIDynamicItemBehavior
!
public
init
(
item
:
UIDynamicItem
)
{
self
.
item
=
item
}
open
func
prepare
()
{
prepareAttachmentBehavior
()
prepareDynamicItemBehavior
()
}
}
extension
MotionDynamics
{
fileprivate
func
prepareAttachmentBehavior
()
{
attachmentBehavior
=
UIAttachmentBehavior
(
item
:
item
,
attachedToAnchor
:
.
zero
)
attachmentBehavior
.
frequency
=
3.5
attachmentBehavior
.
damping
=
0.4
attachmentBehavior
.
length
=
0
addChildBehavior
(
attachmentBehavior
)
}
fileprivate
func
prepareDynamicItemBehavior
()
{
dynamicItemBehavior
=
UIDynamicItemBehavior
(
items
:
[
item
])
dynamicItemBehavior
.
density
=
100
dynamicItemBehavior
.
resistance
=
10
addChildBehavior
(
dynamicItemBehavior
)
}
}
public
enum
PaneState
:
Int
{
case
opened
case
closed
}
@objc(MotionDynamicsAnimatorDelegate)
public
protocol
MotionDynamicsAnimatorDelegate
{
// - (void)animationTick:(CFTimeInterval)dt finished:(BOOL *)finished;
}
open
class
PaneMotionDynamicsAnimator
:
MotionDynamicsAnimatorDelegate
{
// - (void)animationTick:(CFTimeInterval)dt finished:(BOOL *)finished;
}
open
class
PaneController
:
UIViewController
{
fileprivate
var
motionDynamics
:
MotionDynamics
?
fileprivate
var
pane
:
UIView
!
fileprivate
var
paneMotionDynamicsAnimator
:
PaneMotionDynamicsAnimator
!
fileprivate
var
animator
:
UIDynamicItemBehavior
!
open
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
prepare
()
}
open
func
prepare
()
{
prepareAnimator
()
preparePane
()
prepareMotionDynamics
()
preparePaneMotionDynamicsAnimator
()
}
}
extension
PaneController
{
fileprivate
func
prepareAnimator
()
{
animator
=
UIDynamicItemBehavior
()
}
fileprivate
func
preparePane
()
{
pane
=
UIView
()
}
fileprivate
func
prepareMotionDynamics
()
{
guard
nil
==
motionDynamics
else
{
return
}
motionDynamics
=
MotionDynamics
(
item
:
pane
)
}
fileprivate
func
preparePaneMotionDynamicsAnimator
()
{
paneMotionDynamicsAnimator
=
PaneMotionDynamicsAnimator
()
}
}
extension
PaneController
{
fileprivate
func
targetPointFor
(
state
:
PaneState
)
->
CGPoint
{
return
.
zero
}
}
extension
PaneController
{
fileprivate
func
draggable
(
view
:
UIView
,
draggingEndedWith
velocity
:
CGPoint
)
{
animatePaneTo
(
state
:
velocity
.
y
<
0
?
.
opened
:
.
closed
,
initialVelocity
:
velocity
)
}
fileprivate
func
animatePaneTo
(
state
:
PaneState
,
initialVelocity
:
CGPoint
)
{
prepareMotionDynamics
()
motionDynamics
?
.
targetPoint
=
targetPointFor
(
state
:
state
)
if
initialVelocity
.
equalTo
(
.
zero
)
{
motionDynamics
?
.
velocity
=
initialVelocity
}
// animator.addChildBehavior(motionDynamics)
}
}
Sources/iOS/PulseAnimation.swift
View file @
fc98f8b5
...
...
@@ -29,6 +29,7 @@
*/
import
UIKit
import
Motion
@objc(PulseAnimation)
public
enum
PulseAnimation
:
Int
{
...
...
Sources/iOS/PulseView.swift
View file @
fc98f8b5
...
...
@@ -29,6 +29,7 @@
*/
import
UIKit
import
Motion
open
class
PulseView
:
View
,
Pulseable
,
PulseableLayer
{
/// A Pulse reference.
...
...
Sources/iOS/SnackbarController.swift
View file @
fc98f8b5
...
...
@@ -29,6 +29,7 @@
*/
import
UIKit
import
Motion
@objc(SnackbarControllerDelegate)
public
protocol
SnackbarControllerDelegate
{
...
...
Sources/iOS/TableViewCell.swift
View file @
fc98f8b5
...
...
@@ -29,6 +29,7 @@
*/
import
UIKit
import
Motion
open
class
TableViewCell
:
UITableViewCell
,
Pulseable
,
PulseableLayer
{
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment