├── Package.swift ├── IBAnimatableApp ├── Assets.xcassets │ ├── Contents.json │ ├── icon │ │ ├── Contents.json │ │ ├── add.imageset │ │ │ ├── add.pdf │ │ │ └── Contents.json │ │ ├── back.imageset │ │ │ ├── back.pdf │ │ │ └── Contents.json │ │ ├── done.imageset │ │ │ ├── done.pdf │ │ │ └── Contents.json │ │ ├── email.imageset │ │ │ ├── email.pdf │ │ │ └── Contents.json │ │ ├── home.imageset │ │ │ ├── home.pdf │ │ │ └── Contents.json │ │ ├── left.imageset │ │ │ ├── left-1.pdf │ │ │ └── Contents.json │ │ ├── lists.imageset │ │ │ ├── lists.pdf │ │ │ └── Contents.json │ │ ├── menu.imageset │ │ │ ├── menu.pdf │ │ │ └── Contents.json │ │ ├── more.imageset │ │ │ ├── more.pdf │ │ │ └── Contents.json │ │ ├── right.imageset │ │ │ ├── right.pdf │ │ │ └── Contents.json │ │ ├── filter.imageset │ │ │ ├── filter.pdf │ │ │ └── Contents.json │ │ ├── gender.imageset │ │ │ ├── gender.pdf │ │ │ └── Contents.json │ │ ├── groups.imageset │ │ │ ├── groups.pdf │ │ │ └── Contents.json │ │ ├── logo.imageset │ │ │ ├── logo@2x.png │ │ │ ├── logo@3x.png │ │ │ └── Contents.json │ │ ├── logout.imageset │ │ │ ├── logout.pdf │ │ │ └── Contents.json │ │ ├── checked.imageset │ │ │ ├── checked.pdf │ │ │ └── Contents.json │ │ ├── profile.imageset │ │ │ ├── profile.pdf │ │ │ └── Contents.json │ │ ├── birthday.imageset │ │ │ ├── birthday.pdf │ │ │ └── Contents.json │ │ ├── calendar.imageset │ │ │ ├── calendar.pdf │ │ │ └── Contents.json │ │ ├── overview.imageset │ │ │ ├── overview.pdf │ │ │ └── Contents.json │ │ ├── password.imageset │ │ │ ├── password.pdf │ │ │ └── Contents.json │ │ ├── settings.imageset │ │ │ ├── settings.pdf │ │ │ └── Contents.json │ │ ├── timeline.imageset │ │ │ ├── timeline.pdf │ │ │ └── Contents.json │ │ ├── username.imageset │ │ │ ├── username.pdf │ │ │ └── Contents.json │ │ ├── add-photo.imageset │ │ │ ├── add-photo.pdf │ │ │ └── Contents.json │ │ ├── attention.imageset │ │ │ ├── attention.pdf │ │ │ └── Contents.json │ │ ├── playground.imageset │ │ │ ├── playground.pdf │ │ │ └── Contents.json │ │ └── unchecked.imageset │ │ │ ├── unchecked.pdf │ │ │ └── Contents.json │ ├── avatar │ │ ├── Contents.json │ │ ├── jakelin.imageset │ │ │ ├── jakelin.jpg │ │ │ └── Contents.json │ │ ├── avatar1.imageset │ │ │ ├── avatar1@2x.png │ │ │ ├── avatar1@3x.png │ │ │ └── Contents.json │ │ ├── avatar2.imageset │ │ │ ├── avatar2@2x.png │ │ │ ├── avatar2@3x.png │ │ │ └── Contents.json │ │ ├── avatar3.imageset │ │ │ ├── avatar3@2x.png │ │ │ ├── avatar3@3x.png │ │ │ └── Contents.json │ │ └── jakelin-small.imageset │ │ │ ├── jakelin-small@2x.png │ │ │ ├── jakelin-small@3x.png │ │ │ └── Contents.json │ ├── background │ │ ├── Contents.json │ │ ├── auto-bg.imageset │ │ │ ├── auto-bg.png │ │ │ └── Contents.json │ │ ├── food-bg.imageset │ │ │ ├── food-bg.png │ │ │ └── Contents.json │ │ ├── home-bg.imageset │ │ │ ├── home-bg.png │ │ │ └── Contents.json │ │ ├── work-bg.imageset │ │ │ ├── work-bg.png │ │ │ └── Contents.json │ │ ├── login-bg.imageset │ │ │ ├── login-bg@2x.png │ │ │ └── Contents.json │ │ ├── profile-bg.imageset │ │ │ ├── profile-bg.png │ │ │ └── Contents.json │ │ ├── calendar-bg.imageset │ │ │ ├── calendar-bg.png │ │ │ └── Contents.json │ │ ├── overview-bg.imageset │ │ │ ├── overview-bg.png │ │ │ └── Contents.json │ │ ├── timeline-bg.imageset │ │ │ ├── timeline-bg.png │ │ │ └── Contents.json │ │ └── walkthrough-bg.imageset │ │ │ ├── walkthrough-bg@2x.png │ │ │ └── Contents.json │ └── AppIcon.appiconset │ │ ├── Icon-76.png │ │ ├── Icon-29@2x.png │ │ ├── Icon-29@3x.png │ │ ├── Icon-40@2x.png │ │ ├── Icon-40@3x.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-83.5@2x.png │ │ └── Contents.json ├── Functions.swift ├── README.md ├── InteractionTableViewController.swift ├── TransitionViewController.swift ├── UIViewControllerExtension.swift ├── TransitionPushedViewController.swift ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── AppDelegate.swift ├── ContainerTransitionViewController.swift ├── Animations.storyboard └── UserInterface.storyboard ├── .swiftlint.yml ├── IBAnimatable.playground ├── Pages │ ├── Animation Properties.xcplaygroundpage │ │ ├── timeline.xctimeline │ │ └── Contents.swift │ ├── Chaining Animations.xcplaygroundpage │ │ ├── timeline.xctimeline │ │ └── Contents.swift │ └── Predefined Animations.xcplaygroundpage │ │ ├── timeline.xctimeline │ │ └── Contents.swift ├── playground.xcworkspace │ └── contents.xcworkspacedata └── contents.xcplayground ├── IBAnimatableApp.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── IBAnimatable.xcscheme ├── IBAnimatable ├── TransitionPageType.swift ├── StatusBarDesignable.swift ├── BlurEffectStyle.swift ├── BorderSide.swift ├── TransitionHollowState.swift ├── Typealias.swift ├── MaskType.swift ├── DismissSegue.swift ├── Constants.swift ├── GradientStartPoint.swift ├── GestureDirection.swift ├── CALayerExtension.swift ├── TransitionType.swift ├── PresentFadeSegue.swift ├── PresentExplodeSegue.swift ├── PresentFlipSegue.swift ├── PresentTurnSegue.swift ├── CornerDesignable.swift ├── PresentCardsSegue.swift ├── PresentNatGeoSegue.swift ├── PresentFoldSegue.swift ├── PresentSlideSegue.swift ├── PresentPortalSegue.swift ├── PresentFadeWithDismissInteractionSegue.swift ├── PresentFlipWithDismissInteractionSegue.swift ├── PresentTurnWithDismissInteractionSegue.swift ├── PresentNatGeoWithDismissInteractionSegue.swift ├── ViewControllerDesignable.swift ├── PresentFoldWithDismissInteractionSegue.swift ├── PresentSlideWithDismissInteractionSegue.swift ├── PresentPortalWithDismissInteractionSegue.swift ├── RotationDesignable.swift ├── BarButtonItemDesignable.swift ├── ColorType.swift ├── UIViewControllerExtension.swift ├── PlaceholderDesignable.swift ├── DesignableNavigationBar.swift ├── TransitionAnimatable.swift ├── RootWindowDesignable.swift ├── TableViewCellDesignable.swift ├── Info.plist ├── InteractiveAnimatorFactory.swift ├── SystemTransitionType.swift ├── UIColorExtension.swift ├── NavigationBarDesginable.swift ├── CheckBoxDesignable.swift ├── TransitionFromDirection.swift ├── SystemRotateAnimator.swift ├── SystemSuckEffectAnimator.swift ├── SystemRippleEffectAnimator.swift ├── AnimationType.swift ├── PaddingDesignable.swift ├── BlurDesignable.swift ├── AnimatableBarButtonItem.swift ├── PresenterManager.swift ├── SystemPageAnimator.swift ├── TintDesignable.swift ├── AnimatableNavigationController.swift ├── ShadowDesignable.swift ├── SystemRevealAnimator.swift ├── SystemMoveInAnimator.swift ├── SystemPushAnimator.swift ├── SystemCubeAnimator.swift ├── PanInteractiveAnimator.swift ├── PinchInteractiveAnimator.swift ├── SystemCameraIrisAnimator.swift ├── SystemFlipAnimator.swift ├── AnimatableViewController.swift ├── AnimatableTextView.swift ├── InteractiveGestureType.swift ├── AnimatableTableView.swift ├── FadeAnimator.swift ├── AnimatableLabel.swift ├── AnimatableTableViewCell.swift ├── AnimatedTransitioning.swift ├── ScreenEdgePanInteractiveAnimator.swift ├── Navigator.swift ├── AnimatableCollectionViewCell.swift ├── AnimatorFactory.swift ├── GradientType.swift ├── SideImageDesignable.swift ├── InteractiveAnimator.swift ├── AnimatableButton.swift ├── Presenter.swift ├── FillDesignable.swift └── SlideAnimator.swift ├── .travis.yml ├── IBAnimatable.podspec ├── LICENSE ├── Scripts ├── GradientsTypeScript.swift └── FlatColorsTypeScript.swift └── .gitignore /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package(name: "IBAnimatable") 4 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/add.imageset/add.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/add.imageset/add.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/back.imageset/back.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/back.imageset/back.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/done.imageset/done.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/done.imageset/done.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/email.imageset/email.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/email.imageset/email.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/home.imageset/home.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/home.imageset/home.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/left.imageset/left-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/left.imageset/left-1.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/lists.imageset/lists.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/lists.imageset/lists.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/menu.imageset/menu.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/menu.imageset/menu.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/more.imageset/more.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/more.imageset/more.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/right.imageset/right.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/right.imageset/right.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/filter.imageset/filter.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/filter.imageset/filter.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/gender.imageset/gender.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/gender.imageset/gender.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/groups.imageset/groups.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/groups.imageset/groups.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/logo.imageset/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/logo.imageset/logo@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/logo.imageset/logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/logo.imageset/logo@3x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/logout.imageset/logout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/logout.imageset/logout.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/checked.imageset/checked.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/checked.imageset/checked.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/profile.imageset/profile.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/profile.imageset/profile.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/jakelin.imageset/jakelin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/jakelin.imageset/jakelin.jpg -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/birthday.imageset/birthday.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/birthday.imageset/birthday.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/calendar.imageset/calendar.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/calendar.imageset/calendar.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/overview.imageset/overview.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/overview.imageset/overview.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/password.imageset/password.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/password.imageset/password.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/settings.imageset/settings.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/settings.imageset/settings.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/timeline.imageset/timeline.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/timeline.imageset/timeline.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/username.imageset/username.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/username.imageset/username.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar1.imageset/avatar1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/avatar1.imageset/avatar1@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar1.imageset/avatar1@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/avatar1.imageset/avatar1@3x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar2.imageset/avatar2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/avatar2.imageset/avatar2@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar2.imageset/avatar2@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/avatar2.imageset/avatar2@3x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar3.imageset/avatar3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/avatar3.imageset/avatar3@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar3.imageset/avatar3@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/avatar3.imageset/avatar3@3x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/auto-bg.imageset/auto-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/auto-bg.imageset/auto-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/food-bg.imageset/food-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/food-bg.imageset/food-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/home-bg.imageset/home-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/home-bg.imageset/home-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/work-bg.imageset/work-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/work-bg.imageset/work-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/add-photo.imageset/add-photo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/add-photo.imageset/add-photo.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/attention.imageset/attention.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/attention.imageset/attention.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/playground.imageset/playground.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/playground.imageset/playground.pdf -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/unchecked.imageset/unchecked.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/icon/unchecked.imageset/unchecked.pdf -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - trailing_whitespace 3 | - todo 4 | - variable_name 5 | - line_length 6 | - file_length 7 | - function_body_length 8 | - cyclomatic_complexity 9 | - type_name -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/login-bg.imageset/login-bg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/login-bg.imageset/login-bg@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/profile-bg.imageset/profile-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/profile-bg.imageset/profile-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/calendar-bg.imageset/calendar-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/calendar-bg.imageset/calendar-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/overview-bg.imageset/overview-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/overview-bg.imageset/overview-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/timeline-bg.imageset/timeline-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/timeline-bg.imageset/timeline-bg.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/jakelin-small.imageset/jakelin-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/jakelin-small.imageset/jakelin-small@2x.png -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/jakelin-small.imageset/jakelin-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/avatar/jakelin-small.imageset/jakelin-small@3x.png -------------------------------------------------------------------------------- /IBAnimatable.playground/Pages/Animation Properties.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /IBAnimatable.playground/Pages/Chaining Animations.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /IBAnimatable.playground/Pages/Predefined Animations.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /IBAnimatableApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IBAnimatable.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/walkthrough-bg.imageset/walkthrough-bg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielPeart/IBAnimatable/HEAD/IBAnimatableApp/Assets.xcassets/background/walkthrough-bg.imageset/walkthrough-bg@2x.png -------------------------------------------------------------------------------- /IBAnimatable/TransitionPageType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 31/03/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum TransitionPageType { 9 | case Curl 10 | case UnCurl 11 | } 12 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/add.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "add.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "back.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/done.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "done.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/home.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "home.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/menu.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "menu.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/more.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "more.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatable/StatusBarDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/15/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol StatusBarDesignable { 9 | var lightStatusBar: Bool { get set } 10 | } 11 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/email.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "email.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/filter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "filter.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/gender.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "gender.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/groups.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "groups.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/left.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "left-1.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/lists.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "lists.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/logout.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "logout.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/right.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "right.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/add-photo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "add-photo.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/attention.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "attention.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/birthday.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "birthday.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/calendar.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "calendar.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/checked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "checked.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/overview.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "overview.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/password.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "password.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/profile.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "profile.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/settings.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "settings.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/timeline.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "timeline.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/unchecked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "unchecked.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/username.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "username.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/playground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "playground.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /IBAnimatable/BlurEffectStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/5/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum BlurEffectStyle: String { 9 | case ExtraLight 10 | case Light 11 | case Dark 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode7.3 2 | language: objective-c 3 | script: 4 | - | 5 | xcodebuild build \ 6 | -project IBAnimatableApp.xcodeproj \ 7 | -scheme IBAnimatable \ 8 | -sdk iphonesimulator \ 9 | -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' 10 | -------------------------------------------------------------------------------- /IBAnimatable/BorderSide.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/9/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum BorderSide: String { 9 | case Top 10 | case Right 11 | case Bottom 12 | case Left 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/TransitionHollowState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 30/03/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum TransitionHollowState { 9 | case None 10 | case Open 11 | case Close 12 | } 13 | -------------------------------------------------------------------------------- /IBAnimatable/Typealias.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/23/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public typealias AnimatableCompletion = () -> Void 9 | public typealias AnimatableExecution = () -> Void 10 | public typealias Duration = NSTimeInterval 11 | -------------------------------------------------------------------------------- /IBAnimatable/MaskType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/13/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum MaskType: String { 9 | case Circle 10 | case Polygon 11 | case Star 12 | case Triangle 13 | case Wave 14 | case Parallelogram 15 | } 16 | -------------------------------------------------------------------------------- /IBAnimatable/DismissSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/14/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class DismissSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | sourceViewController.dismissViewControllerAnimated(true, completion: nil) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /IBAnimatable.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IBAnimatable/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/29/16. 3 | // Copyright (c) 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | // Default transition duration. 9 | // The default UIKit transtion animation duration is 0.35, but too fast for most of custom transition animations. 10 | let defaultTransitionDuration: Duration = 0.75 11 | -------------------------------------------------------------------------------- /IBAnimatable/GradientStartPoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/2/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum GradientStartPoint: String { 9 | case Top 10 | case TopRight 11 | case Right 12 | case BottomRight 13 | case Bottom 14 | case BottomLeft 15 | case Left 16 | case TopLeft 17 | } 18 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/jakelin.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "jakelin.jpg", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/auto-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "auto-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/food-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "food-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/home-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "home-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/work-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "work-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/login-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "login-bg@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatable/GestureDirection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 4/5/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | /** 9 | GestureDirection: Used to specify the direction in `InteractiveGestureType` 10 | */ 11 | public enum GestureDirection: String { 12 | case Horizontal 13 | case Vertical 14 | case Left 15 | case Right 16 | case Top 17 | case Bottom 18 | case Close 19 | case Open 20 | } 21 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/calendar-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "calendar-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/overview-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "overview-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/profile-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "profile-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/timeline-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "timeline-bg.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/background/walkthrough-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "walkthrough-bg@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/icon/logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "logo@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "logo@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "avatar1@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "avatar1@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "avatar2@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "avatar2@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/avatar3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "avatar3@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "avatar3@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /IBAnimatable/CALayerExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/23/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public extension CALayer { 9 | class func animate(animation: AnimatableExecution, completion: AnimatableCompletion? = nil) { 10 | CATransaction.begin() 11 | if let completion = completion { 12 | CATransaction.setCompletionBlock { completion() } 13 | } 14 | animation() 15 | CATransaction.commit() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /IBAnimatable/TransitionType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 3/16/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | enum TransitionType { 9 | case NavigationTransition(UINavigationControllerOperation) 10 | case PresentationTransition(PresentationOperation) 11 | case TabTransition(TabOperation) 12 | } 13 | 14 | enum PresentationOperation { 15 | case Presentation, Dismissal 16 | } 17 | 18 | enum TabOperation { 19 | case ToLeft, ToRight 20 | } 21 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/avatar/jakelin-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "jakelin-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "jakelin-small@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /IBAnimatable/PresentFadeSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/28/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentFadeSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Fade(direction: .Cross)) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentExplodeSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 03/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentExplodeSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Explode(params: [])) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentFlipSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 05/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentFlipSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Flip(fromDirection: .Left)) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentTurnSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 01/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentTurnSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Turn(fromDirection: .Left)) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/CornerDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/1/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol CornerDesignable { 9 | /** 10 | `border-radius` 11 | */ 12 | var cornerRadius: CGFloat { get set } 13 | } 14 | 15 | public extension CornerDesignable where Self: UIView { 16 | public func configCornerRadius() { 17 | if !cornerRadius.isNaN && cornerRadius > 0 { 18 | layer.cornerRadius = cornerRadius 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /IBAnimatable/PresentCardsSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 01/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentCardsSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Cards(direction: .Forward)) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentNatGeoSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 24/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentNatGeoSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.NatGeo(toDirection: .Left)) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentFoldSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 09/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentFoldSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Fold(fromDirection: .Left, params: [])) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentSlideSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 08/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentSlideSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Slide(toDirection: .Left, params: [])) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentPortalSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 17/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentPortalSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Portal(direction: .Forward, params: [])) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentFadeWithDismissInteractionSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 3/14/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentFadeWithDismissInteractionSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Fade(direction: .Cross), interactiveGestureType: .Default) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentFlipWithDismissInteractionSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 05/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentFlipWithDismissInteractionSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Flip(fromDirection: .Left), interactiveGestureType: .Default) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentTurnWithDismissInteractionSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 01/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentTurnWithDismissInteractionSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Turn(fromDirection: .Left), interactiveGestureType: .Default) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentNatGeoWithDismissInteractionSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 24/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentNatGeoWithDismissInteractionSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.NatGeo(toDirection: .Left), interactiveGestureType: .Default) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/ViewControllerDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/14/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol ViewControllerDesignable { 9 | var hideNavigationBar: Bool { get set } 10 | } 11 | 12 | public extension ViewControllerDesignable where Self: UIViewController { 13 | public func confingHideNavigationBar() { 14 | navigationController?.navigationBarHidden = hideNavigationBar 15 | } 16 | 17 | public func resetHideNavigationBar() { 18 | navigationController?.navigationBarHidden = false 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IBAnimatable/PresentFoldWithDismissInteractionSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 09/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentFoldWithDismissInteractionSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Fold(fromDirection: .Left, params: []), interactiveGestureType: .Default) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentSlideWithDismissInteractionSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 08/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentSlideWithDismissInteractionSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Slide(toDirection: .Left, params: []), interactiveGestureType: .Default) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/PresentPortalWithDismissInteractionSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 17/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PresentPortalWithDismissInteractionSegue: UIStoryboardSegue { 9 | public override func perform() { 10 | destinationViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(.Portal(direction: .Forward, params: []), interactiveGestureType: .Default) 11 | sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IBAnimatable/RotationDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/5/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | import Darwin 8 | 9 | /** 10 | It is not able to preview the rotation in IB. 11 | */ 12 | public protocol RotationDesignable { 13 | var rotate: CGFloat { get set } 14 | } 15 | 16 | public extension RotationDesignable where Self: UIView { 17 | public func configRotate() { 18 | if !rotate.isNaN && rotate > -360 && rotate < 360 { 19 | self.transform = CGAffineTransformMakeRotation(CGFloat(M_PI) * rotate / 180) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /IBAnimatable.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "IBAnimatable" 3 | s.version = "2.2" 4 | s.summary = "Design and prototype UI, interaction, navigation, transition and animation for App Store ready Apps in Interface Builder with IBAnimatable." 5 | s.homepage = "https://github.com/JakeLin/IBAnimatable" 6 | s.license = { :type => "MIT", :file => "LICENSE" } 7 | s.author = { "Jake Lin" => "JakeLinAu@gmail.com" } 8 | s.platform = :ios, '8.0' 9 | s.source = { :git => "https://github.com/JakeLin/IBAnimatable.git", tag: "#{s.version}" } 10 | s.source_files = "IBAnimatable/*.swift" 11 | end 12 | -------------------------------------------------------------------------------- /IBAnimatableApp/Functions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mark Hamilton on 4/9/16. 3 | // Copyright © 2016 dryverless. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | // Source: https://gist.github.com/TheDarkCode/2f65c1a25d5886ed210c3b33d73fe8a9 9 | // Based on earlier version: http://stackoverflow.com/a/28341290/749786 10 | public func iterateEnum(_: T.Type) -> AnyGenerator { 11 | var x = 0 12 | return AnyGenerator { 13 | let next = withUnsafePointer(&x) { 14 | UnsafePointer($0).memory 15 | } 16 | defer { 17 | x += 1 18 | } 19 | return next.hashValue == x ? next : nil 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /IBAnimatableApp/README.md: -------------------------------------------------------------------------------- 1 | # IBAnimatable Playground 2 | **IBAnimatable Playground** is a playground to see the features IBAnimatable can support for prototyping and designing UI, animations, transitions and interactions. You can find your favourite effects and apply them in Interface Builder. 3 | 4 | The `code` folder is not mandatory for the demo App. **The app was made in Interface Builder with `IBAnimatable` without a single line of code**. 5 | 6 | Because we want to demonstrate more effects (e.g. animations, transitions) with only one Scene in Interface Builder. In most of Apps, we usually apply one effect to one View or Scene, then we can configurate that effect in Interface Builder without any code. 7 | -------------------------------------------------------------------------------- /IBAnimatable/BarButtonItemDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/16/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol BarButtonItemDesignable { 9 | var roundedImage: UIImage? { get set } 10 | } 11 | 12 | public extension BarButtonItemDesignable where Self: UIBarButtonItem { 13 | public func confingBarButtonItemImage() { 14 | guard let unwrappedRoundedImage = roundedImage else { 15 | return 16 | } 17 | 18 | let originalImage: UIImage? = unwrappedRoundedImage.imageWithRenderingMode(.AlwaysOriginal) 19 | if let unwrappedImage = originalImage { 20 | image = unwrappedImage 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /IBAnimatable/ColorType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 13/02/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum ColorType: String { 9 | case FlatEmerland 10 | case FlatPomegranate 11 | case FlatWetAsphalt 12 | case FlatTurquoise 13 | case FlatConcrete 14 | case FlatOrange 15 | case FlatAsbestos 16 | case FlatPeterRiver 17 | case FlatSilver 18 | case FlatSunFlower 19 | case FlatAmethyst 20 | case FlatAlizarin 21 | case FlatGreenSea 22 | case FlatBelizeHole 23 | case FlatNephritis 24 | case FlatMidnightBlue 25 | case FlatClouds 26 | case FlatWisteria 27 | case FlatCarrot 28 | case FlatPumpkin 29 | } 30 | -------------------------------------------------------------------------------- /IBAnimatable/UIViewControllerExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/14/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | // MARK: - UIStoryboardSegue 9 | public extension UIViewController { 10 | @IBAction public func unwindToViewController(sender: UIStoryboardSegue) { 11 | } 12 | 13 | @IBAction public func dismissCurrentViewController(sender: UIStoryboardSegue) { 14 | sender.sourceViewController.dismissViewControllerAnimated(true, completion: nil) 15 | } 16 | 17 | @IBAction public func popToRootViewController(sender: UIStoryboardSegue) { 18 | sender.sourceViewController.navigationController?.popToRootViewControllerAnimated(true) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /IBAnimatable/PlaceholderDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/19/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol PlaceholderDesignable { 9 | /** 10 | `color` within `::-webkit-input-placeholder`, `::-moz-placeholder` or `:-ms-input-placeholder` 11 | */ 12 | var placeholderColor: UIColor? { get set } 13 | } 14 | 15 | public extension PlaceholderDesignable where Self: UITextField { 16 | public func configPlaceholderColor() { 17 | if let unwrappedPlaceholderColor = placeholderColor { 18 | attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: [NSForegroundColorAttributeName: unwrappedPlaceholderColor]) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /IBAnimatable/DesignableNavigationBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/10/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class DesignableNavigationBar: UINavigationBar, NavigationBarDesignable { 9 | @IBInspectable public var solidColor: Bool = false 10 | 11 | // MARK: - Lifecycle 12 | public override func prepareForInterfaceBuilder() { 13 | super.prepareForInterfaceBuilder() 14 | configInspectableProperties() 15 | } 16 | 17 | public override func awakeFromNib() { 18 | super.awakeFromNib() 19 | configInspectableProperties() 20 | } 21 | 22 | // MARK: - Private 23 | private func configInspectableProperties() { 24 | configNavigationBar() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /IBAnimatableApp/InteractionTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 5/12/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | class InteractionTableViewController: UITableViewController { 9 | 10 | } 11 | 12 | // MARK: - UITableViewDataSource / UITableViewDelegate 13 | 14 | extension InteractionTableViewController { 15 | 16 | // MARK: - reset the group heander font color and size 17 | override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { 18 | if let header = view as? UITableViewHeaderFooterView { 19 | header.textLabel?.textColor = UIColor.whiteColor() 20 | header.textLabel?.font = UIFont.systemFontOfSize(16, weight: UIFontWeightLight) 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /IBAnimatable/TransitionAnimatable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/24/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol TransitionAnimatable: class { 9 | /** 10 | String value of `TransitionAnimationType` enum, used to specify the transition animations 11 | */ 12 | var transitionAnimationType: String? { get set } 13 | 14 | /** 15 | Transition duration: default value should be `Double.NaN`. Need to use `Double` instead of `NSTimeInterval` because IB doesn't support `NSTimeInterval` 16 | */ 17 | var transitionDuration: Double { get set } 18 | 19 | /** 20 | String value of `InteractiveTransitionType` enum, used to specify the gesture to dismiss/pop current scence 21 | */ 22 | var interactiveGestureType: String? { get set } 23 | } 24 | -------------------------------------------------------------------------------- /IBAnimatable/RootWindowDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/25/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol RootWindowDesignable { 9 | /** 10 | Root window background color 11 | */ 12 | var rootWindowBackgroundColor: UIColor? { get set } 13 | } 14 | 15 | public extension RootWindowDesignable where Self: UIViewController { 16 | 17 | public func configRootWindowBackgroundColor() { 18 | #if NS_EXTENSION_UNAVAILABLE_IOS 19 | 20 | if let wrappedRootWindowBackgroundColor = rootWindowBackgroundColor, 21 | delegate = UIApplication.sharedApplication().delegate, 22 | rootWindow = delegate.window { 23 | rootWindow?.backgroundColor = wrappedRootWindowBackgroundColor 24 | } 25 | 26 | #endif 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /IBAnimatable/TableViewCellDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/19/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol TableViewCellDesignable { 9 | var removeSeparatorMargins: Bool { get set } 10 | } 11 | 12 | public extension TableViewCellDesignable where Self: UITableViewCell { 13 | public func configSeparatorMargins() { 14 | if removeSeparatorMargins { 15 | if respondsToSelector(Selector("setSeparatorInset:")) { 16 | separatorInset = UIEdgeInsetsZero 17 | } 18 | 19 | if respondsToSelector(Selector("setPreservesSuperviewLayoutMargins:")) { 20 | preservesSuperviewLayoutMargins = false 21 | } 22 | 23 | if respondsToSelector(Selector("setLayoutMargins:")) { 24 | layoutMargins = UIEdgeInsetsZero 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /IBAnimatable/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 | 2.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /IBAnimatable/InteractiveAnimatorFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 4/6/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | /** 8 | Interactive Animator Factory 9 | */ 10 | struct InteractiveAnimatorFactory { 11 | static func generateInteractiveAnimator(interactiveGestureType: InteractiveGestureType, transitionType: TransitionType) -> InteractiveAnimator? { 12 | switch interactiveGestureType { 13 | case .Pan: 14 | return PanInteractiveAnimator(interactiveGestureType: interactiveGestureType, transitionType: transitionType) 15 | case .ScreenEdgePan: 16 | return ScreenEdgePanInteractiveAnimator(interactiveGestureType: interactiveGestureType, transitionType: transitionType) 17 | case .Pinch: 18 | return PinchInteractiveAnimator(interactiveGestureType: interactiveGestureType, transitionType: transitionType) 19 | default: 20 | return nil 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /IBAnimatable/SystemTransitionType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/24/16. 3 | // Copyright (c) 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | /** 9 | System Transition Type: map to iOS built-in CATransition Type 10 | refer to http://iphonedevwiki.net/index.php/CATransition 11 | */ 12 | public enum SystemTransitionType: String { 13 | case Fade = "fade" // kCATransitionFade 14 | case MoveIn = "moveIn" // kCATransitionMoveIn 15 | case Push = "push" // kCATransitionPush 16 | case Reveal = "reveal" // kCATransitionReveal 17 | case Flip = "flip" 18 | case Cube = "cube" 19 | case PageCurl = "pageCurl" 20 | case PageUnCurl = "pageUnCurl" 21 | case RippleEffect = "rippleEffect" 22 | case SuckEffect = "suckEffect" 23 | case CameraIris = "cameraIris" 24 | case CameraIrisHollowOpen = "cameraIrisHollowOpen" 25 | case CameraIrisHollowClose = "cameraIrisHollowClose" 26 | case Rotate = "rotate" 27 | } 28 | -------------------------------------------------------------------------------- /IBAnimatable/UIColorExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 09/02/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | extension UIColor { 9 | 10 | convenience init(hexString: String) { 11 | let hex = hexString.stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet) 12 | var int = UInt32() 13 | NSScanner(string: hex).scanHexInt(&int) 14 | let a, r, g, b: UInt32 15 | switch hex.characters.count { 16 | case 3: 17 | (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) 18 | case 6: 19 | (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) 20 | case 8: 21 | (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) 22 | default: 23 | (a, r, g, b) = (1, 1, 1, 0) 24 | } 25 | self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /IBAnimatable/NavigationBarDesginable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/10/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol NavigationBarDesignable { 9 | /** 10 | Specify whether is solid color only, if `true` will remove hairline from navigation bar 11 | */ 12 | var solidColor: Bool { get set } 13 | } 14 | 15 | public extension NavigationBarDesignable where Self: UINavigationBar { 16 | public func configNavigationBar() { 17 | if solidColor { 18 | let emptyImage = UIImage() 19 | setBackgroundImage(emptyImage, forBarPosition: .Any, barMetrics: .Default) 20 | shadowImage = emptyImage 21 | // Need to manually untick translucent in Interface Builder, 22 | // otherwise, it will have constrait issue in IB although it is correct in run time. 23 | // translucent = false 24 | } else { 25 | setBackgroundImage(nil, forBarPosition: .Any, barMetrics: .Default) 26 | shadowImage = nil 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /IBAnimatable/CheckBoxDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/20/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol CheckBoxDesignable { 9 | var checked: Bool { get set } 10 | var checkedImage: UIImage? { get set } 11 | var uncheckedImage: UIImage? { get set } 12 | } 13 | 14 | public extension CheckBoxDesignable where Self: UIButton { 15 | public func configCheckBoxChecked() { 16 | selected = checked 17 | } 18 | 19 | public func configCheckBoxCheckedImage() { 20 | guard let unwrappedCheckedImage = checkedImage else { 21 | return 22 | } 23 | 24 | setBackgroundImage(unwrappedCheckedImage, forState: .Selected) 25 | setBackgroundImage(unwrappedCheckedImage, forState: [.Selected, .Highlighted]) 26 | } 27 | 28 | public func configCheckBoxUncheckedImage() { 29 | guard let unwrappedUncheckedImage = uncheckedImage else { 30 | return 31 | } 32 | 33 | setBackgroundImage(unwrappedUncheckedImage, forState: .Normal) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /IBAnimatable/TransitionFromDirection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016 Jake Lin. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | /** 8 | TransitionDirection: used to specify the direction for the transition 9 | */ 10 | public enum TransitionDirection { 11 | case Left 12 | case Right 13 | case Top 14 | case Bottom 15 | case Forward 16 | case Backward 17 | case In 18 | case Out 19 | case Cross 20 | 21 | // Convert from direction to CATransition Subtype used in `CATransition` 22 | var CATransitionSubtype: String { 23 | switch self { 24 | case .Left: 25 | return kCATransitionFromLeft 26 | case .Right: 27 | return kCATransitionFromRight 28 | case .Top: 29 | // The actual transition direction is oposite, need to reverse 30 | return kCATransitionFromBottom 31 | case .Bottom: 32 | // The actual transition direction is oposite, need to reverse 33 | return kCATransitionFromTop 34 | default: 35 | return "" 36 | } 37 | } 38 | 39 | var isHorizontal: Bool { 40 | return self == .Left || self == .Right 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jake Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /IBAnimatableApp/TransitionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 3/1/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | import IBAnimatable 8 | 9 | class TransitionViewController: AnimatableViewController { 10 | 11 | @IBOutlet var presentButton: AnimatableButton! 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Transition animations start with `System` do not support Present transition, so hide it 17 | if let animationType = transitionAnimationType where animationType.hasPrefix("System") { 18 | // Cannot use `hidden` here because of `UIStackView` 19 | presentButton.alpha = 0 20 | } 21 | } 22 | 23 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 24 | super.prepareForSegue(segue, sender: sender) 25 | 26 | // Set the transition animation type for `AnimatableViewController`, used for Present/Dismiss transitions 27 | if let toViewController = segue.destinationViewController as? AnimatableViewController { 28 | toViewController.transitionAnimationType = transitionAnimationType 29 | toViewController.interactiveGestureType = interactiveGestureType 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /IBAnimatable/SystemRotateAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 02/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SystemRotateAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | public init(transitionDuration: Duration) { 16 | self.transitionDuration = transitionDuration 17 | self.transitionAnimationType = .SystemRotate 18 | self.reverseAnimationType = .SystemRotate 19 | 20 | super.init() 21 | } 22 | } 23 | 24 | extension SystemRotateAnimator: UIViewControllerAnimatedTransitioning { 25 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 26 | return retrieveTransitionDuration(transitionContext) 27 | } 28 | 29 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 30 | animateWithCATransition(transitionContext, type: SystemTransitionType.Rotate, subtype: "90") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /IBAnimatable/SystemSuckEffectAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 30/03/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SystemSuckEffectAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | public init(transitionDuration: Duration) { 16 | self.transitionDuration = transitionDuration 17 | self.transitionAnimationType = .SystemSuckEffect 18 | self.reverseAnimationType = .SystemSuckEffect 19 | super.init() 20 | } 21 | } 22 | 23 | extension SystemSuckEffectAnimator: UIViewControllerAnimatedTransitioning { 24 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 25 | return retrieveTransitionDuration(transitionContext) 26 | } 27 | 28 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 29 | animateWithCATransition(transitionContext, type: SystemTransitionType.SuckEffect, subtype: nil) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /IBAnimatable/SystemRippleEffectAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 30/03/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SystemRippleEffectAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | public init(transitionDuration: Duration) { 16 | self.transitionDuration = transitionDuration 17 | self.transitionAnimationType = .SystemRippleEffect 18 | self.reverseAnimationType = .SystemRippleEffect 19 | super.init() 20 | } 21 | } 22 | 23 | extension SystemRippleEffectAnimator: UIViewControllerAnimatedTransitioning { 24 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 25 | return retrieveTransitionDuration(transitionContext) 26 | } 27 | 28 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 29 | animateWithCATransition(transitionContext, type: SystemTransitionType.RippleEffect, subtype: nil) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /IBAnimatableApp/UIViewControllerExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 5/16/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | import IBAnimatable 8 | 9 | extension UIViewController { 10 | 11 | func generateRandomGradient() -> GradientType { 12 | var predefinedGradients = [GradientType]() 13 | iterateEnum(GradientType).forEach { 14 | predefinedGradients.append($0) 15 | } 16 | 17 | let randomIndex: Int = Int(arc4random_uniform(UInt32(predefinedGradients.count))) 18 | return predefinedGradients[randomIndex] 19 | } 20 | 21 | func retrieveGestureText(interactiveGestureType: InteractiveGestureType, transitionAnimationType: TransitionAnimationType, exit: String) -> String { 22 | switch interactiveGestureType { 23 | case .Default: 24 | // Default gesture 25 | let transitionAnimator = AnimatorFactory.generateAnimator(transitionAnimationType) 26 | if let interactiveGestureType = transitionAnimator.interactiveGestureType { 27 | return String("or use \(interactiveGestureType.toString()) gesture to \(exit)") 28 | } 29 | 30 | // The transition animator doesn't have default `interactiveGestureType` 31 | return "" 32 | default: 33 | // Specified gesture 34 | return String("or use \(interactiveGestureType.toString()) gesture to \(exit)") 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /IBAnimatable/AnimationType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/19/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | /** 9 | Predefined Animation Type 10 | */ 11 | public enum AnimationType: String { 12 | case SlideInLeft 13 | case SlideInRight 14 | case SlideInDown 15 | case SlideInUp 16 | case SlideOutLeft 17 | case SlideOutRight 18 | case SlideOutDown 19 | case SlideOutUp 20 | case SqueezeInLeft 21 | case SqueezeInRight 22 | case SqueezeInDown 23 | case SqueezeInUp 24 | case SqueezeOutLeft 25 | case SqueezeOutRight 26 | case SqueezeOutDown 27 | case SqueezeOutUp 28 | case FadeIn 29 | case FadeOut 30 | case FadeOutIn 31 | case FadeInOut 32 | case FadeInLeft 33 | case FadeInRight 34 | case FadeInDown 35 | case FadeInUp 36 | case FadeOutLeft 37 | case FadeOutRight 38 | case FadeOutDown 39 | case FadeOutUp 40 | case SqueezeFadeInLeft 41 | case SqueezeFadeInRight 42 | case SqueezeFadeInDown 43 | case SqueezeFadeInUp 44 | case SqueezeFadeOutLeft 45 | case SqueezeFadeOutRight 46 | case SqueezeFadeOutDown 47 | case SqueezeFadeOutUp 48 | case ZoomIn 49 | case ZoomOut 50 | case Shake 51 | case Pop 52 | case FlipX 53 | case FlipY 54 | case Morph 55 | case Squeeze 56 | case Flash 57 | case Wobble 58 | case Swing 59 | case Rotate 60 | case RotateCCW 61 | case MoveTo 62 | case MoveBy 63 | } 64 | -------------------------------------------------------------------------------- /IBAnimatable/PaddingDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/18/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol PaddingDesignable { 9 | /** 10 | `padding-left` 11 | */ 12 | var paddingLeft: CGFloat { get set } 13 | 14 | /** 15 | `padding-right` 16 | */ 17 | var paddingRight: CGFloat { get set } 18 | 19 | /** 20 | `padding-left` and `padding-right` 21 | */ 22 | var paddingSide: CGFloat { get set } 23 | } 24 | 25 | public extension PaddingDesignable where Self: UITextField { 26 | public func configPaddingLeft() { 27 | if paddingLeft.isNaN { 28 | return 29 | } 30 | 31 | let padding = UIView(frame: CGRect(x: 0, y: 0, width: paddingLeft, height: 0)) 32 | leftViewMode = .Always 33 | leftView = padding 34 | } 35 | 36 | public func configPaddingRight() { 37 | if paddingRight.isNaN { 38 | return 39 | } 40 | 41 | let padding = UIView(frame: CGRect(x: 0, y: 0, width: paddingRight, height: 0)) 42 | rightViewMode = .Always 43 | rightView = padding 44 | } 45 | 46 | public func configPaddingSide() { 47 | if paddingSide.isNaN { 48 | return 49 | } 50 | 51 | let padding = UIView(frame: CGRect(x: 0, y: 0, width: paddingSide, height: paddingSide)) 52 | leftViewMode = .Always 53 | leftView = padding 54 | 55 | rightViewMode = .Always 56 | rightView = padding 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /IBAnimatableApp/TransitionPushedViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 5/13/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | import IBAnimatable 8 | 9 | class TransitionPushedViewController: UIViewController { 10 | 11 | @IBOutlet var gestureLabel: UILabel! 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | if let animatableView = view as? AnimatableView { 17 | animatableView.predefinedGradient = String(generateRandomGradient()) 18 | } 19 | configureGestureLabel() 20 | } 21 | 22 | } 23 | 24 | private extension TransitionPushedViewController { 25 | 26 | func configureGestureLabel() { 27 | // Shows nothing by default 28 | gestureLabel.text = "to pop" 29 | 30 | guard let navigationController = self.navigationController as? AnimatableNavigationController else { 31 | return 32 | } 33 | 34 | // No gesture for this animator 35 | guard let interactiveGestureTypeString = navigationController.interactiveGestureType, 36 | interactiveGestureType = InteractiveGestureType.fromString(interactiveGestureTypeString), 37 | transitionAnimationTypeString = navigationController.transitionAnimationType, 38 | transitionAnimationType = TransitionAnimationType.fromString(transitionAnimationTypeString) else { 39 | return 40 | } 41 | 42 | gestureLabel.text = retrieveGestureText(interactiveGestureType, transitionAnimationType: transitionAnimationType, exit: "pop") 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /IBAnimatable.playground/Pages/Chaining Animations.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | //: ## Chaining Animations 4 | 5 | import UIKit 6 | import XCPlayground 7 | import IBAnimatable 8 | 9 | //: Constants 10 | let iPhoneWidth = 375 11 | let iPhoneHeight = 667 12 | let animatableViewWidth = 100 13 | let animatableViewX = (iPhoneWidth - animatableViewWidth) / 2 14 | let animatableViewY = (iPhoneHeight - animatableViewWidth) / 2 15 | 16 | //: Set up the iPhone View 17 | let iPhoneView = UIView(frame: CGRect(x: 0, y: 0, width: iPhoneWidth, height: iPhoneHeight)) 18 | iPhoneView.backgroundColor = .whiteColor() 19 | XCPlaygroundPage.currentPage.liveView = iPhoneView 20 | 21 | //: Set up the animatable View 22 | let view = AnimatableView(frame: CGRect(x: animatableViewX, y: animatableViewY, width: animatableViewWidth, height: animatableViewWidth)) 23 | view.configAnimatableProperties() 24 | iPhoneView.addSubview(view) 25 | 26 | view.fillColor = UIColor(red: 0xba/0xff, green: 0x77/0xff, blue: 1, alpha: 1) 27 | view.maskType = String(MaskType.Circle) 28 | 29 | //: Start another animation in completion closure 30 | view.squeezeInDown { view.pop { view.shake { view.squeeze { view.wobble { view.flipX { view.flash { view.flipY { view.fadeOutDown() } } } } } } } } 31 | 32 | //: To apply delay, we can specify the animationType and delay 33 | //view.animationType = String(AnimationType.Pop) 34 | //view.animate{ 35 | // view.delay = 0.3 36 | // view.animationType = String(AnimationType.Shake) 37 | // view.animate() 38 | //} 39 | 40 | //: [Next](@next) 41 | -------------------------------------------------------------------------------- /IBAnimatable/BlurDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/23/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol BlurDesignable { 9 | /** 10 | blur effect style: `ExtraLight`, `Light` or `Dark` 11 | */ 12 | var blurEffectStyle: String? { get set } 13 | 14 | var blurOpacity: CGFloat { get set } 15 | } 16 | 17 | public extension BlurDesignable where Self: UIView { 18 | /** 19 | configBlurEffectStyle method, should be called in layoutSubviews() method 20 | */ 21 | public func configBlurEffectStyle() { 22 | guard let unwrappedBlurEffectStyle = blurEffectStyle else { 23 | return 24 | } 25 | 26 | var style: UIBlurEffectStyle? 27 | guard let blurEffectStyle = BlurEffectStyle(rawValue: unwrappedBlurEffectStyle) else { 28 | return 29 | } 30 | 31 | switch blurEffectStyle { 32 | case .ExtraLight: 33 | style = .ExtraLight 34 | case .Light: 35 | style = .Light 36 | case .Dark: 37 | style = .Dark 38 | } 39 | 40 | let blurEffect = UIBlurEffect(style: style!) 41 | let blurEffectView = UIVisualEffectView(effect: blurEffect) 42 | blurEffectView.frame = bounds 43 | let opacity = blurOpacity.isNaN ? 1.0 : blurOpacity // Default is 1.0 44 | blurEffectView.alpha = opacity 45 | if layer.cornerRadius > 0 { 46 | blurEffectView.layer.cornerRadius = layer.cornerRadius 47 | blurEffectView.clipsToBounds = true 48 | } 49 | blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] 50 | insertSubview(blurEffectView, atIndex: 0) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableBarButtonItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/16/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableBarButtonItem: UIBarButtonItem, BarButtonItemDesignable, Animatable { 9 | // MARK: - BarButtonItemDesignable 10 | @IBInspectable public var roundedImage: UIImage? 11 | 12 | // MARK: - Lifecycle 13 | public override func prepareForInterfaceBuilder() { 14 | super.prepareForInterfaceBuilder() 15 | configInspectableProperties() 16 | } 17 | 18 | public override func awakeFromNib() { 19 | super.awakeFromNib() 20 | configInspectableProperties() 21 | } 22 | 23 | // TODO: animations 24 | // public override func layoutSubviews() { 25 | // super.layoutSubviews() 26 | // 27 | // autoRunAnimation() 28 | // } 29 | 30 | // MARK: - Animatable 31 | @IBInspectable public var animationType: String? 32 | @IBInspectable public var autoRun: Bool = true 33 | @IBInspectable public var duration: Double = Double.NaN 34 | @IBInspectable public var delay: Double = Double.NaN 35 | @IBInspectable public var damping: CGFloat = CGFloat.NaN 36 | @IBInspectable public var velocity: CGFloat = CGFloat.NaN 37 | @IBInspectable public var force: CGFloat = CGFloat.NaN 38 | @IBInspectable public var repeatCount: Float = Float.NaN 39 | @IBInspectable public var x: CGFloat = CGFloat.NaN 40 | @IBInspectable public var y: CGFloat = CGFloat.NaN 41 | 42 | // MARK: - Private 43 | private func configInspectableProperties() { 44 | // configAnimatableProperties() 45 | confingBarButtonItemImage() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /IBAnimatable/PresenterManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/29/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | /** 9 | Presenter Manager: Used to cache the Presenters for Present and Dismiss transitions 10 | */ 11 | public class PresenterManager { 12 | // MARK: - Singleton Constructor 13 | private init() {} 14 | private struct Shared { 15 | static let instance = PresenterManager() 16 | } 17 | 18 | public static func sharedManager() -> PresenterManager { 19 | return Shared.instance 20 | } 21 | 22 | // MARK: - Private 23 | private var cache = [String: Presenter]() 24 | 25 | // MARK: Internal Interface 26 | public func retrievePresenter(transitionAnimationType: TransitionAnimationType, transitionDuration: Duration = defaultTransitionDuration, interactiveGestureType: InteractiveGestureType? = nil) -> Presenter { 27 | // Get the cached presenter 28 | let presenter = cache[transitionAnimationType.stringValue] 29 | if let presenter = presenter { 30 | // Update the `transitionDuration` and `interactiveGestureType` every time to reuse the same presenter with the same type 31 | presenter.transitionDuration = transitionDuration 32 | presenter.interactiveGestureType = interactiveGestureType 33 | return presenter 34 | } 35 | 36 | // Create a new if cache doesn't exist 37 | let newPresenter = Presenter(transitionAnimationType: transitionAnimationType, transitionDuration: transitionDuration, interactiveGestureType: interactiveGestureType) 38 | cache[transitionAnimationType.stringValue] = newPresenter 39 | return newPresenter 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /IBAnimatableApp/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 | -------------------------------------------------------------------------------- /IBAnimatableApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Animatable 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 2.1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UIStatusBarHidden 36 | 37 | UIStatusBarStyle 38 | UIStatusBarStyleLightContent 39 | UISupportedInterfaceOrientations 40 | 41 | UIInterfaceOrientationPortrait 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /IBAnimatable/SystemPageAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 28/03/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SystemPageAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | // MARK: - private 16 | private var type: TransitionPageType 17 | 18 | public init(type: TransitionPageType, transitionDuration: Duration) { 19 | self.transitionDuration = transitionDuration 20 | self.type = type 21 | 22 | switch type { 23 | case .Curl: 24 | self.transitionAnimationType = .SystemPage(type: .Curl) 25 | self.reverseAnimationType = .SystemPage(type: .UnCurl) 26 | case .UnCurl: 27 | self.transitionAnimationType = .SystemPage(type: .UnCurl) 28 | self.reverseAnimationType = .SystemPage(type: .Curl) 29 | } 30 | 31 | super.init() 32 | } 33 | } 34 | 35 | extension SystemPageAnimator: UIViewControllerAnimatedTransitioning { 36 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 37 | return retrieveTransitionDuration(transitionContext) 38 | } 39 | 40 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 41 | switch self.type { 42 | case .Curl: 43 | animateWithCATransition(transitionContext, type: SystemTransitionType.PageCurl, subtype: nil) 44 | case .UnCurl: 45 | animateWithCATransition(transitionContext, type: SystemTransitionType.PageUnCurl, subtype: nil) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /IBAnimatable/TintDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/24/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol TintDesignable { 9 | /** 10 | Opacity in tint Color (White): from 0 to 1 11 | */ 12 | var tintOpacity: CGFloat { get set } 13 | 14 | 15 | /** 16 | Opacity in shade Color (Black): from 0 to 1 17 | */ 18 | var shadeOpacity: CGFloat { get set } 19 | 20 | /** 21 | tone color 22 | */ 23 | var toneColor: UIColor? { get set } 24 | 25 | /** 26 | Opacity in tone color: from 0 to 1 27 | */ 28 | var toneOpacity: CGFloat { get set } 29 | } 30 | 31 | public extension TintDesignable where Self: UIView { 32 | /** 33 | configTintedColor method, should be called in layoutSubviews() method 34 | */ 35 | public func configTintedColor() { 36 | if !tintOpacity.isNaN && tintOpacity >= 0 && tintOpacity <= 1 { 37 | addColorSubview(UIColor.whiteColor(), opacity: tintOpacity) 38 | } 39 | 40 | if !shadeOpacity.isNaN && shadeOpacity >= 0 && shadeOpacity <= 1 { 41 | addColorSubview(UIColor.blackColor(), opacity: shadeOpacity) 42 | } 43 | 44 | if let unwrappedToneColor = toneColor { 45 | if !toneOpacity.isNaN && toneOpacity >= 0 && toneOpacity <= 1 { 46 | addColorSubview(unwrappedToneColor, opacity: toneOpacity) 47 | } 48 | } 49 | } 50 | 51 | private func addColorSubview(color: UIColor, opacity: CGFloat) { 52 | let subview = UIView(frame: self.bounds) 53 | subview.backgroundColor = color 54 | subview.alpha = opacity 55 | if layer.cornerRadius > 0 { 56 | subview.layer.cornerRadius = layer.cornerRadius 57 | } 58 | subview.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] 59 | self.insertSubview(subview, atIndex: 0) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Scripts/GradientsTypeScript.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/swift 2 | 3 | import Foundation 4 | 5 | let gradientTypeURL = "https://raw.githubusercontent.com/Ghosh/uiGradients/master/gradients.json" 6 | 7 | func JSONFromURL(urlToRequest: String) -> NSData { 8 | return NSData(contentsOfURL: NSURL(string: urlToRequest)!)! 9 | } 10 | 11 | func parseJSON(JSONData: NSData) -> [[String: AnyObject]]? { 12 | var json: [[String: AnyObject]]? 13 | do { 14 | json = try NSJSONSerialization.JSONObjectWithData(JSONData, options: .MutableContainers) as? [[String: AnyObject]] 15 | return json 16 | } catch { 17 | print("JSON serialization did fail") 18 | return nil 19 | } 20 | } 21 | 22 | // Generator constants 23 | let enumCase = "\tcase %@\n" 24 | let switchCase = "case .%@:\n" 25 | let colors = "\treturn (UIColor(hexString: \"%@\"), UIColor(hexString: \"%@\"))\n" 26 | let endEnumOrSwitch = "}" 27 | 28 | // Finale string 29 | var enumGradientType = "public enum GradientType: String {\n" 30 | var switchPredefinedGradientType = "switch gradientType {\n" 31 | 32 | // Enum generator 33 | let gradientsType = parseJSON(JSONFromURL(gradientTypeURL)) 34 | for gradient in gradientsType! { 35 | if var name = gradient["name"] as? String, 36 | unwrappedColors = gradient["colors"] as? [String], 37 | startColor = unwrappedColors.first, 38 | endColor = unwrappedColors.last { 39 | name = name.stringByReplacingOccurrencesOfString(" ", withString: "") 40 | enumGradientType += String(format: enumCase, name) 41 | switchPredefinedGradientType += String(format: switchCase, name) 42 | switchPredefinedGradientType += String(format: colors, startColor, endColor) 43 | } 44 | } 45 | 46 | enumGradientType += endEnumOrSwitch 47 | switchPredefinedGradientType += endEnumOrSwitch 48 | print(enumGradientType) 49 | print("\n") 50 | print(switchPredefinedGradientType) 51 | -------------------------------------------------------------------------------- /IBAnimatableApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-29@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-29@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-40@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-40@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-60@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-60@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "idiom" : "ipad", 41 | "size" : "29x29", 42 | "scale" : "1x" 43 | }, 44 | { 45 | "size" : "29x29", 46 | "idiom" : "ipad", 47 | "filename" : "Icon-29@2x.png", 48 | "scale" : "2x" 49 | }, 50 | { 51 | "idiom" : "ipad", 52 | "size" : "40x40", 53 | "scale" : "1x" 54 | }, 55 | { 56 | "size" : "40x40", 57 | "idiom" : "ipad", 58 | "filename" : "Icon-40@2x.png", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "size" : "76x76", 63 | "idiom" : "ipad", 64 | "filename" : "Icon-76.png", 65 | "scale" : "1x" 66 | }, 67 | { 68 | "size" : "76x76", 69 | "idiom" : "ipad", 70 | "filename" : "Icon-76@2x.png", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "size" : "83.5x83.5", 75 | "idiom" : "ipad", 76 | "filename" : "Icon-83.5@2x.png", 77 | "scale" : "2x" 78 | } 79 | ], 80 | "info" : { 81 | "version" : 1, 82 | "author" : "xcode" 83 | } 84 | } -------------------------------------------------------------------------------- /IBAnimatable/AnimatableNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/20/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class AnimatableNavigationController: UINavigationController, TransitionAnimatable { 9 | 10 | // MARK: - TransitionAnimatable 11 | @IBInspectable public var transitionAnimationType: String? { 12 | didSet { 13 | configureNavigationControllerDelegate() 14 | } 15 | } 16 | @IBInspectable public var transitionDuration: Double = .NaN { 17 | didSet { 18 | configureNavigationControllerDelegate() 19 | } 20 | } 21 | @IBInspectable public var interactiveGestureType: String? { 22 | didSet { 23 | configureNavigationControllerDelegate() 24 | } 25 | } 26 | 27 | // MARK: - Lifecylce 28 | public override func viewDidLoad() { 29 | super.viewDidLoad() 30 | configureNavigationControllerDelegate() 31 | } 32 | 33 | // MARK: - Private 34 | // Must have a property to keep the reference alive because `UINavigationController.delegate` is `weak` 35 | private var navigator: Navigator? 36 | 37 | private func configureNavigationControllerDelegate() { 38 | guard let transitionAnimationType = transitionAnimationType, animationType = TransitionAnimationType.fromString(transitionAnimationType) else { 39 | navigator = nil 40 | delegate = nil 41 | return 42 | } 43 | var duration = transitionDuration 44 | // Set the default duration for transition 45 | if transitionDuration.isNaN { 46 | duration = defaultTransitionDuration 47 | } 48 | if let interactiveGestureType = interactiveGestureType, gestureType = InteractiveGestureType.fromString(interactiveGestureType) { 49 | navigator = Navigator(transitionAnimationType: animationType, transitionDuration: duration, interactiveGestureType: gestureType) 50 | } else { 51 | navigator = Navigator(transitionAnimationType: animationType, transitionDuration: duration) 52 | } 53 | delegate = navigator 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /IBAnimatable/ShadowDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/18/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | /** 9 | These properties are not able to render in IB correctly, it maybe a bug of IB. 10 | 11 | To use them, `UIView`'s `clipsToBounds` and `CALayer`'s `masksToBounds` (`Clip Subviews` in IB) must be `false`, 12 | */ 13 | public protocol ShadowDesignable { 14 | /** 15 | `color` when using with `box-shadow` 16 | */ 17 | var shadowColor: UIColor? { get set } 18 | 19 | /** 20 | Radius in `box-shadow` 21 | */ 22 | var shadowRadius: CGFloat { get set } 23 | 24 | /** 25 | Opacity in `box-shadow`: from 0 to 1 26 | */ 27 | var shadowOpacity: CGFloat { get set } 28 | 29 | /** 30 | Offset in `box-shadow`. `x` is horizontal offset and `y` is vertical offset 31 | */ 32 | var shadowOffset: CGPoint { get set } 33 | } 34 | 35 | public extension ShadowDesignable where Self: UIView { 36 | public func configShadowColor() { 37 | if let unwrappedShadowColor = shadowColor { 38 | commonSetup() 39 | layer.shadowColor = unwrappedShadowColor.CGColor 40 | } 41 | } 42 | 43 | public func configShadowRadius() { 44 | if !shadowRadius.isNaN && shadowRadius > 0 { 45 | commonSetup() 46 | layer.shadowRadius = shadowRadius 47 | } 48 | } 49 | 50 | public func configShadowOpacity() { 51 | if !shadowOpacity.isNaN && shadowOpacity >= 0 && shadowOpacity <= 1 { 52 | commonSetup() 53 | layer.shadowOpacity = Float(shadowOpacity) 54 | } 55 | } 56 | 57 | public func configShadowOffset() { 58 | if !shadowOffset.x.isNaN { 59 | commonSetup() 60 | layer.shadowOffset.width = shadowOffset.x 61 | } 62 | 63 | if !shadowOffset.y.isNaN { 64 | commonSetup() 65 | layer.shadowOffset.height = shadowOffset.y 66 | } 67 | } 68 | 69 | private func commonSetup() { 70 | // Need to set `layer.masksToBounds` to `false`. 71 | // If `layer.masksToBounds == true` then shadow doesn't work any more. 72 | if layer.masksToBounds { 73 | layer.masksToBounds = false 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /IBAnimatableApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/18/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @UIApplicationMain 9 | class AppDelegate: UIResponder, UIApplicationDelegate { 10 | 11 | var window: UIWindow? 12 | 13 | 14 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 15 | // Override point for customization after application launch. 16 | return true 17 | } 18 | 19 | func applicationWillResignActive(application: UIApplication) { 20 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 21 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 22 | } 23 | 24 | func applicationDidEnterBackground(application: UIApplication) { 25 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 26 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 27 | } 28 | 29 | func applicationWillEnterForeground(application: UIApplication) { 30 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 31 | } 32 | 33 | func applicationDidBecomeActive(application: UIApplication) { 34 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 35 | } 36 | 37 | func applicationWillTerminate(application: UIApplication) { 38 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Scripts/FlatColorsTypeScript.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/swift 2 | 3 | import Foundation 4 | 5 | let colorsTypeURL = "https://gist.githubusercontent.com/tkrugg/a577c32e93eecc6c7991/raw/f7866132e26f9bffcda9caf13dced55e4a99e145/flatuicolors.json" 6 | 7 | func JSONFromURL(urlToRequest: String) -> NSData { 8 | return NSData(contentsOfURL: NSURL(string: urlToRequest)!)! 9 | } 10 | 11 | func parseJSON(JSONData: NSData) -> [String: String]? { 12 | var json: [String: String]? 13 | do { 14 | json = try NSJSONSerialization.JSONObjectWithData(JSONData, options: .MutableContainers) as? [String: String] 15 | return json 16 | } catch { 17 | print("JSON serialization did fail") 18 | return nil 19 | } 20 | } 21 | 22 | // Generator constants 23 | let enumCase = "\tcase %@\n" 24 | let switchCase = "case .%@:\n" 25 | let color = "\treturn UIColor(red: %@ / 255, green: %@ / 255, blue: %@ / 255, alpha: %@)\n" 26 | let endEnumOrSwitch = "}" 27 | 28 | // Finale string 29 | var enumColorType = "public enum ColorType: String {\n" 30 | var switchColorType = "switch colorType {\n" 31 | 32 | // Enum generator 33 | let colorsType: Dictionary? = parseJSON(JSONFromURL(colorsTypeURL)) 34 | 35 | // Parsing 36 | if let uwnrappedColorsType = colorsType { 37 | for colorName in uwnrappedColorsType.keys { 38 | if var unwrappedRGBColors = uwnrappedColorsType[colorName] { 39 | var finalName = colorName.capitalizedStringWithLocale(NSLocale.currentLocale()) 40 | finalName = finalName.stringByReplacingOccurrencesOfString("-", withString: "") 41 | finalName = "Flat" + finalName 42 | enumColorType += String(format: enumCase, finalName) 43 | switchColorType += String(format: switchCase, finalName) 44 | 45 | unwrappedRGBColors = unwrappedRGBColors.stringByReplacingOccurrencesOfString("rgba(", withString: "") 46 | unwrappedRGBColors = unwrappedRGBColors.stringByReplacingOccurrencesOfString(")", withString: "") 47 | let colors = unwrappedRGBColors.componentsSeparatedByString(",") 48 | switchColorType += String(format: color, colors[0], colors[1], colors[2], colors[3]) 49 | } 50 | } 51 | 52 | enumColorType += endEnumOrSwitch 53 | switchColorType += endEnumOrSwitch 54 | print(enumColorType) 55 | print("\n") 56 | print(switchColorType) 57 | } 58 | -------------------------------------------------------------------------------- /IBAnimatable/SystemRevealAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 02/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SystemRevealAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | // MARK: - private 16 | private var fromDirection: TransitionDirection 17 | 18 | public init(fromDirection: TransitionDirection, transitionDuration: Duration) { 19 | self.fromDirection = fromDirection 20 | self.transitionDuration = transitionDuration 21 | 22 | switch fromDirection { 23 | case .Right: 24 | self.transitionAnimationType = .SystemReveal(fromDirection: .Right) 25 | self.reverseAnimationType = .SystemReveal(fromDirection: .Left) 26 | self.interactiveGestureType = .Pan(fromDirection: .Left) 27 | case .Top: 28 | self.transitionAnimationType = .SystemReveal(fromDirection: .Top) 29 | self.reverseAnimationType = .SystemReveal(fromDirection: .Bottom) 30 | self.interactiveGestureType = .Pan(fromDirection: .Bottom) 31 | case .Bottom: 32 | self.transitionAnimationType = .SystemReveal(fromDirection: .Bottom) 33 | self.reverseAnimationType = .SystemReveal(fromDirection: .Top) 34 | self.interactiveGestureType = .Pan(fromDirection: .Top) 35 | default: 36 | self.transitionAnimationType = .SystemPush(fromDirection: .Left) 37 | self.reverseAnimationType = .SystemPush(fromDirection: .Right) 38 | self.interactiveGestureType = .Pan(fromDirection: .Right) 39 | } 40 | 41 | super.init() 42 | } 43 | } 44 | 45 | extension SystemRevealAnimator: UIViewControllerAnimatedTransitioning { 46 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 47 | return retrieveTransitionDuration(transitionContext) 48 | } 49 | 50 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 51 | animateWithCATransition(transitionContext, type: SystemTransitionType.Reveal, subtype: fromDirection.CATransitionSubtype) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /IBAnimatable/SystemMoveInAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 02/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SystemMoveInAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | // MARK: - private 16 | private var fromDirection: TransitionDirection 17 | 18 | public init(fromDirection: TransitionDirection, transitionDuration: Duration) { 19 | self.fromDirection = fromDirection 20 | self.transitionDuration = transitionDuration 21 | 22 | switch fromDirection { 23 | case .Right: 24 | self.transitionAnimationType = .SystemMoveIn(fromDirection: .Right) 25 | self.reverseAnimationType = .SystemMoveIn(fromDirection: .Left) 26 | self.interactiveGestureType = .Pan(fromDirection: .Left) 27 | case .Top: 28 | self.transitionAnimationType = .SystemMoveIn(fromDirection: .Top) 29 | self.reverseAnimationType = .SystemMoveIn(fromDirection: .Bottom) 30 | self.interactiveGestureType = .Pan(fromDirection: .Bottom) 31 | case .Bottom: 32 | self.transitionAnimationType = .SystemMoveIn(fromDirection: .Bottom) 33 | self.reverseAnimationType = .SystemMoveIn(fromDirection: .Top) 34 | self.interactiveGestureType = .Pan(fromDirection: .Top) 35 | default: 36 | self.transitionAnimationType = .SystemMoveIn(fromDirection: .Left) 37 | self.reverseAnimationType = .SystemMoveIn(fromDirection: .Right) 38 | self.interactiveGestureType = .Pan(fromDirection: .Right) 39 | } 40 | 41 | super.init() 42 | } 43 | } 44 | 45 | extension SystemMoveInAnimator: UIViewControllerAnimatedTransitioning { 46 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 47 | return retrieveTransitionDuration(transitionContext) 48 | } 49 | 50 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 51 | animateWithCATransition(transitionContext, type: SystemTransitionType.MoveIn, subtype: fromDirection.CATransitionSubtype) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /IBAnimatable/SystemPushAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SystemPushAnimator.swift 3 | // IBAnimatableApp 4 | // 5 | // Created by Tom Baranes on 02/04/16. 6 | // Copyright © 2016 Jake Lin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class SystemPushAnimator: NSObject, AnimatedTransitioning { 12 | // MARK: - AnimatorProtocol 13 | public var transitionAnimationType: TransitionAnimationType 14 | public var transitionDuration: Duration = defaultTransitionDuration 15 | public var reverseAnimationType: TransitionAnimationType? 16 | public var interactiveGestureType: InteractiveGestureType? 17 | 18 | // MARK: - private 19 | private var fromDirection: TransitionDirection 20 | 21 | public init(fromDirection: TransitionDirection, transitionDuration: Duration) { 22 | self.fromDirection = fromDirection 23 | self.transitionDuration = transitionDuration 24 | 25 | switch fromDirection { 26 | case .Right: 27 | self.transitionAnimationType = .SystemPush(fromDirection: .Right) 28 | self.reverseAnimationType = .SystemPush(fromDirection: .Left) 29 | self.interactiveGestureType = .Pan(fromDirection: .Left) 30 | case .Top: 31 | self.transitionAnimationType = .SystemPush(fromDirection: .Top) 32 | self.reverseAnimationType = .SystemPush(fromDirection: .Bottom) 33 | self.interactiveGestureType = .Pan(fromDirection: .Bottom) 34 | case .Bottom: 35 | self.transitionAnimationType = .SystemPush(fromDirection: .Bottom) 36 | self.reverseAnimationType = .SystemPush(fromDirection: .Top) 37 | self.interactiveGestureType = .Pan(fromDirection: .Top) 38 | default: 39 | self.transitionAnimationType = .SystemPush(fromDirection: .Left) 40 | self.reverseAnimationType = .SystemPush(fromDirection: .Right) 41 | self.interactiveGestureType = .Pan(fromDirection: .Right) 42 | } 43 | 44 | super.init() 45 | } 46 | } 47 | 48 | extension SystemPushAnimator: UIViewControllerAnimatedTransitioning { 49 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 50 | return retrieveTransitionDuration(transitionContext) 51 | } 52 | 53 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 54 | animateWithCATransition(transitionContext, type: SystemTransitionType.Push, subtype: fromDirection.CATransitionSubtype) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IBAnimatable/SystemCubeAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2016 Jake Lin. All rights reserved. 3 | // 4 | 5 | import UIKit 6 | 7 | /** 8 | System Cube Animator - To support 3D animation (Four rotation directions supported: left, right, top, bottom) 9 | */ 10 | public class SystemCubeAnimator: NSObject, AnimatedTransitioning { 11 | // MARK: - AnimatorProtocol 12 | public var transitionAnimationType: TransitionAnimationType 13 | public var transitionDuration: Duration = defaultTransitionDuration 14 | public var reverseAnimationType: TransitionAnimationType? 15 | public var interactiveGestureType: InteractiveGestureType? 16 | 17 | // MARK: - private 18 | private var fromDirection: TransitionDirection 19 | 20 | public init(fromDirection: TransitionDirection, transitionDuration: Duration) { 21 | self.fromDirection = fromDirection 22 | self.transitionDuration = transitionDuration 23 | 24 | switch fromDirection { 25 | case .Right: 26 | self.transitionAnimationType = .SystemCube(fromDirection: .Right) 27 | self.reverseAnimationType = .SystemCube(fromDirection: .Left) 28 | self.interactiveGestureType = .Pan(fromDirection: .Left) 29 | case .Top: 30 | self.transitionAnimationType = .SystemCube(fromDirection: .Top) 31 | self.reverseAnimationType = .SystemCube(fromDirection: .Bottom) 32 | self.interactiveGestureType = .Pan(fromDirection: .Bottom) 33 | case .Bottom: 34 | self.transitionAnimationType = .SystemCube(fromDirection: .Bottom) 35 | self.reverseAnimationType = .SystemCube(fromDirection: .Top) 36 | self.interactiveGestureType = .Pan(fromDirection: .Top) 37 | default: 38 | self.transitionAnimationType = .SystemCube(fromDirection: .Left) 39 | self.reverseAnimationType = .SystemCube(fromDirection: .Right) 40 | self.interactiveGestureType = .Pan(fromDirection: .Right) 41 | } 42 | 43 | super.init() 44 | } 45 | } 46 | 47 | extension SystemCubeAnimator: UIViewControllerAnimatedTransitioning { 48 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 49 | return retrieveTransitionDuration(transitionContext) 50 | } 51 | 52 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 53 | animateWithCATransition(transitionContext, type: SystemTransitionType.Cube, subtype: fromDirection.CATransitionSubtype) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /IBAnimatable/PanInteractiveAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 3/3/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | // Pan interactive animator: pan gesture transition controller 9 | public class PanInteractiveAnimator: InteractiveAnimator { 10 | 11 | override func createGestureRecognizer() -> UIGestureRecognizer { 12 | return UIPanGestureRecognizer(target: self, action: #selector(handleGesture(_:))) 13 | } 14 | 15 | override func calculateProgress(gestureRecognizer: UIGestureRecognizer) -> (progress: CGFloat, shouldFinishInteractiveTransition: Bool) { 16 | guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer, 17 | superview = gestureRecognizer.view?.superview else { 18 | return (0, false) 19 | } 20 | let translation = gestureRecognizer.translationInView(superview) 21 | let velocity = gestureRecognizer.velocityInView(superview) 22 | 23 | var progress: CGFloat 24 | let distance: CGFloat 25 | let speed: CGFloat 26 | switch interactiveGestureType { 27 | case let .Pan(direction): 28 | switch direction { 29 | case .Horizontal: 30 | distance = superview.frame.width 31 | progress = abs(translation.x / distance) 32 | speed = abs(velocity.x) 33 | case .Left: 34 | distance = superview.frame.width 35 | progress = translation.x / distance 36 | speed = velocity.x 37 | case .Right: 38 | distance = superview.frame.width 39 | progress = -(translation.x / distance) 40 | speed = -velocity.x 41 | case .Vertical: 42 | distance = superview.frame.height 43 | progress = abs(translation.y / distance) 44 | speed = abs(velocity.y) 45 | case .Top: 46 | distance = superview.frame.height 47 | progress = translation.y / distance 48 | speed = velocity.y 49 | case .Bottom: 50 | distance = superview.frame.height 51 | progress = -translation.y / distance 52 | speed = -velocity.y 53 | default: 54 | return (0, false) 55 | } 56 | default: 57 | return (0, false) 58 | } 59 | 60 | progress = min(max(progress, 0), 0.99) 61 | 62 | // Finish the transition when pass the threathold 63 | let shouldFinishInteractiveTransition = progress > 0.5 || speed > 1000 64 | return (progress, shouldFinishInteractiveTransition) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /IBAnimatable/PinchInteractiveAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 4/26/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class PinchInteractiveAnimator: InteractiveAnimator { 9 | private var startScale: CGFloat = 0 10 | 11 | override func createGestureRecognizer() -> UIGestureRecognizer { 12 | let gestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(handleGesture(_:))) 13 | return gestureRecognizer 14 | } 15 | 16 | override func shouldBeginProgress(gestureRecognizer: UIGestureRecognizer) -> Bool { 17 | guard let gestureRecognizer = gestureRecognizer as? UIPinchGestureRecognizer else { 18 | return false 19 | } 20 | 21 | switch interactiveGestureType { 22 | case let .Pinch(direction): 23 | switch direction { 24 | case .Close: 25 | return gestureRecognizer.velocity < 0 26 | case .Open: 27 | return gestureRecognizer.velocity > 0 28 | default: 29 | return true 30 | } 31 | default: 32 | return false 33 | } 34 | } 35 | 36 | override func calculateProgress(gestureRecognizer: UIGestureRecognizer) -> (progress: CGFloat, shouldFinishInteractiveTransition: Bool) { 37 | guard let gestureRecognizer = gestureRecognizer as? UIPinchGestureRecognizer, 38 | _ = gestureRecognizer.view?.superview else { 39 | return (0, false) 40 | } 41 | 42 | if gestureRecognizer.state == .Began { 43 | startScale = gestureRecognizer.scale 44 | } 45 | 46 | var progress: CGFloat 47 | let _: CGFloat 48 | switch interactiveGestureType { 49 | case let .Pinch(direction): 50 | switch direction { 51 | case .Close: 52 | progress = 1.0 - gestureRecognizer.scale / startScale 53 | case .Open: 54 | let scaleFator: CGFloat = 1.2 // To make the pinch open gesture more natural 😓 55 | progress = gestureRecognizer.scale / scaleFator - 1.0 56 | default: 57 | // For both `.Close` and `.Open` 58 | progress = abs(1.0 - gestureRecognizer.scale / startScale) 59 | } 60 | default: 61 | return (0, false) 62 | } 63 | 64 | progress = min(max(progress, 0), 0.99) 65 | 66 | // Finish the transition when pass the threathold 67 | let shouldFinishInteractiveTransition = progress > 0.5 68 | 69 | return (progress, shouldFinishInteractiveTransition) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /IBAnimatable/SystemCameraIrisAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 30/03/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SystemCameraIrisAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | // MARK: - private 16 | private var hollowState: TransitionHollowState 17 | 18 | public init(hollowState: TransitionHollowState, transitionDuration: Duration) { 19 | self.transitionDuration = transitionDuration 20 | self.hollowState = hollowState 21 | 22 | switch hollowState { 23 | case .Open: 24 | self.transitionAnimationType = .SystemCameraIris(hollowState: .Open) 25 | self.reverseAnimationType = .SystemCameraIris(hollowState: .Close) 26 | self.interactiveGestureType = .Pinch(direction: .Close) 27 | case .Close: 28 | self.transitionAnimationType = .SystemCameraIris(hollowState: .Close) 29 | self.reverseAnimationType = .SystemCameraIris(hollowState: .Open) 30 | self.interactiveGestureType = .Pinch(direction: .Open) 31 | case .None: 32 | self.transitionAnimationType = .SystemCameraIris(hollowState: .None) 33 | self.reverseAnimationType = .SystemCameraIris(hollowState: .None) 34 | self.interactiveGestureType = .Pinch(direction: .Close) 35 | } 36 | 37 | super.init() 38 | } 39 | } 40 | 41 | extension SystemCameraIrisAnimator: UIViewControllerAnimatedTransitioning { 42 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 43 | return retrieveTransitionDuration(transitionContext) 44 | } 45 | 46 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 47 | switch self.hollowState { 48 | case .Open: 49 | animateWithCATransition(transitionContext, type: SystemTransitionType.CameraIrisHollowOpen, subtype: nil) 50 | case .Close: 51 | animateWithCATransition(transitionContext, type: SystemTransitionType.CameraIrisHollowClose, subtype: nil) 52 | case .None: 53 | animateWithCATransition(transitionContext, type: SystemTransitionType.CameraIris, subtype: nil) 54 | 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /IBAnimatable/SystemFlipAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/25/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | /** 9 | System Flip Animator - To support Flip animation (Four flip directions supported: left, right, top, bottom) 10 | */ 11 | public class SystemFlipAnimator: NSObject, AnimatedTransitioning { 12 | // MARK: - AnimatorProtocol 13 | public var transitionAnimationType: TransitionAnimationType 14 | public var transitionDuration: Duration = defaultTransitionDuration 15 | public var reverseAnimationType: TransitionAnimationType? 16 | public var interactiveGestureType: InteractiveGestureType? 17 | 18 | // MARK: - private 19 | private var fromDirection: TransitionDirection 20 | 21 | public init(fromDirection: TransitionDirection, transitionDuration: Duration) { 22 | self.fromDirection = fromDirection 23 | self.transitionDuration = transitionDuration 24 | 25 | switch fromDirection { 26 | case .Right: 27 | self.transitionAnimationType = .SystemFlip(fromDirection: .Right) 28 | self.reverseAnimationType = .SystemFlip(fromDirection: .Left) 29 | self.interactiveGestureType = .Pan(fromDirection: .Left) 30 | case .Top: 31 | self.transitionAnimationType = .SystemFlip(fromDirection: .Top) 32 | self.reverseAnimationType = .SystemFlip(fromDirection: .Bottom) 33 | self.interactiveGestureType = .Pan(fromDirection: .Bottom) 34 | case .Bottom: 35 | self.transitionAnimationType = .SystemFlip(fromDirection: .Bottom) 36 | self.reverseAnimationType = .SystemFlip(fromDirection: .Top) 37 | self.interactiveGestureType = .Pan(fromDirection: .Top) 38 | default: 39 | self.transitionAnimationType = .SystemFlip(fromDirection: .Left) 40 | self.reverseAnimationType = .SystemFlip(fromDirection: .Right) 41 | self.interactiveGestureType = .Pan(fromDirection: .Right) 42 | } 43 | 44 | super.init() 45 | } 46 | } 47 | 48 | extension SystemFlipAnimator: UIViewControllerAnimatedTransitioning { 49 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 50 | return retrieveTransitionDuration(transitionContext) 51 | } 52 | 53 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 54 | animateWithCATransition(transitionContext, type: SystemTransitionType.Flip, subtype: fromDirection.CATransitionSubtype) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/14/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableViewController: UIViewController, ViewControllerDesignable, StatusBarDesignable, RootWindowDesignable, TransitionAnimatable { 9 | // MARK: - ViewControllerDesignable 10 | @IBInspectable public var hideNavigationBar: Bool = false 11 | 12 | // MARK: - StatusBarDesignable 13 | @IBInspectable public var lightStatusBar: Bool = false 14 | 15 | // MARK: - RootWindowDesignable 16 | @IBInspectable public var rootWindowBackgroundColor: UIColor? 17 | 18 | // MARK: - TransitionAnimatable 19 | @IBInspectable public var transitionAnimationType: String? 20 | @IBInspectable public var transitionDuration: Double = .NaN 21 | @IBInspectable public var interactiveGestureType: String? 22 | 23 | // MARK: - Lifecylce 24 | public override func viewWillAppear(animated: Bool) { 25 | super.viewWillAppear(animated) 26 | confingHideNavigationBar() 27 | configRootWindowBackgroundColor() 28 | } 29 | 30 | public override func viewWillDisappear(animated: Bool) { 31 | super.viewWillDisappear(animated) 32 | resetHideNavigationBar() 33 | } 34 | 35 | public override func preferredStatusBarStyle() -> UIStatusBarStyle { 36 | if lightStatusBar { 37 | return .LightContent 38 | } 39 | return .Default 40 | } 41 | 42 | public override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 43 | super.prepareForSegue(segue, sender: sender) 44 | 45 | // Configure custom transition animation 46 | guard let transitionAnimationType = transitionAnimationType, animationType = TransitionAnimationType.fromString(transitionAnimationType) else { 47 | super.prepareForSegue(segue, sender: sender) 48 | return 49 | } 50 | 51 | let toViewController = segue.destinationViewController 52 | // If interactiveGestureType has been set 53 | if let interactiveGestureType = interactiveGestureType, interactiveGestureTypeValue = InteractiveGestureType.fromString(interactiveGestureType) { 54 | toViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(animationType, transitionDuration: transitionDuration, interactiveGestureType: interactiveGestureTypeValue) 55 | } else { 56 | toViewController.transitioningDelegate = PresenterManager.sharedManager().retrievePresenter(animationType, transitionDuration: transitionDuration) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableTextView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/19/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableTextView: UITextView, CornerDesignable, FillDesignable, BorderDesignable, Animatable { 9 | 10 | // MARK: - CornerDesignable 11 | @IBInspectable public var cornerRadius: CGFloat = CGFloat.NaN { 12 | didSet { 13 | configCornerRadius() 14 | } 15 | } 16 | 17 | // MARK: - FillDesignable 18 | @IBInspectable public var fillColor: UIColor? { 19 | didSet { 20 | configFillColor() 21 | } 22 | } 23 | 24 | @IBInspectable public var predefinedColor: String? { 25 | didSet { 26 | configFillColor() 27 | } 28 | } 29 | 30 | @IBInspectable public var opacity: CGFloat = CGFloat.NaN { 31 | didSet { 32 | configOpacity() 33 | } 34 | } 35 | 36 | // MARK: - BorderDesignable 37 | @IBInspectable public var borderColor: UIColor? { 38 | didSet { 39 | configBorder() 40 | } 41 | } 42 | 43 | @IBInspectable public var borderWidth: CGFloat = CGFloat.NaN { 44 | didSet { 45 | configBorder() 46 | } 47 | } 48 | 49 | @IBInspectable public var borderSide: String? { 50 | didSet { 51 | configBorder() 52 | } 53 | } 54 | 55 | // MARK: - Animatable 56 | @IBInspectable public var animationType: String? 57 | @IBInspectable public var autoRun: Bool = true 58 | @IBInspectable public var duration: Double = Double.NaN 59 | @IBInspectable public var delay: Double = Double.NaN 60 | @IBInspectable public var damping: CGFloat = CGFloat.NaN 61 | @IBInspectable public var velocity: CGFloat = CGFloat.NaN 62 | @IBInspectable public var force: CGFloat = CGFloat.NaN 63 | @IBInspectable public var repeatCount: Float = Float.NaN 64 | @IBInspectable public var x: CGFloat = CGFloat.NaN 65 | @IBInspectable public var y: CGFloat = CGFloat.NaN 66 | 67 | // MARK: - Lifecycle 68 | public override func prepareForInterfaceBuilder() { 69 | super.prepareForInterfaceBuilder() 70 | configInspectableProperties() 71 | } 72 | 73 | public override func awakeFromNib() { 74 | super.awakeFromNib() 75 | configInspectableProperties() 76 | } 77 | 78 | public override func layoutSubviews() { 79 | super.layoutSubviews() 80 | configAfterLayoutSubviews() 81 | autoRunAnimation() 82 | } 83 | 84 | // MARK: - Private 85 | private func configInspectableProperties() { 86 | configAnimatableProperties() 87 | } 88 | 89 | private func configAfterLayoutSubviews() { 90 | configBorder() 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /IBAnimatable.playground/Pages/Animation Properties.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | //: ## Animation Properties 4 | 5 | import UIKit 6 | import XCPlayground 7 | import IBAnimatable 8 | 9 | //: Constants 10 | let iPhoneWidth = 375 11 | let iPhoneHeight = 667 12 | let animatableViewWidth = 100 13 | let animatableViewX = (iPhoneWidth - animatableViewWidth) / 2 14 | let animatableViewY = (iPhoneHeight - animatableViewWidth) / 2 15 | 16 | //: Set up the iPhone View 17 | let iPhoneView = UIView(frame: CGRect(x: 0, y: 0, width: iPhoneWidth, height: iPhoneHeight)) 18 | iPhoneView.backgroundColor = .whiteColor() 19 | XCPlaygroundPage.currentPage.liveView = iPhoneView 20 | 21 | //: Set up the animatable View 22 | let view = AnimatableView(frame: CGRect(x: animatableViewX, y: animatableViewY, width: animatableViewWidth, height: animatableViewWidth)) 23 | view.configAnimatableProperties() 24 | iPhoneView.addSubview(view) 25 | 26 | view.fillColor = UIColor(red: 0xba/0xff, green: 0x77/0xff, blue: 1, alpha: 1) 27 | view.maskType = String(MaskType.Circle) 28 | 29 | //: animationType: all supported predefined animations can be found in `enum AnimationType` 30 | view.animationType = String(AnimationType.SqueezeInLeft) 31 | 32 | //: duration: used to specify the duration of animation. Default value is 0.7 33 | view.duration = 0.8 34 | 35 | //: delay: used to delay the animation in seconds. Default value is 0 36 | view.delay = 0.5 37 | 38 | //: damping: used in UIView Spring animation (0 ~ 1). To smoothly decelerate the animation without oscillation, use a value of 1. Employ a damping ratio closer to zero to increase oscillation. Default is 0.7. Notice: FadeOutIn, FadeInOut, Shake, Pop, Morph, Squeeze, Flash, Wobble and Swing animations do not use damping. 39 | view.damping = 0.5 40 | 41 | //: velocity: used in UIView Spring animation. A value of 1 corresponds to the total animation distance traversed in one second. For example, if the total animation distance is 200 points and you want the start of the animation to match a view velocity of 100 pt/s, use a value of 0.5. Default is 0.7. Notice: FadeOutIn, FadeInOut, Shake, Pop, Morph, Squeeze, Flash, Wobble and Swing animations do not use damping. 42 | view.velocity = 2 43 | 44 | //: force: used to apply force to the animation. The number is higher, the animation property has more changes. eg. for Pop animation, higher force causes the view poping bigger. Default is 1 45 | view.force = 1 46 | 47 | //: repeatCount: used to sepecify the count to repeat the animation. Can noly used in Shake, Pop, Morph, Squeeze, Flash, Wobble, Swing and Rotate animations 48 | view.repeatCount = 5 49 | 50 | view.animate() 51 | 52 | //: [Next](@next) 53 | -------------------------------------------------------------------------------- /IBAnimatable.playground/Pages/Predefined Animations.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: ## Predefined Animations 2 | 3 | import UIKit 4 | import XCPlayground 5 | import IBAnimatable 6 | 7 | //: Constants 8 | let iPhoneWidth = 375 9 | let iPhoneHeight = 667 10 | let animatableViewWidth = 100 11 | let animatableViewX = (iPhoneWidth - animatableViewWidth) / 2 12 | let animatableViewY = (iPhoneHeight - animatableViewWidth) / 2 13 | 14 | //: Set up the iPhone View 15 | let iPhoneView = UIView(frame: CGRect(x: 0, y: 0, width: iPhoneWidth, height: iPhoneHeight)) 16 | iPhoneView.backgroundColor = .whiteColor() 17 | XCPlaygroundPage.currentPage.liveView = iPhoneView 18 | 19 | //: Set up the animatable View 20 | let view = AnimatableView(frame: CGRect(x: animatableViewX, y: animatableViewY, width: animatableViewWidth, height: animatableViewWidth)) 21 | view.configAnimatableProperties() 22 | iPhoneView.addSubview(view) 23 | 24 | view.fillColor = UIColor(red: 0xba/0xff, green: 0x77/0xff, blue: 1, alpha: 1) 25 | view.borderWidth = 2 26 | view.borderColor = UIColor.purpleColor() 27 | view.maskType = String(MaskType.Circle) 28 | 29 | // For moveTo or moveBy animation 30 | view.x = -100 31 | view.y = 200 32 | 33 | //: Animations, all supported predefined animations can be found in `enum AnimationType` 34 | 35 | // Uncomment one line to play the animation 36 | 37 | //view.moveX() 38 | //view.moveY() 39 | //view.moveXY() 40 | //view.slideInLeft() 41 | //view.slideInRight() 42 | //view.slideInDown() 43 | //view.slideInUp() 44 | //view.slideOutLeft() 45 | //view.slideOutRight() 46 | //view.slideOutDown() 47 | //view.slideOutUp() 48 | //view.squeezeInLeft() 49 | //view.squeezeInRight() 50 | //view.squeezeInDown() 51 | //view.squeezeInUp() 52 | //view.squeezeOutLeft() 53 | //view.squeezeOutRight() 54 | //view.squeezeOutDown() 55 | //view.squeezeOutUp() 56 | //view.fadeIn() 57 | //view.fadeOut() 58 | //view.fadeOutIn() 59 | //view.fadeInOut() 60 | //view.fadeInLeft() 61 | //view.fadeInRight() 62 | //view.fadeInDown() 63 | //view.fadeInUp() 64 | //view.fadeOutLeft() 65 | //view.fadeOutRight() 66 | //view.fadeOutDown() 67 | //view.fadeOutUp() 68 | //view.squeezeFadeInLeft() 69 | //view.squeezeFadeInRight() 70 | //view.squeezeFadeInDown() 71 | //view.squeezeFadeInUp() 72 | //view.squeezeFadeOutLeft() 73 | //view.squeezeFadeOutRight() 74 | //view.squeezeFadeOutDown() 75 | //view.squeezeFadeOutUp() 76 | //view.zoomIn() 77 | //view.zoomOut() 78 | //view.shake() 79 | //view.pop() 80 | //view.flipX() 81 | //view.flipY() 82 | //view.morph() 83 | //view.squeeze() 84 | //view.flash() 85 | //view.wobble() 86 | //view.swing() 87 | //view.rotate() 88 | //view.rotate(clockwise: false) 89 | //view.moveTo() 90 | view.moveBy() 91 | 92 | //: [Next](@next) 93 | -------------------------------------------------------------------------------- /IBAnimatable/InteractiveGestureType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 3/3/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | /** 9 | The interactive gesture type 10 | */ 11 | public enum InteractiveGestureType { 12 | case Default // Will use the default interactive gesture type from `AnimatedTransitioning` 13 | case Pan(fromDirection: GestureDirection) 14 | case ScreenEdgePan(fromDirection: GestureDirection) 15 | case Pinch(direction: GestureDirection) 16 | 17 | var stringValue: String { 18 | return String(self) 19 | } 20 | 21 | public static func fromString(interactiveGestureType: String) -> InteractiveGestureType? { 22 | if interactiveGestureType.hasPrefix("Default") { 23 | return .Default 24 | } else if interactiveGestureType.hasPrefix("Pan") || interactiveGestureType.hasPrefix("ScreenEdgePan") || 25 | interactiveGestureType.hasPrefix("Pinch") { 26 | return fromStringWithDirection(interactiveGestureType) 27 | } 28 | return nil 29 | } 30 | 31 | // Return the `String` without qualification 32 | public func toString() -> String { 33 | let namespace = "IBAnimatable." + String(GestureDirection) + "." 34 | return String(self).stringByReplacingOccurrencesOfString(namespace, withString: "") 35 | } 36 | } 37 | 38 | // MARK: - InteractiveGestureType from string 39 | 40 | private extension InteractiveGestureType { 41 | static func cleanInteractiveGestureType(interactiveGestureType: String) -> String { 42 | let range = interactiveGestureType.rangeOfString("(") 43 | let interactiveGestureType = interactiveGestureType.stringByReplacingOccurrencesOfString(" ", withString: "") 44 | .lowercaseString 45 | .substringFromIndex(range?.startIndex ?? interactiveGestureType.endIndex) 46 | .stringByReplacingOccurrencesOfString("(", withString: "") 47 | .stringByReplacingOccurrencesOfString(")", withString: "") 48 | .capitalizedString 49 | return interactiveGestureType 50 | } 51 | 52 | static func fromStringWithDirection(interactiveGestureType: String) -> InteractiveGestureType? { 53 | let gestureDirectionString = cleanInteractiveGestureType(interactiveGestureType) 54 | 55 | guard let direction = GestureDirection(rawValue: gestureDirectionString) else { 56 | return nil 57 | } 58 | 59 | if interactiveGestureType.hasPrefix("Pan") { 60 | return .Pan(fromDirection: direction) 61 | } else if interactiveGestureType.hasPrefix("ScreenEdgePan") { 62 | return .ScreenEdgePan(fromDirection: direction) 63 | } else if interactiveGestureType.hasPrefix("Pinch") { 64 | return .Pinch(direction: direction) 65 | } 66 | 67 | return nil 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableTableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/15/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableTableView: UITableView, FillDesignable, BorderDesignable, GradientDesignable, Animatable { 9 | 10 | // MARK: - FillDesignable 11 | @IBInspectable public var fillColor: UIColor? { 12 | didSet { 13 | configFillColor() 14 | } 15 | } 16 | 17 | @IBInspectable public var predefinedColor: String? { 18 | didSet { 19 | configFillColor() 20 | } 21 | } 22 | 23 | @IBInspectable public var opacity: CGFloat = CGFloat.NaN { 24 | didSet { 25 | configOpacity() 26 | } 27 | } 28 | 29 | // MARK: - BorderDesignable 30 | @IBInspectable public var borderColor: UIColor? { 31 | didSet { 32 | configBorder() 33 | } 34 | } 35 | 36 | @IBInspectable public var borderWidth: CGFloat = CGFloat.NaN { 37 | didSet { 38 | configBorder() 39 | } 40 | } 41 | 42 | @IBInspectable public var borderSide: String? { 43 | didSet { 44 | configBorder() 45 | } 46 | } 47 | 48 | // MARK: - GradientDesignable 49 | @IBInspectable public var startColor: UIColor? 50 | @IBInspectable public var endColor: UIColor? 51 | @IBInspectable public var predefinedGradient: String? 52 | @IBInspectable public var startPoint: String? 53 | 54 | // MARK: - Animatable 55 | @IBInspectable public var animationType: String? 56 | @IBInspectable public var autoRun: Bool = true 57 | @IBInspectable public var duration: Double = Double.NaN 58 | @IBInspectable public var delay: Double = Double.NaN 59 | @IBInspectable public var damping: CGFloat = CGFloat.NaN 60 | @IBInspectable public var velocity: CGFloat = CGFloat.NaN 61 | @IBInspectable public var force: CGFloat = CGFloat.NaN 62 | @IBInspectable public var repeatCount: Float = Float.NaN 63 | @IBInspectable public var x: CGFloat = CGFloat.NaN 64 | @IBInspectable public var y: CGFloat = CGFloat.NaN 65 | 66 | // MARK: - Lifecycle 67 | public override func prepareForInterfaceBuilder() { 68 | super.prepareForInterfaceBuilder() 69 | configInspectableProperties() 70 | } 71 | 72 | public override func awakeFromNib() { 73 | super.awakeFromNib() 74 | configInspectableProperties() 75 | } 76 | 77 | public override func layoutSubviews() { 78 | super.layoutSubviews() 79 | autoRunAnimation() 80 | configAfterLayoutSubviews() 81 | } 82 | 83 | // MARK: - Private 84 | private func configInspectableProperties() { 85 | configAnimatableProperties() 86 | configOpacity() 87 | 88 | } 89 | 90 | private func configAfterLayoutSubviews() { 91 | configBorder() 92 | configGradient() 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /IBAnimatable/FadeAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/27/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class FadeAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? = .Pan(fromDirection: .Horizontal) 14 | 15 | // MARK: - private 16 | private var direction: TransitionDirection 17 | 18 | public init(direction: TransitionDirection, transitionDuration: Duration) { 19 | self.direction = direction 20 | self.transitionDuration = transitionDuration 21 | 22 | switch direction { 23 | case .In: 24 | self.transitionAnimationType = .Fade(direction: .In) 25 | self.reverseAnimationType = .Fade(direction: .Out) 26 | case .Out: 27 | self.transitionAnimationType = .Fade(direction: .Out) 28 | self.reverseAnimationType = .Fade(direction: .In) 29 | default: 30 | self.transitionAnimationType = .Fade(direction: .Cross) 31 | self.reverseAnimationType = .Fade(direction: .Cross) 32 | } 33 | 34 | super.init() 35 | } 36 | } 37 | 38 | extension FadeAnimator: UIViewControllerAnimatedTransitioning { 39 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 40 | return retrieveTransitionDuration(transitionContext) 41 | } 42 | 43 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 44 | let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext) 45 | guard let fromView = tempfromView, toView = tempToView, containerView = tempContainerView else { 46 | transitionContext.completeTransition(true) 47 | return 48 | } 49 | 50 | switch direction { 51 | case .In: 52 | toView.alpha = 0 53 | containerView.addSubview(toView) 54 | case .Out: 55 | containerView.insertSubview(toView, belowSubview: fromView) 56 | default: 57 | toView.alpha = 0 58 | containerView.addSubview(toView) 59 | } 60 | 61 | UIView.animateWithDuration(transitionDuration(transitionContext), 62 | animations: { 63 | switch self.direction { 64 | case .In: 65 | toView.alpha = 1 66 | case .Out: 67 | fromView.alpha = 0 68 | default: 69 | fromView.alpha = 0 70 | toView.alpha = 1 71 | } 72 | }, 73 | completion: { _ in 74 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) 75 | }) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/20/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableLabel: UILabel, CornerDesignable, FillDesignable, Animatable, RotationDesignable, BorderDesignable { 9 | 10 | // MARK: - CornerDesignable 11 | @IBInspectable public var cornerRadius: CGFloat = CGFloat.NaN { 12 | didSet { 13 | configCornerRadius() 14 | } 15 | } 16 | 17 | // MARK: - FillDesignable 18 | @IBInspectable public var fillColor: UIColor? { 19 | didSet { 20 | configFillColor() 21 | } 22 | } 23 | 24 | @IBInspectable public var predefinedColor: String? { 25 | didSet { 26 | configFillColor() 27 | } 28 | } 29 | 30 | @IBInspectable public var opacity: CGFloat = CGFloat.NaN { 31 | didSet { 32 | configOpacity() 33 | } 34 | } 35 | 36 | // MARK: - BorderDesignable 37 | @IBInspectable public var borderColor: UIColor? { 38 | didSet { 39 | configBorder() 40 | } 41 | } 42 | 43 | @IBInspectable public var borderWidth: CGFloat = CGFloat.NaN { 44 | didSet { 45 | configBorder() 46 | } 47 | } 48 | 49 | @IBInspectable public var borderSide: String? { 50 | didSet { 51 | configBorder() 52 | } 53 | } 54 | 55 | // MARK: - Animatable 56 | @IBInspectable public var animationType: String? 57 | @IBInspectable public var autoRun: Bool = true 58 | @IBInspectable public var duration: Double = Double.NaN 59 | @IBInspectable public var delay: Double = Double.NaN 60 | @IBInspectable public var damping: CGFloat = CGFloat.NaN 61 | @IBInspectable public var velocity: CGFloat = CGFloat.NaN 62 | @IBInspectable public var force: CGFloat = CGFloat.NaN 63 | @IBInspectable public var repeatCount: Float = Float.NaN 64 | @IBInspectable public var x: CGFloat = CGFloat.NaN 65 | @IBInspectable public var y: CGFloat = CGFloat.NaN 66 | 67 | // MARK: - RotationDesignable 68 | @IBInspectable public var rotate: CGFloat = CGFloat.NaN { 69 | didSet { 70 | configRotate() 71 | } 72 | } 73 | 74 | // MARK: - Lifecycle 75 | public override func prepareForInterfaceBuilder() { 76 | super.prepareForInterfaceBuilder() 77 | configInspectableProperties() 78 | } 79 | 80 | public override func awakeFromNib() { 81 | super.awakeFromNib() 82 | configInspectableProperties() 83 | } 84 | 85 | public override func layoutSubviews() { 86 | super.layoutSubviews() 87 | configAfterLayoutSubviews() 88 | autoRunAnimation() 89 | } 90 | 91 | // MARK: - Private 92 | private func configInspectableProperties() { 93 | configAnimatableProperties() 94 | configBorder() 95 | } 96 | 97 | private func configAfterLayoutSubviews() { 98 | configBorder() 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/16/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableTableViewCell: UITableViewCell, FillDesignable, BorderDesignable, TableViewCellDesignable, GradientDesignable, Animatable { 9 | 10 | // MARK: - FillDesignable 11 | @IBInspectable public var fillColor: UIColor? { 12 | didSet { 13 | configFillColor() 14 | } 15 | } 16 | 17 | @IBInspectable public var predefinedColor: String? { 18 | didSet { 19 | configFillColor() 20 | } 21 | } 22 | 23 | @IBInspectable public var opacity: CGFloat = CGFloat.NaN { 24 | didSet { 25 | configOpacity() 26 | } 27 | } 28 | 29 | // MARK: - BorderDesignable 30 | @IBInspectable public var borderColor: UIColor? { 31 | didSet { 32 | configBorder() 33 | } 34 | } 35 | 36 | @IBInspectable public var borderWidth: CGFloat = CGFloat.NaN { 37 | didSet { 38 | configBorder() 39 | } 40 | } 41 | 42 | @IBInspectable public var borderSide: String? { 43 | didSet { 44 | configBorder() 45 | } 46 | } 47 | 48 | // MARK: - TableViewCellDesignable 49 | @IBInspectable public var removeSeparatorMargins: Bool = false 50 | 51 | // MARK: - GradientDesignable 52 | @IBInspectable public var startColor: UIColor? 53 | @IBInspectable public var endColor: UIColor? 54 | @IBInspectable public var predefinedGradient: String? 55 | @IBInspectable public var startPoint: String? 56 | 57 | // MARK: - Animatable 58 | @IBInspectable public var animationType: String? 59 | @IBInspectable public var autoRun: Bool = true 60 | @IBInspectable public var duration: Double = Double.NaN 61 | @IBInspectable public var delay: Double = Double.NaN 62 | @IBInspectable public var damping: CGFloat = CGFloat.NaN 63 | @IBInspectable public var velocity: CGFloat = CGFloat.NaN 64 | @IBInspectable public var force: CGFloat = CGFloat.NaN 65 | @IBInspectable public var repeatCount: Float = Float.NaN 66 | @IBInspectable public var x: CGFloat = CGFloat.NaN 67 | @IBInspectable public var y: CGFloat = CGFloat.NaN 68 | 69 | // MARK: - Lifecycle 70 | public override func prepareForInterfaceBuilder() { 71 | super.prepareForInterfaceBuilder() 72 | configInspectableProperties() 73 | } 74 | 75 | public override func awakeFromNib() { 76 | super.awakeFromNib() 77 | configInspectableProperties() 78 | } 79 | 80 | public override func layoutSubviews() { 81 | super.layoutSubviews() 82 | configAfterLayoutSubviews() 83 | autoRunAnimation() 84 | } 85 | 86 | // MARK: - Private 87 | private func configInspectableProperties() { 88 | configAnimatableProperties() 89 | configOpacity() 90 | configSeparatorMargins() 91 | } 92 | 93 | private func configAfterLayoutSubviews() { 94 | configBorder() 95 | configGradient() 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatedTransitioning.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/24/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | /** 8 | AnimatedTransitioning is the protocol of all Animator subclasses 9 | */ 10 | public protocol AnimatedTransitioning: UIViewControllerAnimatedTransitioning { 11 | 12 | /** 13 | Value of `TransitionAnimationType` enum 14 | */ 15 | var transitionAnimationType: TransitionAnimationType { get set } 16 | 17 | /** 18 | Transition duration 19 | */ 20 | var transitionDuration: Duration { get set } 21 | 22 | /** 23 | Reverse animation type: used to specify the revers animation for pop or dismiss. 24 | */ 25 | var reverseAnimationType: TransitionAnimationType? { get set } 26 | 27 | /** 28 | Interactive gesture type: used to specify the gesture type to pop or dismiss. 29 | */ 30 | var interactiveGestureType: InteractiveGestureType? { get set } 31 | } 32 | 33 | public extension AnimatedTransitioning { 34 | public func retrieveViews(transitionContext: UIViewControllerContextTransitioning) -> (UIView?, UIView?, UIView?) { 35 | return (transitionContext.viewForKey(UITransitionContextFromViewKey), transitionContext.viewForKey(UITransitionContextToViewKey), transitionContext.containerView()) 36 | } 37 | 38 | public func retrieveViewControllers(transitionContext: UIViewControllerContextTransitioning) -> (UIViewController?, UIViewController?, UIView?) { 39 | return (transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey), transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey), transitionContext.containerView()) 40 | } 41 | 42 | public func retrieveTransitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 43 | if let transitionContext = transitionContext { 44 | return transitionContext.isAnimated() ? transitionDuration : 0 45 | } 46 | return 0 47 | } 48 | 49 | public func animateWithCATransition(transitionContext: UIViewControllerContextTransitioning, type: SystemTransitionType, subtype: String?) { 50 | let (_, tempToView, tempContainerView) = retrieveViews(transitionContext) 51 | guard let toView = tempToView, containerView = tempContainerView else { 52 | transitionContext.completeTransition(true) 53 | return 54 | } 55 | 56 | containerView.addSubview(toView) 57 | CALayer.animate({ 58 | let transition = CATransition() 59 | transition.type = type.rawValue 60 | if let subtype = subtype { 61 | transition.subtype = subtype 62 | } 63 | transition.duration = self.transitionDuration(transitionContext) 64 | // Use `EaseOutQubic` for system built-in transition animations. Thanks to @lexrus 65 | transition.timingFunction = CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) 66 | containerView.layer.addAnimation(transition, forKey: kCATransition) 67 | }, 68 | completion: { 69 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /IBAnimatable/ScreenEdgePanInteractiveAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 4/5/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class ScreenEdgePanInteractiveAnimator: InteractiveAnimator { 9 | 10 | override func createGestureRecognizer() -> UIGestureRecognizer { 11 | let gestureRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handleGesture(_:))) 12 | switch interactiveGestureType { 13 | case let .ScreenEdgePan(direction): 14 | switch direction { 15 | case .Left: 16 | gestureRecognizer.edges = .Left 17 | case .Right: 18 | gestureRecognizer.edges = .Right 19 | case .Horizontal: 20 | gestureRecognizer.edges = [.Left, .Right] 21 | case .Top: 22 | gestureRecognizer.edges = .Top 23 | case .Bottom: 24 | gestureRecognizer.edges = .Bottom 25 | case .Vertical: 26 | gestureRecognizer.edges = [.Top, .Bottom] 27 | default: 28 | break 29 | } 30 | default: 31 | break 32 | } 33 | return gestureRecognizer 34 | } 35 | 36 | override func calculateProgress(gestureRecognizer: UIGestureRecognizer) -> (progress: CGFloat, shouldFinishInteractiveTransition: Bool) { 37 | guard let gestureRecognizer = gestureRecognizer as? UIScreenEdgePanGestureRecognizer, 38 | superview = gestureRecognizer.view?.superview else { 39 | return (0, false) 40 | } 41 | let translation = gestureRecognizer.translationInView(superview) 42 | let velocity = gestureRecognizer.velocityInView(superview) 43 | 44 | var progress: CGFloat 45 | let distance: CGFloat 46 | let speed: CGFloat 47 | switch interactiveGestureType { 48 | case let .ScreenEdgePan(direction): 49 | switch direction { 50 | case .Horizontal: 51 | distance = superview.frame.width 52 | progress = abs(translation.x / distance) 53 | speed = abs(velocity.x) 54 | case .Left: 55 | distance = superview.frame.width 56 | progress = translation.x / distance 57 | speed = velocity.x 58 | case .Right: 59 | distance = superview.frame.width 60 | progress = -(translation.x / distance) 61 | speed = -velocity.x 62 | case .Vertical: 63 | distance = superview.frame.height 64 | progress = abs(translation.y / distance) 65 | speed = abs(velocity.y) 66 | case .Top: 67 | distance = superview.frame.height 68 | progress = translation.y / distance 69 | speed = velocity.y 70 | case .Bottom: 71 | distance = superview.frame.height 72 | progress = -translation.y / distance 73 | speed = -velocity.y 74 | default: 75 | return (0, false) 76 | } 77 | default: 78 | return (0, false) 79 | } 80 | 81 | progress = min(max(progress, 0), 0.99) 82 | 83 | // Finish the transition when pass the threathold 84 | let shouldFinishInteractiveTransition = progress > 0.5 || speed > 1000 85 | 86 | return (progress, shouldFinishInteractiveTransition) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /IBAnimatableApp/ContainerTransitionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 07/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | import IBAnimatable 8 | 9 | class ContainerTransitionViewController: UIViewController, UITabBarDelegate { 10 | 11 | // MARK: Properties 12 | 13 | @IBOutlet var tabBar: UITabBar! 14 | @IBOutlet var containerView: UIView! 15 | 16 | private var viewControllers = [AnimatableViewController]() 17 | private var currentViewController: AnimatableViewController? 18 | 19 | // MARK: Life cycle 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | createChildViewControllers() 24 | tabBar.selectedItem = tabBar.items?.first 25 | } 26 | 27 | } 28 | 29 | // MARK: - ChildViewController 30 | 31 | private extension ContainerTransitionViewController { 32 | 33 | func createChildViewControllers() { 34 | var viewController = AnimatableViewController() 35 | viewController.view.backgroundColor = UIColor.blueColor() 36 | viewController.transitionAnimationType = "Explode" 37 | viewControllers.append(viewController) 38 | 39 | viewController = AnimatableViewController() 40 | viewController.view.backgroundColor = UIColor.greenColor() 41 | viewController.transitionAnimationType = "Fold" 42 | viewControllers.append(viewController) 43 | 44 | viewController = AnimatableViewController() 45 | viewController.view.backgroundColor = UIColor.yellowColor() 46 | viewController.transitionAnimationType = "NatGeo" 47 | viewControllers.append(viewController) 48 | 49 | viewController = AnimatableViewController() 50 | viewController.view.backgroundColor = UIColor.redColor() 51 | viewController.transitionAnimationType = "Portal" 52 | viewControllers.append(viewController) 53 | 54 | cycleFromViewController(containerView, fromViewController: nil, toViewController: viewControllers[0]) 55 | 56 | } 57 | 58 | func cycleFromViewController(containerView: UIView, fromViewController: AnimatableViewController?, toViewController: AnimatableViewController) { 59 | guard let animationType = TransitionAnimationType.fromString(toViewController.transitionAnimationType ?? "") else { 60 | return 61 | } 62 | 63 | let transitionContext = ContainerTransition(animationType: animationType, 64 | container: containerView, 65 | parentViewController: self, 66 | fromViewController: fromViewController, 67 | toViewController: toViewController) { 68 | self.currentViewController = toViewController 69 | } 70 | transitionContext.animate() 71 | } 72 | 73 | } 74 | 75 | // MARK: - UITabBarDelegate 76 | 77 | extension ContainerTransitionViewController { 78 | 79 | func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) { 80 | let toViewController = viewControllers[item.tag] 81 | cycleFromViewController(containerView, fromViewController: currentViewController, toViewController: toViewController) 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /IBAnimatable/Navigator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/24/16. 3 | // Copyright (c) 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | /** 9 | Navigator for `UINavigationController` to support custom transition animation for Push and Pop 10 | */ 11 | public class Navigator: NSObject { 12 | var transitionAnimationType: TransitionAnimationType 13 | var transitionDuration: Duration = defaultTransitionDuration 14 | 15 | // animation controller 16 | private var animator: AnimatedTransitioning? 17 | // interaction controller 18 | private var interactiveAnimator: InteractiveAnimator? 19 | 20 | public init(transitionAnimationType: TransitionAnimationType, transitionDuration: Duration = defaultTransitionDuration, interactiveGestureType: InteractiveGestureType? = nil) { 21 | self.transitionAnimationType = transitionAnimationType 22 | self.transitionDuration = transitionDuration 23 | super.init() 24 | 25 | animator = AnimatorFactory.generateAnimator(transitionAnimationType, transitionDuration: transitionDuration) 26 | 27 | // If interactiveGestureType has been set 28 | if let interactiveGestureType = interactiveGestureType { 29 | // If configured as `.Default` then use the default interactive gesture type from the Animator 30 | switch interactiveGestureType { 31 | case .Default: 32 | if let interactiveGestureType = animator?.interactiveGestureType { 33 | interactiveAnimator = InteractiveAnimatorFactory.generateInteractiveAnimator(interactiveGestureType, transitionType: .NavigationTransition(.Pop)) 34 | } 35 | default: 36 | interactiveAnimator = InteractiveAnimatorFactory.generateInteractiveAnimator(interactiveGestureType, transitionType: .NavigationTransition(.Pop)) 37 | } 38 | } 39 | } 40 | } 41 | 42 | extension Navigator: UINavigationControllerDelegate { 43 | // MARK: - animation controller 44 | public func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 45 | interactiveAnimator?.connectGestureRecognizer(toVC) 46 | 47 | if operation == .Push { 48 | animator?.transitionDuration = transitionDuration 49 | return animator 50 | } else if operation == .Pop { 51 | // Use the reverse animation 52 | if let reverseTransitionAnimationType = animator?.reverseAnimationType { 53 | return AnimatorFactory.generateAnimator(reverseTransitionAnimationType, transitionDuration: transitionDuration) 54 | } 55 | } 56 | return nil 57 | } 58 | 59 | // MARK: - interaction controller 60 | public func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 61 | if let interactiveAnimator = interactiveAnimator where interactiveAnimator.interacting { 62 | return interactiveAnimator 63 | } else { 64 | return nil 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 11/04/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableCollectionViewCell: UICollectionViewCell, CornerDesignable, FillDesignable, BorderDesignable, TableViewCellDesignable, GradientDesignable, Animatable { 9 | 10 | // MARK: - CornerDesignable 11 | @IBInspectable public var cornerRadius: CGFloat = CGFloat.NaN { 12 | didSet { 13 | configCornerRadius() 14 | } 15 | } 16 | 17 | // MARK: - FillDesignable 18 | @IBInspectable public var fillColor: UIColor? { 19 | didSet { 20 | configFillColor() 21 | } 22 | } 23 | 24 | @IBInspectable public var predefinedColor: String? { 25 | didSet { 26 | configFillColor() 27 | } 28 | } 29 | 30 | @IBInspectable public var opacity: CGFloat = CGFloat.NaN { 31 | didSet { 32 | configOpacity() 33 | } 34 | } 35 | 36 | // MARK: - BorderDesignable 37 | @IBInspectable public var borderColor: UIColor? { 38 | didSet { 39 | configBorder() 40 | } 41 | } 42 | 43 | @IBInspectable public var borderWidth: CGFloat = CGFloat.NaN { 44 | didSet { 45 | configBorder() 46 | } 47 | } 48 | 49 | @IBInspectable public var borderSide: String? { 50 | didSet { 51 | configBorder() 52 | } 53 | } 54 | 55 | // MARK: - TableViewCellDesignable 56 | @IBInspectable public var removeSeparatorMargins: Bool = false 57 | 58 | // MARK: - GradientDesignable 59 | @IBInspectable public var startColor: UIColor? 60 | @IBInspectable public var endColor: UIColor? 61 | @IBInspectable public var predefinedGradient: String? 62 | @IBInspectable public var startPoint: String? 63 | 64 | // MARK: - Animatable 65 | @IBInspectable public var animationType: String? 66 | @IBInspectable public var autoRun: Bool = true 67 | @IBInspectable public var duration: Double = Double.NaN 68 | @IBInspectable public var delay: Double = Double.NaN 69 | @IBInspectable public var damping: CGFloat = CGFloat.NaN 70 | @IBInspectable public var velocity: CGFloat = CGFloat.NaN 71 | @IBInspectable public var force: CGFloat = CGFloat.NaN 72 | @IBInspectable public var repeatCount: Float = Float.NaN 73 | @IBInspectable public var x: CGFloat = CGFloat.NaN 74 | @IBInspectable public var y: CGFloat = CGFloat.NaN 75 | 76 | // MARK: - Lifecycle 77 | public override func prepareForInterfaceBuilder() { 78 | super.prepareForInterfaceBuilder() 79 | configInspectableProperties() 80 | } 81 | 82 | public override func awakeFromNib() { 83 | super.awakeFromNib() 84 | configInspectableProperties() 85 | } 86 | 87 | public override func layoutSubviews() { 88 | super.layoutSubviews() 89 | configAfterLayoutSubviews() 90 | autoRunAnimation() 91 | } 92 | 93 | // MARK: - Private 94 | private func configInspectableProperties() { 95 | configAnimatableProperties() 96 | configOpacity() 97 | } 98 | 99 | private func configAfterLayoutSubviews() { 100 | configBorder() 101 | configGradient() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatorFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/24/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | /** 8 | Animator Factory 9 | */ 10 | public struct AnimatorFactory { 11 | public static func generateAnimator(transitionAnimationType: TransitionAnimationType) -> AnimatedTransitioning { 12 | return generateAnimator(transitionAnimationType, transitionDuration: defaultTransitionDuration) 13 | } 14 | 15 | public static func generateAnimator(transitionAnimationType: TransitionAnimationType, transitionDuration: Duration) -> AnimatedTransitioning { 16 | switch transitionAnimationType { 17 | case .SystemRotate: 18 | return SystemRotateAnimator(transitionDuration: transitionDuration) 19 | case .SystemSuckEffect: 20 | return SystemSuckEffectAnimator(transitionDuration: transitionDuration) 21 | case .SystemRippleEffect: 22 | return SystemRippleEffectAnimator(transitionDuration: transitionDuration) 23 | case let .Explode(params): 24 | return ExplodeAnimator(params: params, transitionDuration: transitionDuration) 25 | case let .Fade(direction): 26 | return FadeAnimator(direction: direction, transitionDuration: transitionDuration) 27 | case let .Fold(direction, params): 28 | return FoldAnimator(fromDirection: direction, params: params, transitionDuration: transitionDuration) 29 | case let .Portal(direction, params): 30 | return PortalAnimator(fromDirection: direction, params: params, transitionDuration: transitionDuration) 31 | case let .NatGeo(direction): 32 | return NatGeoAnimator(fromDirection: direction, transitionDuration: transitionDuration) 33 | case let .Turn(direction): 34 | return TurnAnimator(fromDirection: direction, transitionDuration: transitionDuration) 35 | case let .Cards(direction): 36 | return CardsAnimator(fromDirection: direction, transitionDuration: transitionDuration) 37 | case let .Flip(direction): 38 | return FlipAnimator(fromDirection: direction, transitionDuration: transitionDuration) 39 | case let .Slide(direction, params): 40 | return SlideAnimator(fromDirection: direction, params: params, transitionDuration: transitionDuration) 41 | case let .SystemCube(direction): 42 | return SystemCubeAnimator(fromDirection: direction, transitionDuration: transitionDuration) 43 | case let .SystemFlip(direction): 44 | return SystemFlipAnimator(fromDirection: direction, transitionDuration: transitionDuration) 45 | case let .SystemMoveIn(direction): 46 | return SystemMoveInAnimator(fromDirection: direction, transitionDuration: transitionDuration) 47 | case let .SystemPush(direction): 48 | return SystemPushAnimator(fromDirection: direction, transitionDuration: transitionDuration) 49 | case let .SystemReveal(direction): 50 | return SystemRevealAnimator(fromDirection: direction, transitionDuration: transitionDuration) 51 | case let .SystemPage(type): 52 | return SystemPageAnimator(type: type, transitionDuration: transitionDuration) 53 | case let .SystemCameraIris(hollowState): 54 | return SystemCameraIrisAnimator(hollowState: hollowState, transitionDuration: transitionDuration) 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /IBAnimatableApp.xcodeproj/xcshareddata/xcschemes/IBAnimatable.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 | -------------------------------------------------------------------------------- /IBAnimatable/GradientType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 09/02/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | 8 | public enum GradientType: String { 9 | case SunnyDays 10 | case GreenBeach 11 | case IntuitivePurple 12 | case EmeraldWater 13 | case LemonTwist 14 | case Horizon 15 | case RoseWater 16 | case Frozen 17 | case MangoPulp 18 | case BloodyMary 19 | case Aubergine 20 | case AquaMarine 21 | case Sunrise 22 | case PurpleParadise 23 | case SeaWeed 24 | case Pinky 25 | case Cherry 26 | case Mojito 27 | case JuicyOrange 28 | case Mirage 29 | case SteelGray 30 | case Kashmir 31 | case ElectricViolet 32 | case VeniceBlue 33 | case BoraBora 34 | case Moss 35 | case ShroomHaze 36 | case Mystic 37 | case MidnightCity 38 | case SeaBlizz 39 | case Opa 40 | case Titanium 41 | case Mantle 42 | case Dracula 43 | case Peach 44 | case Moonrise 45 | case Clouds 46 | case Stellar 47 | case Bourbon 48 | case CalmDarya 49 | case Influenza 50 | case Shrimpy 51 | case Army 52 | case Miaka 53 | case PinotNoir 54 | case DayTripper 55 | case Namn 56 | case BlurryBeach 57 | case Vasily 58 | case ALostMemory 59 | case Petrichor 60 | case Jonquil 61 | case SiriusTamed 62 | case Kyoto 63 | case MistyMeadow 64 | case Aqualicious 65 | case Moor 66 | case Almost 67 | case ForeverLost 68 | case Winter 69 | case Autumn 70 | case Candy 71 | case Reef 72 | case TheStrain 73 | case DirtyFog 74 | case Earthly 75 | case Virgin 76 | case Ash 77 | case ShadowNight 78 | case Cherryblossoms 79 | case Parklife 80 | case DanceToForget 81 | case Starfall 82 | case RedMist 83 | case TealLove 84 | case NeonLife 85 | case ManofSteel 86 | case Amethyst 87 | case CheerUpEmoKid 88 | case Shore 89 | case FacebookMessenger 90 | case SoundCloud 91 | case Behongo 92 | case ServQuick 93 | case Friday 94 | case Martini 95 | case MetallicToad 96 | case BetweenTheClouds 97 | case CrazyOrangeI 98 | case Hersheys 99 | case TalkingToMiceElf 100 | case PurpleBliss 101 | case Predawn 102 | case EndlessRiver 103 | case PastelOrangeattheSun 104 | case Twitch 105 | case Instagram 106 | case Flickr 107 | case Vine 108 | case Turquoiseflow 109 | case Portrait 110 | case VirginAmerica 111 | case KokoCaramel 112 | case FreshTurboscent 113 | case Greentodark 114 | case Ukraine 115 | case Curiosityblue 116 | case DarkKnight 117 | case Piglet 118 | case Lizard 119 | case SagePersuasion 120 | case BetweenNightandDay 121 | case Timber 122 | case Passion 123 | case ClearSky 124 | case MasterCard 125 | case BackToEarth 126 | case DeepPurple 127 | case LittleLeaf 128 | case Netflix 129 | case LightOrange 130 | case GreenandBlue 131 | case Poncho 132 | case BacktotheFuture 133 | case Blush 134 | case Inbox 135 | case Purplin 136 | case PaleWood 137 | case Haikus 138 | case Pizelex 139 | case Joomla 140 | case Christmas 141 | case MinnesotaVikings 142 | case MiamiDolphins 143 | case Forest 144 | case Nighthawk 145 | case Superman 146 | case Suzy 147 | case DarkSkies 148 | } 149 | -------------------------------------------------------------------------------- /IBAnimatable/SideImageDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/8/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol SideImageDesignable { 9 | /** 10 | * The left image 11 | */ 12 | var leftImage: UIImage? { get set } 13 | 14 | /** 15 | * Left padding of the left image, default value is CGFloat.NaN 16 | */ 17 | var leftImageLeftPadding: CGFloat { get set } 18 | 19 | /** 20 | * Right padding of the left image, default value is CGFloat.NaN 21 | */ 22 | var leftImageRightPadding: CGFloat { get set } 23 | 24 | /** 25 | * Top padding of the left image, default value is CGFloat.NaN 26 | */ 27 | var leftImageTopPadding: CGFloat { get set } 28 | 29 | /** 30 | * The right image 31 | */ 32 | var rightImage: UIImage? { get set } 33 | 34 | /** 35 | * Left padding of the right image, default value is CGFloat.NaN 36 | */ 37 | var rightImageLeftPadding: CGFloat { get set } 38 | 39 | /** 40 | * Right padding of the right image, default value is CGFloat.NaN 41 | */ 42 | var rightImageRightPadding: CGFloat { get set } 43 | 44 | /** 45 | * Top padding of the right image, default value is CGFloat.NaN 46 | */ 47 | var rightImageTopPadding: CGFloat { get set } 48 | } 49 | 50 | public extension SideImageDesignable where Self: UITextField { 51 | 52 | public func configImages() { 53 | configLeftImage() 54 | configRightImage() 55 | } 56 | 57 | private func configLeftImage() { 58 | guard let wrappedLeftImage = leftImage else { 59 | return 60 | } 61 | 62 | let sideView = generateSideViewWithImage(wrappedLeftImage, leftPadding: leftImageLeftPadding, rightPadding: leftImageRightPadding, topPadding: leftImageTopPadding) 63 | leftViewMode = .Always 64 | leftView = sideView 65 | } 66 | 67 | private func configRightImage() { 68 | guard let wrappedRightImage = rightImage else { 69 | return 70 | } 71 | 72 | let sideView = generateSideViewWithImage(wrappedRightImage, leftPadding: rightImageLeftPadding, rightPadding: rightImageRightPadding, topPadding: rightImageTopPadding) 73 | rightViewMode = .Always 74 | rightView = sideView 75 | } 76 | 77 | private func generateSideViewWithImage(image: UIImage, leftPadding: CGFloat, rightPadding: CGFloat, topPadding: CGFloat) -> UIView { 78 | let imageView = UIImageView(image: image) 79 | 80 | // If not set, use 0 as default value 81 | var leftPaddingValue: CGFloat = 0.0 82 | if !leftPadding.isNaN { 83 | leftPaddingValue = leftPadding 84 | } 85 | 86 | // If not set, use 0 as default value 87 | var rightPaddingValue: CGFloat = 0.0 88 | if !rightPadding.isNaN { 89 | rightPaddingValue = rightPadding 90 | } 91 | 92 | // If does not specify `topPadding`, then center it in the middle 93 | if topPadding.isNaN { 94 | imageView.frame.origin = CGPoint(x: leftPaddingValue, y: (bounds.height - imageView.bounds.height) / 2) 95 | } else { 96 | imageView.frame.origin = CGPoint(x: leftPaddingValue, y: topPadding) 97 | } 98 | 99 | let padding = rightPaddingValue + imageView.bounds.size.width + leftPaddingValue 100 | let sideView = UIView(frame: CGRect(x: 0, y: 0, width: padding, height: bounds.height)) 101 | sideView.addSubview(imageView) 102 | return sideView 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /IBAnimatable/InteractiveAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 4/5/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | // Super abstract class for all interactive animator subclasses 9 | public class InteractiveAnimator: UIPercentDrivenInteractiveTransition { 10 | internal(set) public var interacting = false 11 | 12 | // transitionType: Used to deteminate pop or dismiss 13 | let transitionType: TransitionType 14 | // interactiveGestureType: Used to deteminate gesture type (direction) 15 | let interactiveGestureType: InteractiveGestureType 16 | // viewController: the viewController will connect to the gestureRecognizer 17 | weak var viewController: UIViewController? 18 | // gestureRecognizer: the gesture recognizer to handle gesture 19 | var gestureRecognizer: UIGestureRecognizer? 20 | 21 | init(interactiveGestureType: InteractiveGestureType, transitionType: TransitionType) { 22 | self.interactiveGestureType = interactiveGestureType 23 | self.transitionType = transitionType 24 | super.init() 25 | } 26 | 27 | deinit { 28 | if let gestureRecognizer = gestureRecognizer, view = viewController?.view { 29 | gestureRecognizer.removeTarget(self, action: #selector(handleGesture(_:))) 30 | view.removeGestureRecognizer(gestureRecognizer) 31 | } 32 | } 33 | 34 | func connectGestureRecognizer(viewController: UIViewController) { 35 | self.viewController = viewController 36 | let gestureRecognizerType = createGestureRecognizer() 37 | gestureRecognizer = gestureRecognizerType 38 | if let gestureRecognizer = gestureRecognizer { 39 | self.viewController?.view.addGestureRecognizer(gestureRecognizer) 40 | } 41 | } 42 | 43 | func handleGesture(gestureRecognizer: UIGestureRecognizer) { 44 | let (progress, shouldFinishInteractiveTransition) = calculateProgress(gestureRecognizer) 45 | 46 | switch gestureRecognizer.state { 47 | case .Began: 48 | guard shouldBeginProgress(gestureRecognizer) else { 49 | return 50 | } 51 | 52 | interacting = true 53 | switch transitionType { 54 | case .NavigationTransition(.Pop): 55 | viewController?.navigationController?.popViewControllerAnimated(true) 56 | case .PresentationTransition(.Dismissal): 57 | viewController?.dismissViewControllerAnimated(true, completion: nil) 58 | default: 59 | break 60 | } 61 | case .Changed: 62 | updateInteractiveTransition(progress) 63 | case .Cancelled, .Ended: 64 | interacting = false 65 | if shouldFinishInteractiveTransition { 66 | finishInteractiveTransition() 67 | } else { 68 | cancelInteractiveTransition() 69 | } 70 | default: 71 | // Something happened then cancel the transition. 72 | interacting = false 73 | cancelInteractiveTransition() 74 | break 75 | } 76 | } 77 | 78 | // Because Swift doesn't support pure virtual method, need to throw error 79 | func createGestureRecognizer() -> UIGestureRecognizer { 80 | preconditionFailure("This method must be overridden") 81 | } 82 | 83 | func shouldBeginProgress(gestureRecognizer: UIGestureRecognizer) -> Bool { 84 | // return true by default 85 | return true 86 | } 87 | 88 | func calculateProgress(gestureRecognizer: UIGestureRecognizer) -> (progress: CGFloat, shouldFinishInteractiveTransition: Bool) { 89 | preconditionFailure("This method must be overridden") 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /IBAnimatable/AnimatableButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 11/18/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | @IBDesignable public class AnimatableButton: UIButton, CornerDesignable, FillDesignable, BorderDesignable, ShadowDesignable, MaskDesignable, Animatable { 9 | 10 | // MARK: - CornerDesignable 11 | @IBInspectable public var cornerRadius: CGFloat = CGFloat.NaN { 12 | didSet { 13 | configCornerRadius() 14 | } 15 | } 16 | 17 | // MARK: - FillDesignable 18 | @IBInspectable public var fillColor: UIColor? { 19 | didSet { 20 | configFillColor() 21 | } 22 | } 23 | 24 | @IBInspectable public var predefinedColor: String? { 25 | didSet { 26 | configFillColor() 27 | } 28 | } 29 | 30 | @IBInspectable public var opacity: CGFloat = CGFloat.NaN { 31 | didSet { 32 | configOpacity() 33 | } 34 | } 35 | 36 | // MARK: - BorderDesignable 37 | @IBInspectable public var borderColor: UIColor? { 38 | didSet { 39 | configBorder() 40 | } 41 | } 42 | 43 | @IBInspectable public var borderWidth: CGFloat = CGFloat.NaN { 44 | didSet { 45 | configBorder() 46 | } 47 | } 48 | 49 | @IBInspectable public var borderSide: String? { 50 | didSet { 51 | configBorder() 52 | } 53 | } 54 | 55 | // MARK: - ShadowDesignable 56 | @IBInspectable public var shadowColor: UIColor? { 57 | didSet { 58 | configShadowColor() 59 | } 60 | } 61 | 62 | @IBInspectable public var shadowRadius: CGFloat = CGFloat.NaN { 63 | didSet { 64 | configShadowRadius() 65 | } 66 | } 67 | 68 | @IBInspectable public var shadowOpacity: CGFloat = CGFloat.NaN { 69 | didSet { 70 | configShadowOpacity() 71 | } 72 | } 73 | 74 | @IBInspectable public var shadowOffset: CGPoint = CGPoint(x: CGFloat.NaN, y: CGFloat.NaN) { 75 | didSet { 76 | configShadowOffset() 77 | } 78 | } 79 | 80 | // MARK: - MaskDesignable 81 | @IBInspectable public var maskType: String? { 82 | didSet { 83 | configMask() 84 | configBorder() 85 | } 86 | } 87 | 88 | // MARK: - Animatable 89 | @IBInspectable public var animationType: String? 90 | @IBInspectable public var autoRun: Bool = true 91 | @IBInspectable public var duration: Double = Double.NaN 92 | @IBInspectable public var delay: Double = Double.NaN 93 | @IBInspectable public var damping: CGFloat = CGFloat.NaN 94 | @IBInspectable public var velocity: CGFloat = CGFloat.NaN 95 | @IBInspectable public var force: CGFloat = CGFloat.NaN 96 | @IBInspectable public var repeatCount: Float = Float.NaN 97 | @IBInspectable public var x: CGFloat = CGFloat.NaN 98 | @IBInspectable public var y: CGFloat = CGFloat.NaN 99 | 100 | // MARK: - Lifecycle 101 | public override func prepareForInterfaceBuilder() { 102 | super.prepareForInterfaceBuilder() 103 | configInspectableProperties() 104 | } 105 | 106 | public override func awakeFromNib() { 107 | super.awakeFromNib() 108 | configInspectableProperties() 109 | } 110 | 111 | public override func layoutSubviews() { 112 | super.layoutSubviews() 113 | configAfterLayoutSubviews() 114 | autoRunAnimation() 115 | } 116 | 117 | // MARK: - Private 118 | private func configInspectableProperties() { 119 | configAnimatableProperties() 120 | } 121 | 122 | private func configAfterLayoutSubviews() { 123 | configMask() 124 | configBorder() 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /IBAnimatableApp/Animations.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /IBAnimatable/Presenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 2/24/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | /** 9 | Presenter for `UIViewController` to support custom transition animation for Present and Dismiss 10 | */ 11 | public class Presenter: NSObject { 12 | private var transitionAnimationType: TransitionAnimationType 13 | var transitionDuration: Duration { 14 | didSet { 15 | if oldValue != transitionDuration { 16 | updateTransitionDuration() 17 | } 18 | } 19 | } 20 | 21 | var interactiveGestureType: InteractiveGestureType? { 22 | // Update `interactiveAnimator` if needed 23 | didSet { 24 | if oldValue?.stringValue != interactiveGestureType?.stringValue { 25 | updateInteractiveAnimator() 26 | } 27 | } 28 | } 29 | 30 | // animation controller 31 | private var animator: AnimatedTransitioning? 32 | 33 | // interaction controller 34 | private var interactiveAnimator: InteractiveAnimator? 35 | 36 | public init(transitionAnimationType: TransitionAnimationType, transitionDuration: Duration = defaultTransitionDuration, interactiveGestureType: InteractiveGestureType? = nil) { 37 | self.transitionAnimationType = transitionAnimationType 38 | self.transitionDuration = transitionDuration 39 | super.init() 40 | 41 | updateTransitionDuration() 42 | 43 | animator = AnimatorFactory.generateAnimator(transitionAnimationType, transitionDuration: transitionDuration) 44 | 45 | self.interactiveGestureType = interactiveGestureType 46 | updateInteractiveAnimator() 47 | } 48 | 49 | // MARK: - Private 50 | private func updateTransitionDuration() { 51 | if transitionDuration.isNaN { 52 | transitionDuration = defaultTransitionDuration 53 | } 54 | } 55 | 56 | private func updateInteractiveAnimator() { 57 | // If interactiveGestureType has been set 58 | if let interactiveGestureType = interactiveGestureType { 59 | // If configured as `.Default` then use the default interactive gesture type from the Animator 60 | switch interactiveGestureType { 61 | case .Default: 62 | if let interactiveGestureType = animator?.interactiveGestureType { 63 | interactiveAnimator = InteractiveAnimatorFactory.generateInteractiveAnimator(interactiveGestureType, transitionType: .PresentationTransition(.Dismissal)) 64 | } 65 | default: 66 | interactiveAnimator = InteractiveAnimatorFactory.generateInteractiveAnimator(interactiveGestureType, transitionType: .PresentationTransition(.Dismissal)) 67 | } 68 | } else { 69 | interactiveAnimator = nil 70 | } 71 | } 72 | } 73 | 74 | extension Presenter: UIViewControllerTransitioningDelegate { 75 | // MARK: - animation controller 76 | public func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 77 | animator?.transitionDuration = transitionDuration 78 | interactiveAnimator?.connectGestureRecognizer(presented) 79 | return animator 80 | } 81 | 82 | public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 83 | // Use the reverse animation 84 | if let reverseTransitionAnimationType = animator?.reverseAnimationType { 85 | return AnimatorFactory.generateAnimator(reverseTransitionAnimationType, transitionDuration: transitionDuration) 86 | } 87 | return nil 88 | } 89 | 90 | // MARK: - interaction controller 91 | public func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 92 | if let interactiveAnimator = interactiveAnimator where interactiveAnimator.interacting { 93 | return interactiveAnimator 94 | } else { 95 | return nil 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /IBAnimatableApp/UserInterface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/swift,appcode,xcode,osx 3 | 4 | ### Swift ### 5 | # Xcode 6 | # 7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 8 | 9 | ## Build generated 10 | build/ 11 | DerivedData 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata 23 | 24 | ## Other 25 | *.xccheckout 26 | *.moved-aside 27 | *.xcuserstate 28 | *.xcscmblueprint 29 | 30 | ## Obj-C/Swift specific 31 | *.hmap 32 | *.ipa 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | 65 | 66 | ### AppCode ### 67 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 68 | 69 | *.iml 70 | 71 | ### Temporary files 72 | *.orig 73 | 74 | ## Directory-based project format: 75 | .idea/ 76 | # if you remove the above rule, at least ignore the following: 77 | 78 | # User-specific stuff: 79 | # .idea/workspace.xml 80 | # .idea/tasks.xml 81 | # .idea/dictionaries 82 | # .idea/shelf 83 | 84 | # Sensitive or high-churn files: 85 | # .idea/dataSources.ids 86 | # .idea/dataSources.xml 87 | # .idea/sqlDataSources.xml 88 | # .idea/dynamic.xml 89 | # .idea/uiDesigner.xml 90 | 91 | # Gradle: 92 | # .idea/gradle.xml 93 | # .idea/libraries 94 | 95 | # Mongo Explorer plugin: 96 | # .idea/mongoSettings.xml 97 | 98 | ## File-based project format: 99 | *.ipr 100 | *.iws 101 | 102 | ## Plugin-specific files: 103 | 104 | # IntelliJ 105 | /out/ 106 | 107 | # mpeltonen/sbt-idea plugin 108 | .idea_modules/ 109 | 110 | # JIRA plugin 111 | atlassian-ide-plugin.xml 112 | 113 | # Crashlytics plugin (for Android Studio and IntelliJ) 114 | com_crashlytics_export_strings.xml 115 | crashlytics.properties 116 | crashlytics-build.properties 117 | fabric.properties 118 | 119 | 120 | ### Xcode ### 121 | # Xcode 122 | # 123 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 124 | 125 | ## Build generated 126 | build/ 127 | DerivedData 128 | 129 | ## Various settings 130 | *.pbxuser 131 | !default.pbxuser 132 | *.mode1v3 133 | !default.mode1v3 134 | *.mode2v3 135 | !default.mode2v3 136 | *.perspectivev3 137 | !default.perspectivev3 138 | xcuserdata 139 | 140 | ## Other 141 | *.xccheckout 142 | *.moved-aside 143 | *.xcuserstate 144 | 145 | 146 | ### OSX ### 147 | .DS_Store 148 | .AppleDouble 149 | .LSOverride 150 | 151 | # Icon must end with two \r 152 | Icon 153 | 154 | # Thumbnails 155 | ._* 156 | 157 | # Files that might appear in the root of a volume 158 | .DocumentRevisions-V100 159 | .fseventsd 160 | .Spotlight-V100 161 | .TemporaryItems 162 | .Trashes 163 | .VolumeIcon.icns 164 | 165 | # Directories potentially created on remote AFP share 166 | .AppleDB 167 | .AppleDesktop 168 | Network Trash Folder 169 | Temporary Items 170 | .apdisk 171 | 172 | -------------------------------------------------------------------------------- /IBAnimatable/FillDesignable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jake Lin on 12/5/15. 3 | // Copyright © 2015 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public protocol FillDesignable { 9 | var fillColor: UIColor? { get set } 10 | var predefinedColor: String? { get set } 11 | var opacity: CGFloat { get set } 12 | } 13 | 14 | public extension FillDesignable where Self: UIView { 15 | public func configFillColor() { 16 | if let unwrappedFillColor = fillColor { 17 | backgroundColor = unwrappedFillColor 18 | } else if let unwrappedPredefinedColor = predefinedColorFromString(predefinedColor) { 19 | backgroundColor = unwrappedPredefinedColor 20 | } 21 | } 22 | 23 | public func configOpacity() { 24 | if !opacity.isNaN && opacity >= 0 && opacity <= 1 { 25 | alpha = opacity 26 | 27 | // Make better performance 28 | if opacity == 1 { 29 | opaque = true 30 | } 31 | } 32 | } 33 | } 34 | 35 | public extension FillDesignable where Self: UITableViewCell { 36 | public func configFillColor() { 37 | if let unwrappedFillColor = fillColor { 38 | backgroundColor = unwrappedFillColor 39 | contentView.backgroundColor = unwrappedFillColor 40 | } else if let unwrappedPredefinedColor = predefinedColorFromString(predefinedColor) { 41 | backgroundColor = unwrappedPredefinedColor 42 | contentView.backgroundColor = unwrappedPredefinedColor 43 | } 44 | } 45 | } 46 | 47 | private extension FillDesignable { 48 | 49 | func predefinedColorFromString(predefinedColor: String?) -> UIColor? { 50 | guard let unwrappedColorTypeString = predefinedColor, colorType = ColorType(rawValue: unwrappedColorTypeString) else { 51 | return nil 52 | } 53 | 54 | switch colorType { 55 | case .FlatEmerland: 56 | return UIColor(red: 46 / 255, green: 204 / 255, blue: 113 / 255, alpha: 1.0) 57 | case .FlatPomegranate: 58 | return UIColor(red: 192 / 255, green: 57 / 255, blue: 43 / 255, alpha: 1.0) 59 | case .FlatWetAsphalt: 60 | return UIColor(red: 52 / 255, green: 73 / 255, blue: 94 / 255, alpha: 1.0) 61 | case .FlatTurquoise: 62 | return UIColor(red: 26 / 255, green: 188 / 255, blue: 156 / 255, alpha: 1.0) 63 | case .FlatConcrete: 64 | return UIColor(red: 149 / 255, green: 165 / 255, blue: 166 / 255, alpha: 1.0) 65 | case .FlatOrange: 66 | return UIColor(red: 243 / 255, green: 156 / 255, blue: 18 / 255, alpha: 1.0) 67 | case .FlatAsbestos: 68 | return UIColor(red: 127 / 255, green: 140 / 255, blue: 141 / 255, alpha: 1.0) 69 | case .FlatPeterRiver: 70 | return UIColor(red: 52 / 255, green: 152 / 255, blue: 219 / 255, alpha: 1.0) 71 | case .FlatSilver: 72 | return UIColor(red: 189 / 255, green: 195 / 255, blue: 199 / 255, alpha: 1.0) 73 | case .FlatSunFlower: 74 | return UIColor(red: 241 / 255, green: 196 / 255, blue: 15 / 255, alpha: 1.0) 75 | case .FlatAmethyst: 76 | return UIColor(red: 155 / 255, green: 89 / 255, blue: 182 / 255, alpha: 1.0) 77 | case .FlatAlizarin: 78 | return UIColor(red: 231 / 255, green: 76 / 255, blue: 60 / 255, alpha: 1.0) 79 | case .FlatGreenSea: 80 | return UIColor(red: 22 / 255, green: 160 / 255, blue: 133 / 255, alpha: 1.0) 81 | case .FlatBelizeHole: 82 | return UIColor(red: 41 / 255, green: 128 / 255, blue: 185 / 255, alpha: 1.0) 83 | case .FlatNephritis: 84 | return UIColor(red: 39 / 255, green: 174 / 255, blue: 96 / 255, alpha: 1.0) 85 | case .FlatMidnightBlue: 86 | return UIColor(red: 44 / 255, green: 62 / 255, blue: 80 / 255, alpha: 1.0) 87 | case .FlatClouds: 88 | return UIColor(red: 236 / 255, green: 240 / 255, blue: 241 / 255, alpha: 1.0) 89 | case .FlatWisteria: 90 | return UIColor(red: 142 / 255, green: 68 / 255, blue: 173 / 255, alpha: 1.0) 91 | case .FlatCarrot: 92 | return UIColor(red: 230 / 255, green: 126 / 255, blue: 34 / 255, alpha: 1.0) 93 | case .FlatPumpkin: 94 | return UIColor(red: 211 / 255, green: 84 / 255, blue: 0 / 255, alpha: 1.0) 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /IBAnimatable/SlideAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Tom Baranes on 08/05/16. 3 | // Copyright © 2016 Jake Lin. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | 8 | public class SlideAnimator: NSObject, AnimatedTransitioning { 9 | // MARK: - AnimatorProtocol 10 | public var transitionAnimationType: TransitionAnimationType 11 | public var transitionDuration: Duration = defaultTransitionDuration 12 | public var reverseAnimationType: TransitionAnimationType? 13 | public var interactiveGestureType: InteractiveGestureType? 14 | 15 | // MARK: - private 16 | private var fromDirection: TransitionDirection 17 | private var horizontal = false 18 | private var reverse = false 19 | private var fade = false 20 | 21 | public init(fromDirection: TransitionDirection, params: [String], transitionDuration: Duration) { 22 | self.fromDirection = fromDirection 23 | self.transitionDuration = transitionDuration 24 | fade = params.contains("fade") 25 | horizontal = fromDirection.isHorizontal 26 | 27 | switch fromDirection { 28 | case .Right: 29 | self.transitionAnimationType = .Slide(toDirection: .Right, params: params) 30 | self.reverseAnimationType = .Slide(toDirection: .Left, params: params) 31 | self.interactiveGestureType = .Pan(fromDirection: .Right) 32 | reverse = true 33 | case .Top: 34 | self.transitionAnimationType = .Slide(toDirection: .Top, params: params) 35 | self.reverseAnimationType = .Slide(toDirection: .Bottom, params: params) 36 | self.interactiveGestureType = .Pan(fromDirection: .Top) 37 | reverse = false 38 | case .Bottom: 39 | self.transitionAnimationType = .Slide(toDirection: .Bottom, params: params) 40 | self.reverseAnimationType = .Slide(toDirection: .Top, params: params) 41 | self.interactiveGestureType = .Pan(fromDirection: .Bottom) 42 | reverse = true 43 | default: 44 | self.transitionAnimationType = .Slide(toDirection: .Left, params: params) 45 | self.reverseAnimationType = .Slide(toDirection: .Right, params: params) 46 | self.interactiveGestureType = .Pan(fromDirection: .Left) 47 | reverse = false 48 | } 49 | super.init() 50 | } 51 | } 52 | 53 | extension SlideAnimator: UIViewControllerAnimatedTransitioning { 54 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 55 | return retrieveTransitionDuration(transitionContext) 56 | } 57 | 58 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 59 | let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext) 60 | guard let fromView = tempfromView, toView = tempToView, containerView = tempContainerView else { 61 | transitionContext.completeTransition(true) 62 | return 63 | } 64 | 65 | 66 | let travelDistance = horizontal ? containerView.bounds.width : containerView.bounds.height 67 | let travel = CGAffineTransformMakeTranslation(horizontal ? (reverse ? travelDistance : -travelDistance) : 0, horizontal ? 0 : (reverse ? travelDistance : -travelDistance)) 68 | containerView.addSubview(toView) 69 | if fade { 70 | toView.alpha = 0 71 | } 72 | toView.transform = CGAffineTransformInvert(travel) 73 | animateSlideTransition(toView: toView, fromView: fromView, travel: travel) { 74 | fromView.transform = CGAffineTransformIdentity 75 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) 76 | } 77 | } 78 | 79 | } 80 | 81 | // MARK: - Animation 82 | 83 | private extension SlideAnimator { 84 | 85 | func animateSlideTransition(toView toView: UIView, fromView: UIView, travel: CGAffineTransform, completion: AnimatableCompletion) { 86 | UIView.animateWithDuration(transitionDuration, animations: { 87 | fromView.transform = travel 88 | toView.transform = CGAffineTransformIdentity 89 | if self.fade { 90 | fromView.alpha = 0 91 | toView.alpha = 1 92 | } 93 | }, 94 | completion: { _ in 95 | completion() 96 | }) 97 | } 98 | 99 | } 100 | --------------------------------------------------------------------------------