├── XWTransitionDemo ├── p1.JPG ├── p2.JPG ├── zrx1.jpg ├── zrx2.jpg ├── zrx3.jpg ├── zrx4.jpg ├── zrx5.jpg ├── zrx6.jpg ├── zrx7.jpg ├── zrx8.jpg ├── zrx9.jpg ├── PageFlipTransiton │ ├── XWCoolTypeListController.h │ ├── XWCoolToController.h │ ├── XWCoolFromController.h │ ├── XWCoolTypeListController.m │ ├── XWCoolToController.m │ └── XWCoolFromController.m ├── XWTransitionTypeListController.h ├── MagicMoveTransiton │ ├── XWMagicMoveFromTwoController.h │ ├── XWMagicMoveListController.h │ ├── XWMagicMoveToController.h │ ├── XWMagicMoveFromController.h │ ├── XWMagicMoveToImageController.h │ ├── XWMagicMoveToController.m │ ├── XWMagicMoveListController.m │ ├── XWMagicMoveFromController.m │ ├── XWMagicMoveFromTwoController.m │ └── XWMagicMoveToImageController.m ├── DrawerTransition │ ├── XWDrawerTypeListController.h │ ├── XWDrawerToController.h │ ├── XWDrawerFromController.h │ ├── XWDrawerTypeListController.m │ ├── XWDrawerToController.m │ └── XWDrawerFromController.m ├── CircleSpreadTransition │ ├── XWCircleSpreadToController.h │ ├── XWCircleSpreadFromController.h │ ├── XWCircleSpreadToController.m │ └── XWCircleSpreadFromController.m ├── AppDelegate.h ├── FilterTransition │ ├── XWFilterListControllerController.h │ ├── XWFilterToController.h │ ├── XWFilterFromController.h │ ├── XWFilterListControllerController.m │ ├── XWFilterToController.m │ └── XWFilterFromController.m ├── main.m ├── AppDelegate.m ├── XWBasicToController.h ├── XWBasicFromController.h ├── XWBasicListController.h ├── XWTransitionTypeListController.m ├── XWBasicFromController.m ├── XWBasicToController.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard └── XWBasicListController.m ├── XWTransition ├── Resoures │ ├── line.png │ ├── mask.jpg │ └── restrictedshine.tiff ├── Category │ ├── UIView+Snapshot.h │ ├── UINavigationController+XWTransition.h │ ├── UIView+Snapshot.m │ ├── UIViewController+XWTransition.h │ ├── UIViewController+XWTransition.m │ └── UINavigationController+XWTransition.m ├── XWFilterAnimator │ ├── XWFilterAnimator+XWMask.h │ ├── XWFilterAnimator+XWFlash.h │ ├── XWFilterAnimator+XWBoxBlur.h │ ├── XWFilterAnimator+XWRipple.h │ ├── XWFilterAnimator+XWMod.h │ ├── XWFilterAnimator+XWSwipe.h │ ├── XWFilterAnimator+XWPageCurl.h │ ├── XWFilterAnimator+XWBarSwipe.h │ ├── XWFilterAnimator+XWCopyMachine.h │ ├── XWFilterTransitionView.h │ ├── XWFilterAnimator+XWBoxBlur.m │ ├── XWFilterAnimator+XWBarSwipe.m │ ├── XWFilterAnimator+XWPageCurl.m │ ├── XWFilterAnimator+XWRipple.m │ ├── XWFilterAnimator+XWSwipe.m │ ├── XWFilterAnimator+XWFlash.m │ ├── XWFilterAnimator+XWCopyMachine.m │ ├── XWFilterAnimator+XWMod.m │ ├── XWFilterAnimator+XWMask.m │ ├── XWFilterAnimator.h │ ├── XWFilterTransitionView.m │ └── XWFilterAnimator.m ├── XWCoolAnimator │ ├── XWCoolAnimator+XWExplode.h │ ├── XWCoolAnimator+XWPageFlip.h │ ├── XWCoolAnimator+XWPortal.h │ ├── XWCoolAnimator+XWFold.h │ ├── XWCoolAnimator+XWLines.h │ ├── XWCoolAnimator+XWScanning.h │ ├── XWCoolAnimator+XWMiddlePageFlip.h │ ├── XWCoolAnimator.h │ ├── XWCoolAnimator+XWExplode.m │ ├── XWCoolAnimator+XWScanning.m │ ├── XWCoolAnimator+XWPageFlip.m │ ├── XWCoolAnimator+XWLines.m │ ├── XWCoolAnimator+XWPortal.m │ ├── XWCoolAnimator.m │ ├── XWCoolAnimator+XWFold.m │ └── XWCoolAnimator+XWMiddlePageFlip.m ├── XWCircleSpreadAnimator │ ├── XWCircleSpreadAnimator.h │ └── XWCircleSpreadAnimator.m ├── XWMagicMoveAnimator │ ├── XWMagicMoveAnimator.h │ └── XWMagicMoveAnimator.m ├── Main │ ├── XWTransitionAnimator.h │ ├── XWInteractiveTransition.h │ ├── XWTransitionAnimator.m │ └── XWInteractiveTransition.m └── XWDrawerAnimator │ └── XWDrawerAnimator.h ├── XWTransitionDemo.xcodeproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── .gitignore ├── README.md └── LICENSE.md /XWTransitionDemo/p1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/p1.JPG -------------------------------------------------------------------------------- /XWTransitionDemo/p2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/p2.JPG -------------------------------------------------------------------------------- /XWTransitionDemo/zrx1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx1.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx2.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx3.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx4.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx5.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx6.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx7.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx8.jpg -------------------------------------------------------------------------------- /XWTransitionDemo/zrx9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransitionDemo/zrx9.jpg -------------------------------------------------------------------------------- /XWTransition/Resoures/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransition/Resoures/line.png -------------------------------------------------------------------------------- /XWTransition/Resoures/mask.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransition/Resoures/mask.jpg -------------------------------------------------------------------------------- /XWTransition/Resoures/restrictedshine.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wazrx/XWTransition/HEAD/XWTransition/Resoures/restrictedshine.tiff -------------------------------------------------------------------------------- /XWTransitionDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XWTransitionDemo/PageFlipTransiton/XWCoolTypeListController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolTypeListController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicListController.h" 10 | 11 | @interface XWCoolTypeListController : XWBasicListController 12 | @end 13 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWTransitionTypeListController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/9. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicListController.h" 10 | 11 | @interface XWTransitionTypeListController : XWBasicListController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveFromTwoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveToTwoController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XWMagicMoveFromTwoController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /XWTransitionDemo/DrawerTransition/XWDrawerTypeListController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWDrawerTypeListController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/15. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicListController.h" 10 | 11 | @interface XWDrawerTypeListController : XWBasicListController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveListController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveListController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicListController.h" 10 | 11 | @interface XWMagicMoveListController : XWBasicListController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | .svn 4 | */build/* 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | #*.xcworkspace 14 | xcuserdata 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | *.hmap 19 | *.xccheckout 20 | 21 | #CocoaPods 22 | #Pods 23 | 24 | 25 | -------------------------------------------------------------------------------- /XWTransitionDemo/CircleSpreadTransition/XWCircleSpreadToController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCircleSpreadToController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicToController.h" 10 | 11 | @interface XWCircleSpreadToController : XWBasicToController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /XWTransitionDemo/CircleSpreadTransition/XWCircleSpreadFromController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCircleSpreadController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicFromController.h" 10 | 11 | @interface XWCircleSpreadFromController : XWBasicFromController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /XWTransitionDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/9. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /XWTransitionDemo/FilterTransition/XWFilterListControllerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterListControllerViewController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicListController.h" 10 | 11 | @interface XWFilterListControllerController : XWBasicListController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /XWTransitionDemo/FilterTransition/XWFilterToController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterToController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicToController.h" 10 | 11 | @interface XWFilterToController : XWBasicToController 12 | @property (nonatomic, assign) NSUInteger type; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransitionDemo/PageFlipTransiton/XWCoolToController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWPageFlipToController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicToController.h" 10 | 11 | @interface XWCoolToController : XWBasicToController 12 | @property (nonatomic, assign) NSUInteger type; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransitionDemo/DrawerTransition/XWDrawerToController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWDrawerToController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/15. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicToController.h" 10 | 11 | @interface XWDrawerToController : XWBasicToController 12 | 13 | @property (nonatomic, assign) NSInteger type; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /XWTransitionDemo/FilterTransition/XWFilterFromController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterFromController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicFromController.h" 10 | 11 | @interface XWFilterFromController : XWBasicFromController 12 | @property (nonatomic, assign) NSUInteger type; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveToController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveToController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicToController.h" 10 | 11 | @interface XWMagicMoveToController : XWBasicToController 12 | 13 | - (void)xw_setImage:(UIImage *)img; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /XWTransitionDemo/PageFlipTransiton/XWCoolFromController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWPageFlipFromController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicFromController.h" 10 | 11 | @interface XWCoolFromController : XWBasicFromController 12 | @property (nonatomic, assign) NSUInteger type; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransition/Category/UIView+Snapshot.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Snapshot.h 3 | // XWTransitionDemo 4 | // 5 | // Created by 肖文 on 2016/12/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (Snapshot) 12 | 13 | @property (nonatomic, readonly) UIImage *snapshotImage; 14 | @property (nonatomic, strong) UIImage *contentImage; 15 | 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /XWTransitionDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/9. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /XWTransitionDemo/DrawerTransition/XWDrawerFromController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWDrawerFromController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/15. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicFromController.h" 10 | 11 | @interface XWDrawerFromController : XWBasicFromController 12 | 13 | @property (nonatomic, assign) NSInteger type; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveFromController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveFromController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicFromController.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface XWMagicMoveFromController : XWBasicFromController 14 | 15 | - (void)xw_setImage:(UIImage *)img; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransitionDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/9. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | return YES; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveToImageController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveToImageController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XWMagicMoveToImageController : UIViewController 12 | 13 | @property (nonatomic, assign) NSUInteger idx; 14 | 15 | @property (nonatomic, copy) void(^dismissConfig)(NSInteger currentIndex); 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWMask.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWMask.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWMask) 12 | 13 | - (void)xw_maskAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration; 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWBasicToController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWBasicToController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UINavigationController+XWTransition.h" 11 | #import "UIViewController+XWTransition.h" 12 | 13 | @interface XWBasicToController : UIViewController 14 | @property (nonatomic, weak, readonly) UIButton *button; 15 | 16 | - (void)xw_transiton; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWFlash.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWFlash.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWFlash) 12 | 13 | - (void)xw_flashAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration; 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWBoxBlur.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWBoxBlur.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWBoxBlur) 12 | - (void)xw_boxBlurAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWRipple.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWRipple.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWRipple) 12 | 13 | - (void)xw_rippleAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration; 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWMod.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWMod.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWMod) 12 | 13 | - (void)xw_modAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag; 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWExplode.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWExplode.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/14. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | 11 | @interface XWCoolAnimator (XWExplode) 12 | 13 | - (void)xw_setExplodeToAnimation:(id)transitionContext; 14 | 15 | - (void)xw_setExplodeBackAnimation:(id)transitionContext; 16 | @end 17 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWPageFlip.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWPageFlip.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | 11 | @interface XWCoolAnimator (XWPageFlip) 12 | - (void)xw_setPageFlipToAnimation:(id)transitionContext; 13 | 14 | - (void)xw_setPageFlipBackAnimation:(id)transitionContext; 15 | @end 16 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWSwipe.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWSwipe.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWSwipe) 12 | 13 | - (void)xw_swipeAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag; 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWPortal.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWPortal.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | 11 | @interface XWCoolAnimator (XWPortal) 12 | 13 | - (void)xw_setPortalToAnimation:(id)transitionContext; 14 | 15 | - (void)xw_setPortalBackAnimation:(id)transitionContext; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWPageCurl.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWPageCurl.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | @interface XWFilterAnimator (XWPageCurl) 11 | 12 | - (void)xw_pageCurlAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag; 13 | @end 14 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWBarSwipe.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWBarSwipe.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWBarSwipe) 12 | 13 | - (void)xw_barSwipeAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag; 14 | @end 15 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWCopyMachine.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWCopyMachine.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | 11 | @interface XWFilterAnimator (XWCopyMachine) 12 | - (void)xw_copyMachineAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag; 13 | @end 14 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWFold.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWFold.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | 11 | @interface XWCoolAnimator (XWFold) 12 | 13 | - (void)xw_setFoldToAnimation:(id)transitionContext leftFlag:(BOOL)left; 14 | 15 | - (void)xw_setFoldBackAnimation:(id)transitionContext leftFlag:(BOOL)left; 16 | @end 17 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWBasicFromController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWBasicFromController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UINavigationController+XWTransition.h" 11 | #import "UIViewController+XWTransition.h" 12 | 13 | @interface XWBasicFromController : UIViewController 14 | @property (nonatomic, weak,readonly) UISwitch *pushOrPresntSwitch; 15 | @property (nonatomic, weak, readonly) UIButton *button; 16 | 17 | - (void)xw_transition; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWLines.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWVerticalLines.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/14. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | 11 | @interface XWCoolAnimator (XWLines) 12 | 13 | 14 | - (void)xw_setLinesToAnimation:(id)transitionContext vertical:(BOOL)vertical; 15 | 16 | - (void)xw_setLinesBackAnimation:(id)transitionContext vertical:(BOOL)vertical; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWBasicListController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWBasicListController.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XWBasicListController : UIViewController 12 | @property (nonatomic, copy) NSArray *titleData; 13 | @property (nonatomic, weak,readonly) UITableView *mainView; 14 | 15 | - (void)xw_configCell:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath; 16 | 17 | - (void)xw_selectCellAtIndexPath:(NSIndexPath *)indexPath; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWScanning.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWScanning.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/14. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | 11 | @interface XWCoolAnimator (XWScanning) 12 | 13 | 14 | - (void)xw_setScanningToAnimation:(id)transitionContext direction:(NSUInteger)direction; 15 | 16 | - (void)xw_setScanningBackAnimation:(id)transitionContext direction:(NSUInteger)direction; 17 | @end 18 | -------------------------------------------------------------------------------- /XWTransition/Category/UINavigationController+XWTransition.h: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationController+XWTransition.h 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | @class XWTransitionAnimator; 11 | 12 | @interface UINavigationController (XWTransition) 13 | 14 | /** 15 | * 通过指定的转场animator来push控制器,达到不同的转场效果 16 | * 17 | * @param viewController 被push的控制器 18 | * @param animator 转场Animator 19 | */ 20 | - (void)xw_pushViewController:(UIViewController *)viewController withAnimator:(XWTransitionAnimator *)animator; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /XWTransition/XWCircleSpreadAnimator/XWCircleSpreadAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCircleSpreadAnimator.h 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWTransitionAnimator.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface XWCircleSpreadAnimator : XWTransitionAnimator 14 | 15 | /** 16 | * 返回一个小圆点扩散转场效果器 17 | * 18 | * @param point 扩散开始中心 19 | * @param radius 扩散开始的半径 20 | * 21 | * @return 小圆点扩散转场效果器 22 | */ 23 | + (instancetype)xw_animatorWithStartCenter:(CGPoint)point radius:(CGFloat)radius; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransitionDemo/CircleSpreadTransition/XWCircleSpreadToController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCircleSpreadToController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCircleSpreadToController.h" 10 | 11 | @implementation XWCircleSpreadToController 12 | 13 | - (void)viewDidLoad { 14 | [super viewDidLoad]; 15 | [self.button setTitle:@"点我或向下滑动" forState:UIControlStateNormal]; 16 | __weak typeof(self)weakSelf = self; 17 | [self xw_registerBackInteractiveTransitionWithDirection:XWInteractiveTransitionGestureDirectionDown transitonBlock:^(CGPoint startPoint){ 18 | [weakSelf xw_transiton]; 19 | } edgeSpacing:0]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /XWTransitionDemo/DrawerTransition/XWDrawerTypeListController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWDrawerTypeListController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/15. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWDrawerTypeListController.h" 10 | #import "XWDrawerFromController.h" 11 | 12 | @implementation XWDrawerTypeListController 13 | 14 | - (void)viewDidLoad { 15 | [super viewDidLoad]; 16 | self.navigationItem.title = @"DrawertypeList"; 17 | self.titleData = @[@"drawerLeft(仿QQ)",@"drawerBottom(仿淘宝)"]; 18 | } 19 | 20 | - (void)xw_selectCellAtIndexPath:(NSIndexPath *)indexPath{ 21 | XWDrawerFromController *fVC = [XWDrawerFromController new]; 22 | fVC.type = indexPath.row; 23 | [self.navigationController pushViewController:fVC animated:YES]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /XWTransition/Category/UIView+Snapshot.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Snapshot.m 3 | // XWTransitionDemo 4 | // 5 | // Created by 肖文 on 2016/12/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "UIView+Snapshot.h" 10 | 11 | @implementation UIView (Snapshot) 12 | 13 | - (UIImage *)snapshotImage { 14 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0); 15 | [self.layer renderInContext:UIGraphicsGetCurrentContext()]; 16 | UIImage *snap = UIGraphicsGetImageFromCurrentImageContext(); 17 | UIGraphicsEndImageContext(); 18 | return snap; 19 | } 20 | 21 | - (UIImage *)contentImage{ 22 | return [UIImage imageWithCGImage:(__bridge CGImageRef)self.layer.contents]; 23 | } 24 | 25 | - (void)setContentImage:(UIImage *)contentImage{ 26 | self.layer.contents = (__bridge id)contentImage.CGImage;; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWMiddlePageFlip.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWMiddlePageFlip.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | 11 | typedef NS_ENUM(NSUInteger, XWMiddlePageFlipDirection) { 12 | XWMiddlePageFlipDirectionLeft, 13 | XWMiddlePageFlipDirectionRight, 14 | XWMiddlePageFlipDirectionTop, 15 | XWMiddlePageFlipDirectionBottom 16 | }; 17 | 18 | @interface XWCoolAnimator (XWMiddlePageFlip) 19 | 20 | 21 | - (void)xw_setMiddlePageFlipToAnimation:(id)transitionContext direction:(XWMiddlePageFlipDirection)direction; 22 | 23 | - (void)xw_setMiddlePageFlipBackAnimation:(id)transitionContext direction:(XWMiddlePageFlipDirection)direction; 24 | @end 25 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterTransitionView.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWBlurView.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface XWFilterTransitionView : GLKView 14 | 15 | @property (nonatomic, assign) BOOL blurType; 16 | @property (nonatomic, strong) CIFilter *filter; 17 | 18 | - (instancetype)initWithFrame:(CGRect)frame 19 | fromImage:(UIImage *)fromImage 20 | toImage:(UIImage *)toImage; 21 | 22 | - (CAAnimation *)xw_getInnerAnimation; 23 | 24 | - (CIVector *)xw_getInnerVector; 25 | 26 | + (void)xw_animationWith:(XWFilterTransitionView *)filterView duration:(NSTimeInterval)duration completion:(void (^ __nullable)(BOOL finished))completion; 27 | 28 | @end 29 | 30 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWBoxBlur.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWBoxBlur.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWBoxBlur.h" 10 | 11 | @implementation XWFilterAnimator (XWBoxBlur) 12 | 13 | - (void)xw_boxBlurAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration { 14 | CIFilter *filter = [CIFilter filterWithName: @"CIBoxBlur"]; 15 | filterView.filter = filter; 16 | filterView.blurType = YES; 17 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 18 | [filterView removeFromSuperview]; 19 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 20 | 21 | }]; 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /XWTransitionDemo/DrawerTransition/XWDrawerToController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWDrawerToController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/15. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWDrawerToController.h" 10 | #import "XWCoolAnimator.h" 11 | 12 | @implementation XWDrawerToController 13 | 14 | - (void)viewDidLoad { 15 | [super viewDidLoad]; 16 | NSString *title = _type ? @"点我或向下滑动" : @"点我或向左滑动"; 17 | [self.button setTitle:title forState:UIControlStateNormal]; 18 | self.button.hidden = YES; 19 | XWInteractiveTransitionGestureDirection direction = _type ? XWInteractiveTransitionGestureDirectionDown : XWInteractiveTransitionGestureDirectionLeft; 20 | __weak typeof(self)weakSelf = self; 21 | [self xw_registerBackInteractiveTransitionWithDirection:direction transitonBlock:^(CGPoint startPoint){ 22 | [weakSelf xw_transiton]; 23 | } edgeSpacing:0]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /XWTransitionDemo/FilterTransition/XWFilterListControllerController.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 4 | // XWFilterListControllerViewController.m 5 | // XWTransitionDemo 6 | // 7 | // Created by wazrx on 16/6/17. 8 | // Copyright © 2016年 wazrx. All rights reserved. 9 | // 10 | 11 | #import "XWFilterListControllerController.h" 12 | #import "XWFilterFromController.h" 13 | 14 | @interface XWFilterListControllerController () 15 | 16 | @end 17 | 18 | @implementation XWFilterListControllerController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | self.navigationItem.title = @"FilterTransition"; 23 | self.titleData = @[@"BoxBlur", @"Swipe", @"BarsSwipe", @"Mask", @"Flash", @"Mod", @"PageCurl", @"Ripple", @"CopyMachine"]; 24 | } 25 | 26 | - (void)xw_selectCellAtIndexPath:(NSIndexPath *)indexPath{ 27 | XWFilterFromController *fVC = [XWFilterFromController new]; 28 | fVC.type = indexPath.row; 29 | [self.navigationController pushViewController:fVC animated:YES]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWTransitionTypeListController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/9. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWTransitionTypeListController.h" 10 | 11 | @implementation XWTransitionTypeListController 12 | 13 | - (void)viewDidLoad { 14 | [super viewDidLoad]; 15 | self.navigationItem.title = @"transitionList"; 16 | self.titleData = @[@"CircleSpreadTransition", @"MagicMoveTransition", @"CoolTransition", @"DrawerTransition", @"FilterTransition"]; 17 | } 18 | 19 | - (void)xw_selectCellAtIndexPath:(NSIndexPath *)indexPath{ 20 | NSArray *controllerNames = @[@"XWCircleSpreadFromController", @"XWMagicMoveListController", @"XWCoolTypeListController", @"XWDrawerTypeListController", @"XWFilterListControllerController"]; 21 | UIViewController *pushVC = [NSClassFromString(controllerNames[indexPath.row]) new]; 22 | pushVC.hidesBottomBarWhenPushed = YES; 23 | [self.navigationController pushViewController:pushVC animated:YES]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /XWTransitionDemo/PageFlipTransiton/XWCoolTypeListController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolTypeListController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolTypeListController.h" 10 | #import "XWCoolFromController.h" 11 | #import "XWCoolAnimator.h" 12 | 13 | @implementation XWCoolTypeListController 14 | 15 | - (void)viewDidLoad { 16 | [super viewDidLoad]; 17 | self.navigationItem.title = @"CooltypeList"; 18 | self.titleData = @[@"PageFlip",@"MiddleFlipFromLeft",@"MiddleFlipFromRight",@"MiddleFlipFromTop",@"MiddleFlipFromBottom",@"Portal",@"FoldFromLeft",@"FoldFromRight", @"Explode", @"HorizontalLines", @"VerticalLines",@"ScanningFromLeft",@"ScanningFromRight",@"ScanningFromTop",@"ScanningFromBottom"]; 19 | } 20 | 21 | - (void)xw_selectCellAtIndexPath:(NSIndexPath *)indexPath{ 22 | XWCoolFromController *fVC = [XWCoolFromController new]; 23 | fVC.type = indexPath.row; 24 | [self.navigationController pushViewController:fVC animated:YES]; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /XWTransition/XWMagicMoveAnimator/XWMagicMoveAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveAnimator.h 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/8. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 神奇移动效果请配合UIViewController+XWTransition中的相关API使用,如果神奇移动的终止视图为cell,需要参考一下demo中的九宫格例子 8 | 9 | #import "XWTransitionAnimator.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UIView (XWTransition) 14 | 15 | //神奇移动的时候,如果对设置view的该属性为YES,则移动视图不会按照截图的方式生成,而且尝试直接取得其image(暂时支持imageView、button等),解决神奇移动从下到大会产生模糊的情况 16 | @property (nonatomic, assign) BOOL magicMoveImageMode; 17 | 18 | @end 19 | 20 | 21 | @interface XWMagicMoveAnimator : XWTransitionAnimator 22 | 23 | //是否开启弹簧效果 24 | @property (nonatomic, assign) BOOL dampingEnable; 25 | //设为YES后,对于做神奇移动数组中的所有View会直接取其图片而不会截图,可解决神奇移动从小变得较大的时候,截图不清晰的问题,如果想要对单个view最该设置,请参考上面的UIView分类的magicMoveImageMode属性 26 | @property (nonatomic, assign) BOOL imageMode; 27 | 28 | @end 29 | 30 | UIKIT_EXTERN NSString *const kXWMagicMoveAnimatorStartViewVCKey; 31 | UIKIT_EXTERN NSString *const kXWMagicMoveAnimatorEndViewVCKey; 32 | 33 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWBarSwipe.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWBarSwipe.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWBarSwipe.h" 10 | 11 | @implementation XWFilterAnimator (XWBarSwipe) 12 | 13 | - (void)xw_barSwipeAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag { 14 | CGFloat angle = self.revers && !flag ? self.startAngle + M_PI : self.startAngle; 15 | CIFilter *filter = [CIFilter filterWithName:@"CIBarsSwipeTransition" 16 | keysAndValues: 17 | kCIInputAngleKey, @(angle), 18 | nil]; 19 | filterView.filter = filter; 20 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 21 | [filterView removeFromSuperview]; 22 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 23 | }]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /XWTransitionDemo/PageFlipTransiton/XWCoolToController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWPageFlipToController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolToController.h" 10 | 11 | @implementation XWCoolToController 12 | 13 | - (void)viewDidLoad { 14 | [super viewDidLoad]; 15 | NSArray *directionNames = @[@"右",@"左",@"右",@"上",@"下",@"上",@"左",@"右",@"上",@"右", @"上", @"左", @"右", @"上", @"下"]; 16 | [self.button setTitle:[NSString stringWithFormat:@"点我或向%@滑动", directionNames[_type]] forState:UIControlStateNormal]; 17 | [self.button addTarget:self action:@selector(xw_transiton) forControlEvents:UIControlEventTouchUpInside]; 18 | __weak typeof(self)weakSelf = self; 19 | [self xw_registerBackInteractiveTransitionWithDirection:[self xw_getDirectionWithName:directionNames[_type]] transitonBlock:^(CGPoint startPoint){ 20 | [weakSelf xw_transiton]; 21 | } edgeSpacing:0]; 22 | } 23 | 24 | - (NSInteger)xw_getDirectionWithName:(NSString *)name{ 25 | NSArray *temp = @[@"左", @"右", @"上", @"下"]; 26 | return [temp indexOfObject:name]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWPageCurl.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // XWFilterAnimator+XWPageCurl.m 4 | // XWTransitionDemo 5 | // 6 | // Created by wazrx on 16/6/19. 7 | // Copyright © 2016年 wazrx. All rights reserved. 8 | // 9 | 10 | #import "XWFilterAnimator+XWPageCurl.h" 11 | 12 | @implementation XWFilterAnimator (XWPageCurl) 13 | 14 | - (void)xw_pageCurlAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag{ 15 | CGFloat angle = self.revers && !flag ? self.startAngle + M_PI : self.startAngle; 16 | CIFilter *filter = [CIFilter filterWithName: @"CIPageCurlWithShadowTransition" 17 | keysAndValues: 18 | kCIInputAngleKey, @(angle), 19 | nil]; 20 | filterView.filter = filter; 21 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 22 | [filterView removeFromSuperview]; 23 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 24 | }]; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /XWTransition/Main/XWTransitionAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWTransitionAnimator.h 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 所有转场效果器的基类,若要自定义请继承与该基类 8 | 9 | #import 10 | #import "XWInteractiveTransition.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface XWTransitionAnimator : NSObject 15 | 16 | //to转场时间 默认0.5 17 | @property (nonatomic, assign) NSTimeInterval toDuration; 18 | //back转场时间 默认0.5 19 | @property (nonatomic, assign) NSTimeInterval backDuration; 20 | //是否需要开启手势timer,某些转场如果在转成过程中所开手指,不会有动画过渡,显得很生硬,开启timer后,松开手指,会用timer不断的刷新转场百分比,消除生硬的缺点 21 | @property (nonatomic, assign) BOOL needInteractiveTimer; 22 | 23 | /** 24 | * 配置To过程动画(push, present),自定义转场动画应该复写该方法 25 | */ 26 | - (void)xw_setToAnimation:(id)transitionContext; 27 | /** 28 | * 配置back过程动画(pop, dismiss),自定义转场动画应该复写该方法 29 | */ 30 | - (void)xw_setBackAnimation:(id)transitionContext; 31 | 32 | @end 33 | 34 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransitionDemo/FilterTransition/XWFilterToController.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // XWFilterToController.m 4 | // XWTransitionDemo 5 | // 6 | // Created by wazrx on 16/6/17. 7 | // Copyright © 2016年 wazrx. All rights reserved. 8 | // 9 | 10 | #import "XWFilterToController.h" 11 | 12 | @interface XWFilterToController () 13 | 14 | @end 15 | 16 | @implementation XWFilterToController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | NSArray *directionNames = @[@"上",@"左",@"左", @"上", @"上", @"上", @"左", @"左", @"左"]; 21 | [self.button setTitle:[NSString stringWithFormat:@"点我或向%@滑动", directionNames[_type]] forState:UIControlStateNormal]; 22 | [self.button addTarget:self action:@selector(xw_transiton) forControlEvents:UIControlEventTouchUpInside]; 23 | __weak typeof(self)weakSelf = self; 24 | [self xw_registerBackInteractiveTransitionWithDirection:[self xw_getDirectionWithName:directionNames[_type]] transitonBlock:^(CGPoint startPoint){ 25 | [weakSelf xw_transiton]; 26 | } edgeSpacing:0]; 27 | } 28 | 29 | - (NSInteger)xw_getDirectionWithName:(NSString *)name{ 30 | NSArray *temp = @[@"左", @"右", @"上", @"下"]; 31 | return [temp indexOfObject:name]; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWBasicFromController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWBasicFromController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicFromController.h" 10 | 11 | @implementation XWBasicFromController 12 | 13 | - (void)viewDidLoad { 14 | [super viewDidLoad]; 15 | self.view.backgroundColor = [UIColor whiteColor]; 16 | self.view.layer.contents = (__bridge id)[UIImage imageNamed:@"p1.JPG"].CGImage; 17 | UISwitch *pushOrPresntSwitch = [UISwitch new]; 18 | _pushOrPresntSwitch = pushOrPresntSwitch; 19 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:pushOrPresntSwitch]; 20 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 21 | _button = button; 22 | button.titleLabel.font = [UIFont systemFontOfSize:13]; 23 | button.titleLabel.textAlignment = 1; 24 | [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 25 | button.center = CGPointMake(self.view.center.x, self.view.center.y + 30); 26 | button.bounds = CGRectMake(0, 0, 150, 30); 27 | [button addTarget:self action:@selector(xw_transition) forControlEvents:UIControlEventTouchUpInside]; 28 | [self.view addSubview:button]; 29 | } 30 | 31 | - (void)xw_transition { 32 | 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWBasicToController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWBasicToController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicToController.h" 10 | 11 | @interface XWBasicToController () 12 | 13 | @end 14 | 15 | @implementation XWBasicToController 16 | 17 | - (void)dealloc{ 18 | NSLog(@"toVC销毁了"); 19 | } 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | self.view.backgroundColor = [UIColor whiteColor]; 24 | self.view.layer.contents = (__bridge id)[UIImage imageNamed:@"p2.JPG"].CGImage; 25 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 26 | _button = button; 27 | button.titleLabel.font = [UIFont systemFontOfSize:13]; 28 | [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 29 | button.center = CGPointMake(self.view.center.x, self.view.center.y + 30); 30 | button.bounds = CGRectMake(0, 0, 100, 30); 31 | [button addTarget:self action:@selector(xw_transiton) forControlEvents:UIControlEventTouchUpInside]; 32 | [self.view addSubview:button]; 33 | } 34 | 35 | - (void)xw_transiton{ 36 | if (self.navigationController) { 37 | [self.navigationController popViewControllerAnimated:YES]; 38 | }else{ 39 | [self dismissViewControllerAnimated:YES completion:nil]; 40 | } 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWRipple.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWRipple.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWRipple.h" 10 | 11 | @implementation XWFilterAnimator (XWRipple) 12 | 13 | - (void)xw_rippleAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration{ 14 | CIImage *img = [CIImage imageWithCGImage:[UIImage imageNamed:@"restrictedshine.tiff"].CGImage]; 15 | CIVector *vector = [filterView xw_getInnerVector]; 16 | CIFilter *filter = [CIFilter filterWithName: @"CIRippleTransition" 17 | keysAndValues: 18 | kCIInputShadingImageKey, img, 19 | kCIInputCenterKey, [CIVector vectorWithX:0.5 * vector.CGRectValue.size.width 20 | Y:0.5 * vector.CGRectValue.size.height], 21 | nil]; 22 | filterView.filter = filter; 23 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 24 | [filterView removeFromSuperview]; 25 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 26 | }]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /XWTransition/XWDrawerAnimator/XWDrawerAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWDrawerAnimator.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/15. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWTransitionAnimator.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSUInteger, XWDrawerAnimatorDirection) { 14 | XWDrawerAnimatorDirectionLeft, 15 | XWDrawerAnimatorDirectionRight, 16 | XWDrawerAnimatorDirectionTop, 17 | XWDrawerAnimatorDirectionBottom 18 | }; 19 | 20 | @interface XWDrawerAnimator : XWTransitionAnimator 21 | 22 | /**fromVC的缩放比例, 如果Flip效果,比例默认为0.8, 否者为1.0不缩放*/ 23 | @property (nonatomic, assign) CGFloat scaleRatio; 24 | /**视差效果,类似于QQ的设置界面弹出效果, 和flipEnable只能选择其一,如果都设置为YES,后设置的生效*/ 25 | @property (nonatomic, assign) BOOL parallaxEnable; 26 | /**翻转效果,类似于淘宝选择规格时,后面视图的动画效果*/ 27 | @property (nonatomic, assign) BOOL flipEnable; 28 | 29 | /** 30 | * 初始化一个转场抽屉效果器 31 | * 32 | * @param direction 抽屉效果触发方向 33 | * @param distance 显示在屏幕中的宽度或者高度,如果传0,默认就是当前屏幕的高度或者宽度 34 | * 35 | * @return animator 36 | */ 37 | + (instancetype)xw_animatorWithDirection:(XWDrawerAnimatorDirection)direction moveDistance:(CGFloat)distance; 38 | 39 | /** 40 | * 开启边缘(就是屏幕除开toView所占用的部分)back手势和边缘点击返回效果,类似于QQ设置界面的返回效果 41 | * 42 | * @param backConfig 返回操作,您的dismiss或者pop操作 43 | */ 44 | - (void)xw_enableEdgeGestureAndBackTapWithConfig:(dispatch_block_t)backConfig; 45 | 46 | @end 47 | 48 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWSwipe.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWSwipe.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWSwipe.h" 10 | 11 | @implementation XWFilterAnimator (XWSwipe) 12 | 13 | - (void)xw_swipeAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag { 14 | CGFloat angle = self.revers && !flag ? self.startAngle + M_PI : self.startAngle; 15 | CIVector *vector = [filterView xw_getInnerVector]; 16 | CIFilter *filter = [CIFilter filterWithName:@"CISwipeTransition" 17 | keysAndValues: 18 | kCIInputExtentKey, vector, 19 | kCIInputColorKey, [CIColor colorWithRed:0 green:0 blue:0 alpha:0], 20 | kCIInputAngleKey, @(angle), 21 | kCIInputWidthKey, @80.0, 22 | @"inputOpacity", @0.0, 23 | nil]; 24 | filterView.filter = filter; 25 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 26 | [filterView removeFromSuperview]; 27 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 28 | }]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWFlash.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWFlash.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWFlash.h" 10 | 11 | @implementation XWFilterAnimator (XWFlash) 12 | 13 | - (void)xw_flashAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration{ 14 | CGSize size = filterView.frame.size; 15 | CIFilter *filter = [CIFilter filterWithName:@"CIFlashTransition" 16 | keysAndValues: 17 | kCIInputCenterKey, [CIVector vectorWithCGPoint:CGPointMake(size.width, size.height)], 18 | kCIInputColorKey, [CIColor colorWithRed:1.0 green:0.8 blue:0.6 alpha:1], 19 | @"inputMaxStriationRadius", @2.5, 20 | @"inputStriationStrength", @0.5, 21 | @"inputStriationContrast", @1.37, 22 | @"inputFadeThreshold", @0.5, 23 | nil]; 24 | filterView.filter = filter; 25 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 26 | [filterView removeFromSuperview]; 27 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 28 | }]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWCopyMachine.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWCopyMachine.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWCopyMachine.h" 10 | 11 | @implementation XWFilterAnimator (XWCopyMachine) 12 | 13 | - (void)xw_copyMachineAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag{ 14 | CGFloat angle = self.revers && !flag ? self.startAngle + M_PI : self.startAngle; 15 | CIVector *vector = [filterView xw_getInnerVector]; 16 | CIFilter *filter = [CIFilter filterWithName:@"CICopyMachineTransition" 17 | keysAndValues: 18 | kCIInputExtentKey, vector, 19 | kCIInputColorKey, [CIColor colorWithRed:.6 green:1 blue:.8 alpha:1], 20 | kCIInputAngleKey, @(angle), 21 | kCIInputWidthKey, @50.0, 22 | @"inputOpacity", @1.0, 23 | nil]; 24 | filterView.filter = filter; 25 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 26 | [filterView removeFromSuperview]; 27 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 28 | }]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWMod.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWMod.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWMod.h" 10 | 11 | @implementation XWFilterAnimator (XWMod) 12 | 13 | - (void)xw_modAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration toFlag:(BOOL)flag{ 14 | CGFloat angle = self.revers && !flag ? self.startAngle + M_PI : self.startAngle; 15 | CIVector *vector = [filterView xw_getInnerVector]; 16 | CIFilter *filter = [CIFilter filterWithName: @"CIModTransition" 17 | keysAndValues: 18 | kCIInputCenterKey,[CIVector vectorWithX:0.5 * vector.CGRectValue.size.width 19 | Y:0.5 * vector.CGRectValue.size.height], 20 | kCIInputAngleKey, @(angle), 21 | kCIInputRadiusKey, @30.0, 22 | @"inputCompression", @10.0, 23 | nil]; 24 | filterView.filter = filter; 25 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 26 | [filterView removeFromSuperview]; 27 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 28 | }]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /XWTransitionDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator+XWMask.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator+XWMask.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator+XWMask.h" 10 | 11 | @implementation XWFilterAnimator (XWMask) 12 | 13 | - (void)xw_maskAnimationFor:(XWFilterTransitionView *)filterView transitionContext:(id)transitionContext duration:(NSTimeInterval)duration { 14 | CGFloat height = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.frame.size.height; 15 | CIImage *maskImg = self.maskImg ? [CIImage imageWithCGImage:self.maskImg.CGImage] : [CIImage imageWithCGImage:[UIImage imageNamed:@"mask.jpg"].CGImage]; 16 | CIFilter *filter = [CIFilter filterWithName: @"CIDisintegrateWithMaskTransition" 17 | keysAndValues: 18 | kCIInputMaskImageKey, maskImg, 19 | @"inputShadowRadius", @10.0, 20 | @"inputShadowDensity", @0.7, 21 | @"inputShadowOffset", [CIVector vectorWithX:0.0 Y:-0.05 * height], 22 | nil]; 23 | filterView.filter = filter; 24 | [XWFilterTransitionView xw_animationWith:filterView duration:duration completion:^(BOOL finished) { 25 | [filterView removeFromSuperview]; 26 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 27 | }]; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /XWTransitionDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveToController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveToController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWMagicMoveToController.h" 10 | 11 | @interface XWMagicMoveToController () 12 | @property (nonatomic, weak) UIImageView *imgView; 13 | @property (nonatomic, strong) UIImage *img; 14 | @end 15 | 16 | @implementation XWMagicMoveToController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.view.layer.contents = nil; 21 | UIImageView *imgView = [UIImageView new]; 22 | imgView.frame = CGRectMake(10, 100, 150, 150); 23 | imgView.image = _img; 24 | [self.view addSubview:imgView]; 25 | UIView *view1 = [UIView new]; 26 | view1.backgroundColor = [UIColor blueColor]; 27 | [self.view addSubview:view1]; 28 | view1.frame = CGRectMake(50, 400, 80, 80); 29 | view1.layer.cornerRadius = 40; 30 | UIView *view2 = [UIView new]; 31 | view2.backgroundColor = [UIColor purpleColor]; 32 | view2.frame = CGRectMake(200, 400, 75, 75); 33 | [self.view addSubview:view2]; 34 | [self.button setTitle:@"点我或向上滑动" forState:UIControlStateNormal]; 35 | [self xw_addMagicMoveEndViewGroup:@[imgView, view1, view2]]; 36 | __weak typeof(self)weakSelf = self; 37 | [self xw_registerBackInteractiveTransitionWithDirection:XWInteractiveTransitionGestureDirectionUp transitonBlock:^(CGPoint startPoint){ 38 | [weakSelf xw_transiton]; 39 | } edgeSpacing:0]; 40 | } 41 | 42 | - (void)xw_setImage:(UIImage *)img { 43 | _img = img; 44 | } 45 | @end 46 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // XWFilterAnimator 全都是基于不同的CIFilter产生的一些滤镜效果,貌似在模拟器无法运行这些效果,请在真机上测试 8 | 9 | #import "XWTransitionAnimator.h" 10 | #import "XWFilterTransitionView.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | typedef NS_ENUM(NSUInteger, XWFilterAnimatorType) { 15 | XWFilterAnimatorTypeBoxBlur,//模糊转场,对应CIBoxBlur 16 | XWFilterAnimatorTypeSwipe,//滑动过渡转场,对应CISwipeTranstion 17 | XWFilterAnimatorTypeBarSwipe,//对应CIBarSwipeTranstion 18 | XWFilterAnimatorTypeMask,//按指定遮罩图片转场,对应CIDisintegrateWithMaskTransition 19 | XWFilterAnimatorTypeFlash,//闪烁转场,对应CIFlashTransition 20 | XWFilterAnimatorTypeMod,//条纹转场 对应CIModTransition 21 | XWFilterAnimatorTypePageCurl,//翻页转场 对应CIPageCurlWithShadowTransition 22 | XWFilterAnimatorTypeRipple,//波纹转场,对应CIRippleTransition 23 | XWFilterAnimatorTypeCopyMachine, //效果和XWCoolAnimator中的Scanning效果类似,对应CICopyMachineTransition 24 | }; 25 | 26 | @interface XWFilterAnimator : XWTransitionAnimator 27 | 28 | /**for XWFilterAnimatorTypeMask,如果为空,则为默认的maskImg*/ 29 | @property (nonatomic, strong) UIImage *maskImg; 30 | /**是否翻转,对于有转场有方向之分的此属性可用,如果为YES,如果to转场为左,那么back转场为右,默认为YES*/ 31 | @property (nonatomic, assign) BOOL revers; 32 | /**开始角度,对于有转场方向的转场此属性可用,0为左,M_PI_2 为下 M_PI 为右 M_PI_2 * 3为上,也可指定任意开始角度*/ 33 | @property (nonatomic, assign) CGFloat startAngle; 34 | 35 | /** 36 | * 初始化一个filter转场效果器 37 | * 38 | * @param type 效果枚举值 39 | * 40 | * @return 效果器 41 | */ 42 | + (instancetype)xw_animatorWithType:(XWFilterAnimatorType)type; 43 | 44 | @end 45 | 46 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransitionDemo/FilterTransition/XWFilterFromController.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // XWFilterFromController.m 4 | // XWTransitionDemo 5 | // 6 | // Created by wazrx on 16/6/17. 7 | // Copyright © 2016年 wazrx. All rights reserved. 8 | // 9 | 10 | #import "XWFilterFromController.h" 11 | #import "XWFilterToController.h" 12 | #import "XWFilterAnimator.h" 13 | 14 | @interface XWFilterFromController () 15 | 16 | @end 17 | 18 | @implementation XWFilterFromController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | NSArray *directionNames = @[@"下",@"右", @"右", @"下", @"下", @"下", @"右", @"右", @"右"]; 23 | [self.button setTitle:[NSString stringWithFormat:@"点我或向%@滑动", directionNames[_type]] forState:UIControlStateNormal]; 24 | [self.button addTarget:self action:@selector(xw_transition) forControlEvents:UIControlEventTouchUpInside]; 25 | __weak typeof(self)weakSelf = self; 26 | [self xw_registerToInteractiveTransitionWithDirection:[self xw_getDirectionWithName:directionNames[_type]] transitonBlock:^(CGPoint startPoint){ 27 | [weakSelf xw_transition]; 28 | } edgeSpacing:0]; 29 | } 30 | 31 | - (void)xw_transition{ 32 | XWFilterAnimator *animator = [XWFilterAnimator xw_animatorWithType:_type]; 33 | XWFilterToController *toVC = [XWFilterToController new]; 34 | toVC.type = _type; 35 | if (self.pushOrPresntSwitch.on) { 36 | [self.navigationController xw_pushViewController:toVC withAnimator:animator]; 37 | }else{ 38 | [self xw_presentViewController:toVC withAnimator:animator]; 39 | } 40 | } 41 | 42 | - (NSInteger)xw_getDirectionWithName:(NSString *)name{ 43 | NSArray *temp = @[@"左", @"右", @"上", @"下"]; 44 | return [temp indexOfObject:name]; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /XWTransitionDemo/PageFlipTransiton/XWCoolFromController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWPageFlipFromController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolFromController.h" 10 | #import "XWCoolToController.h" 11 | #import "XWCoolAnimator.h" 12 | 13 | 14 | @implementation XWCoolFromController 15 | 16 | - (void)viewDidLoad { 17 | [super viewDidLoad]; 18 | NSArray *directionNames = @[@"左",@"右", @"左", @"下", @"上", @"下",@"右",@"左",@"下",@"左",@"下",@"右",@"左",@"下",@"上"]; 19 | [self.button setTitle:[NSString stringWithFormat:@"点我或向%@滑动", directionNames[_type]] forState:UIControlStateNormal]; 20 | [self.button addTarget:self action:@selector(xw_transition) forControlEvents:UIControlEventTouchUpInside]; 21 | __weak typeof(self)weakSelf = self; 22 | [self xw_registerToInteractiveTransitionWithDirection:[self xw_getDirectionWithName:directionNames[_type]] transitonBlock:^(CGPoint startPoint){ 23 | [weakSelf xw_transition]; 24 | } edgeSpacing:0]; 25 | } 26 | 27 | - (void)xw_transition{ 28 | XWCoolAnimator *animator = [XWCoolAnimator xw_animatorWithType:_type]; 29 | animator.toDuration = 1.0f; 30 | animator.backDuration = 1.0f; 31 | XWCoolToController *toVC = [XWCoolToController new]; 32 | toVC.type = _type; 33 | if (self.pushOrPresntSwitch.on) { 34 | [self.navigationController xw_pushViewController:toVC withAnimator:animator]; 35 | }else{ 36 | [self xw_presentViewController:toVC withAnimator:animator]; 37 | } 38 | } 39 | 40 | - (NSInteger)xw_getDirectionWithName:(NSString *)name{ 41 | NSArray *temp = @[@"左", @"右", @"上", @"下"]; 42 | return [temp indexOfObject:name]; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /XWTransitionDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /XWTransitionDemo/XWBasicListController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWBasicListController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWBasicListController.h" 10 | 11 | @interface XWBasicListController () 12 | 13 | @end 14 | 15 | @implementation XWBasicListController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | self.view.backgroundColor = [UIColor whiteColor]; 20 | UITableView *mainView = [UITableView new]; 21 | mainView.delegate = self; 22 | mainView.dataSource = self; 23 | mainView.frame = self.view.bounds; 24 | mainView.backgroundColor = [UIColor whiteColor]; 25 | _mainView = mainView; 26 | [self.view addSubview:mainView]; 27 | } 28 | 29 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 30 | return self.titleData.count; 31 | } 32 | 33 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 34 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"xwtransition"]; 35 | if (!cell) { 36 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"xwtransition"]; 37 | } 38 | cell.textLabel.text = _titleData[indexPath.row]; 39 | [self xw_configCell:cell indexPath:indexPath]; 40 | return cell; 41 | } 42 | 43 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 44 | [self xw_selectCellAtIndexPath:indexPath]; 45 | } 46 | 47 | - (void)xw_configCell:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath { 48 | 49 | } 50 | 51 | - (void)xw_selectCellAtIndexPath:(NSIndexPath *)indexPath { 52 | 53 | } 54 | 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveListController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveListController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWMagicMoveListController.h" 10 | #import "XWMagicMoveFromController.h" 11 | #import "XWMagicMoveFromTwoController.h" 12 | #import "XWMagicMoveAnimator.h" 13 | 14 | @implementation XWMagicMoveListController 15 | 16 | - (void)viewDidLoad { 17 | [super viewDidLoad]; 18 | self.navigationItem.title = @"magicTypeList"; 19 | self.titleData = @[@"test1",@"test2"]; 20 | self.mainView.rowHeight = 65; 21 | } 22 | 23 | - (void)xw_configCell:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath{ 24 | NSArray *imgs = @[@"zrx1.jpg", @"zrx2.jpg"]; 25 | cell.imageView.image = [UIImage imageNamed:imgs[indexPath.row]]; 26 | } 27 | 28 | - (void)xw_selectCellAtIndexPath:(NSIndexPath *)indexPath{ 29 | UIImageView *imgView = [self.mainView cellForRowAtIndexPath:indexPath].imageView; 30 | [self xw_addMagicMoveStartViewGroup:@[imgView]]; 31 | XWMagicMoveAnimator *animator = [XWMagicMoveAnimator new]; 32 | animator.dampingEnable = YES; 33 | animator.imageMode = YES; 34 | animator.toDuration = 0.5f; 35 | animator.backDuration = 0.5f; 36 | if (indexPath.row == 0) { 37 | XWMagicMoveFromController *fromVC = [XWMagicMoveFromController new]; 38 | [fromVC xw_setImage:imgView.image]; 39 | [self.navigationController xw_pushViewController:fromVC withAnimator:animator]; 40 | return; 41 | } 42 | if (indexPath.row == 1) { 43 | XWMagicMoveFromTwoController *fromTwoVC = [XWMagicMoveFromTwoController new]; 44 | [self.navigationController xw_pushViewController:fromTwoVC withAnimator:animator]; 45 | } 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWTransitionAnimator.h" 10 | 11 | /** 12 | cool转场效果中的Portal、Fold、Explode效果的部分代码逻辑来源于ColinEberhardt/VCTransitionsLibrary,地址:https://github.com/ColinEberhardt/VCTransitionsLibrary 非常感谢作者,我只是将其进行了部分改动,以便对手势的支持更加完善,里面还有许多其他效果,本人经历有限就没有再集成进来了,大家可以自行查看; 13 | cool转场效果的Lines的想法来自于cinkster/HUAnimator,地址:https://github.com/cinkster/HUAnimator, 非常感谢作者,但是由于作者在对toVC截图采用了延迟的方式来处理,导致了闪烁和一些手势上的bug,对此我采用了另一种方式来解决截图的问题,使用了layer的contentRect属性,解决了闪烁问题和延迟截图的bug问题,相关代码请自行查看 14 | 15 | */ 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | typedef NS_ENUM(NSUInteger, XWCoolTransitionAnimatorType){ 20 | //全屏翻页 21 | XWCoolTransitionAnimatorTypePageFlip, 22 | //中间翻页 23 | XWCoolTransitionAnimatorTypePageMiddleFlipFromLeft, 24 | XWCoolTransitionAnimatorTypePageMiddleFlipFromRight, 25 | XWCoolTransitionAnimatorTypePageMiddleFlipFromTop, 26 | XWCoolTransitionAnimatorTypePageMiddleFlipFromBottom, 27 | //开窗 28 | XWCoolTransitionAnimatorTypePortal, 29 | //折叠 30 | XWCoolTransitionAnimatorTypeFoldFromLeft, 31 | XWCoolTransitionAnimatorTypeFoldFromRight, 32 | //爆炸 33 | XWCoolTransitionAnimatorTypeExplode, 34 | //酷炫线条效果 35 | XWCoolTransitionAnimatorTypeHorizontalLines, 36 | XWCoolTransitionAnimatorTypeVerticalLines, 37 | //扫描效果 38 | XWCoolTransitionAnimatorTypeScanningFromLeft, 39 | XWCoolTransitionAnimatorTypeScanningFromRight, 40 | XWCoolTransitionAnimatorTypeScanningFromTop, 41 | XWCoolTransitionAnimatorTypeScanningFromBottom, 42 | 43 | 44 | }; 45 | 46 | @interface XWCoolAnimator : XWTransitionAnimator 47 | 48 | //flod效果的折叠数量, for XWCoolTransitionAnimatorTypeFoldFromLeft 和 XWCoolTransitionAnimatorTypeFoldFromRight 49 | @property (nonatomic) NSUInteger foldCount; 50 | 51 | + (instancetype)xw_animatorWithType:(XWCoolTransitionAnimatorType)type; 52 | 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransitionDemo/CircleSpreadTransition/XWCircleSpreadFromController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCircleSpreadController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCircleSpreadFromController.h" 10 | #import "XWCircleSpreadToController.h" 11 | #import "XWCircleSpreadAnimator.h" 12 | 13 | @implementation XWCircleSpreadFromController 14 | 15 | - (void)viewDidLoad { 16 | [super viewDidLoad]; 17 | [self.button addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(xw_drag:)]]; 18 | [self.button setTitle:@"点我\n拖我" forState:UIControlStateNormal]; 19 | self.button.backgroundColor = [UIColor lightGrayColor]; 20 | self.button.titleLabel.numberOfLines = 0; 21 | self.button.titleLabel.font = [UIFont systemFontOfSize:12]; 22 | self.button.bounds = CGRectMake(0, 0, 40, 40); 23 | self.button.center = CGPointMake(self.view.center.x, self.view.center.y - 100); 24 | self.button.layer.cornerRadius = 20; 25 | 26 | } 27 | 28 | - (void)xw_transition{ 29 | XWCircleSpreadAnimator *animator = [XWCircleSpreadAnimator xw_animatorWithStartCenter:self.button.center radius:20]; 30 | animator.toDuration = 0.5f; 31 | animator.backDuration = 0.5f; 32 | XWCircleSpreadToController *toVC = [XWCircleSpreadToController new]; 33 | if (self.pushOrPresntSwitch.on) { 34 | [self.navigationController xw_pushViewController:toVC withAnimator:animator]; 35 | }else{ 36 | [self xw_presentViewController:toVC withAnimator:animator]; 37 | } 38 | } 39 | 40 | - (void)xw_drag:(UIPanGestureRecognizer *)panGesture{ 41 | CGPoint transitionP = [panGesture translationInView:panGesture.view]; 42 | CGFloat transitionX = fmax(20, fmin(self.button.center.x + transitionP.x, self.view.bounds.size.width - 20)); 43 | CGFloat transitionY = fmax(64 + 20, fmin(self.button.center.y + transitionP.y, self.view.bounds.size.height - 20)); 44 | self.button.center = CGPointMake(transitionX, transitionY); 45 | [panGesture setTranslation:CGPointZero inView:panGesture.view]; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /XWTransition/Main/XWInteractiveTransition.h: -------------------------------------------------------------------------------- 1 | // 2 | // XWInteractiveTransition.h 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/10. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 手势转场管理者 8 | // 注意:使用UIViewController+XWTransition相关API配合animator,通常情况下无需自己创建手势过渡管理者 9 | 10 | #import 11 | @class XWInteractiveTransition; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | /**手势转场时的代理事件,animator默认为为其手势的代理,复写对应的代理事件可处理一些手势失败闪烁的情况*/ 16 | @protocol XWInteractiveTransitionDelegate 17 | 18 | @optional 19 | /**手势转场即将开始时调用*/ 20 | - (void)xw_interactiveTransitionWillBegin:(XWInteractiveTransition *)interactiveTransition; 21 | /**手势转场中调用*/ 22 | - (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition isUpdating:(CGFloat)percent; 23 | /**如果开始了转场手势timer,会在松开手指,timer开始的时候调用*/ 24 | - (void)xw_interactiveTransitionWillBeginTimerAnimation:(XWInteractiveTransition *)interactiveTransition; 25 | /**手势转场结束的时候调用*/ 26 | - (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition willEndWithSuccessFlag:(BOOL)flag percent:(CGFloat)percent; 27 | 28 | @end 29 | 30 | /**手势转场方向*/ 31 | typedef NS_ENUM(NSUInteger, XWInteractiveTransitionGestureDirection) { 32 | XWInteractiveTransitionGestureDirectionLeft = 0, 33 | XWInteractiveTransitionGestureDirectionRight, 34 | XWInteractiveTransitionGestureDirectionUp, 35 | XWInteractiveTransitionGestureDirectionDown 36 | }; 37 | 38 | @interface XWInteractiveTransition : UIPercentDrivenInteractiveTransition 39 | 40 | @property (nonatomic, assign, readonly) BOOL interation; 41 | @property (nonatomic, assign) BOOL timerEable; 42 | @property (nonatomic, weak) id delegate; 43 | 44 | /**设置该值可改变计算手势百分比的基准,手势基准的原理:百分比 = 拖动距离 / panRatioBaseValue, 默认情况下水平方向panRatioBaseValue为手势所在view的宽度,垂直方向为手势所在view的高度,通常无需更改该值,在某些特殊情况下,如果想要调整手势的速率可以更改该值,比如让手势速率加倍,可以调整该值为view宽度高度的一半*/ 45 | @property (nonatomic, assign) CGFloat panRatioBaseValue; 46 | 47 | + (instancetype)xw_interactiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction config:(void(^)(CGPoint startPoint))config edgeSpacing:(CGFloat)edgeSpacing; 48 | 49 | - (void)xw_addPanGestureForView:(UIView *)view to:(BOOL)flag; 50 | 51 | @end 52 | 53 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /XWTransition/Category/UIViewController+XWTransition.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+XWTransition.h 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XWTransitionAnimator.h" 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UIViewController (XWTransition) 14 | 15 | 16 | /** 17 | * 通过指定的转场animator来present控制器 18 | * 19 | * @param viewController 被modal出的控制器 20 | * @param animator 转场animator 21 | */ 22 | - (void)xw_presentViewController:(UIViewController *)viewController withAnimator:(XWTransitionAnimator *)animator; 23 | 24 | 25 | #pragma mark - 神奇移动相关 26 | 27 | /** 28 | * 注册神奇移动起始视图 29 | * 30 | * @param group 神奇移动起始视图数组 31 | */ 32 | - (void)xw_addMagicMoveStartViewGroup:(NSArray *)group; 33 | 34 | /** 35 | * 注册神奇移动终止视图 36 | * 37 | * @param group 神奇移动终止视图数组,注意起始视图数组和终止视图数组的视图需要一一对应才能有正确的效果 38 | */ 39 | - (void)xw_addMagicMoveEndViewGroup:(NSArray *)group; 40 | 41 | /** 42 | * 改变神奇移动起始视图,因为在back的时候,有可能不需要再回到原来起始的位置,需要去一个新的视图位置,所以在back前需要调用该方法改变起始视图数组 43 | * 44 | * @param group 新的起始视图数组 45 | */ 46 | - (void)xw_changeMagicMoveStartViewGroup:(NSArray *)group; 47 | 48 | #pragma mark - 手势相关 49 | 50 | /** 51 | * 注册to手势(push或者Present手势),block中的startPoint为手势开始时手指所在的点,在有些特殊需求的时候,你可能需要它 52 | * 53 | * @param direction 手势方向 54 | * @param tansitionConfig 手势触发的block,block中需要包含你的push或者Present的逻辑代码,注意避免循环引用问题 55 | * @param edgeSpacing 手势触发的边缘距离,该值为0,表示在整个控制器视图上都有效,否者这在边缘的edgeSpacing之类有效 56 | */ 57 | 58 | - (void)xw_registerToInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(void(^)(CGPoint startPoint))tansitionConfig edgeSpacing:(CGFloat)edgeSpacing; 59 | 60 | /** 61 | * 注册back手势(pop或者dismiss手势) 62 | * 63 | * @param direction 手势方向 64 | * @param tansitionConfig 手势触发的block,block中需要包含你的pop或者dismiss的逻辑代码,注意避免循环引用问题 65 | * @param edgeSpacing 手势触发的边缘距离,该值为0,表示在整个控制器视图上都有效,否者这在边缘的edgeSpacing之类有效 66 | */ 67 | - (void)xw_registerBackInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(void(^)(CGPoint startPoint))tansitionConfig edgeSpacing:(CGFloat)edgeSpacing; 68 | 69 | @end 70 | 71 | UIKIT_EXTERN NSString *const kXWToInteractiveKey; 72 | UIKIT_EXTERN NSString *const kXWAnimatorKey; 73 | 74 | NS_ASSUME_NONNULL_END 75 | 76 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveFromController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveFromController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/12. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWMagicMoveFromController.h" 10 | #import "XWMagicMoveToController.h" 11 | #import "XWMagicMoveAnimator.h" 12 | #import "UIViewController+XWTransition.h" 13 | #import "UINavigationController+XWTransition.h" 14 | 15 | @interface XWMagicMoveFromController () 16 | 17 | @property (nonatomic, strong) UIImage *img; 18 | 19 | @end 20 | 21 | @implementation XWMagicMoveFromController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | self.view.layer.contents = nil; 26 | UIImageView *imgView = [UIImageView new]; 27 | imgView.center = CGPointMake(self.view.center.x, 170); 28 | imgView.bounds = CGRectMake(0, 0, 200, 200); 29 | imgView.image = _img; 30 | [self.view addSubview:imgView]; 31 | UIView *view1 = [UIView new]; 32 | view1.backgroundColor = [UIColor blueColor]; 33 | [self.view addSubview:view1]; 34 | view1.frame = CGRectMake(50, 300, 50, 50); 35 | view1.layer.cornerRadius = 25; 36 | UIView *view2 = [UIView new]; 37 | view2.backgroundColor = [UIColor purpleColor]; 38 | view2.frame = CGRectMake(250, 300, 75, 75); 39 | [self.view addSubview:view2]; 40 | 41 | [self.button setTitle:@"点我或向下滑动" forState:UIControlStateNormal]; 42 | //注册神奇移动前视图 43 | [self xw_addMagicMoveEndViewGroup:@[imgView]]; 44 | [self xw_addMagicMoveStartViewGroup:@[imgView, view1, view2]]; 45 | __weak typeof(self)weakSelf = self; 46 | [self xw_registerToInteractiveTransitionWithDirection:XWInteractiveTransitionGestureDirectionDown transitonBlock:^(CGPoint startPoint){ 47 | [weakSelf xw_transition]; 48 | } edgeSpacing:0]; 49 | } 50 | 51 | - (void)xw_setImage:(UIImage *)img { 52 | _img = img; 53 | } 54 | 55 | - (void)xw_transition{ 56 | XWMagicMoveToController *toVC = [XWMagicMoveToController new]; 57 | [toVC xw_setImage:_img]; 58 | XWMagicMoveAnimator *animator = [XWMagicMoveAnimator new]; 59 | animator.toDuration = animator.backDuration = 0.5; 60 | if (self.pushOrPresntSwitch.on) { 61 | [self.navigationController xw_pushViewController:toVC withAnimator:animator]; 62 | }else{ 63 | [self xw_presentViewController:toVC withAnimator:animator]; 64 | } 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveFromTwoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveToTwoController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWMagicMoveFromTwoController.h" 10 | #import "XWMagicMoveToImageController.h" 11 | #import "UIViewController+XWTransition.h" 12 | #import "UINavigationController+XWTransition.h" 13 | #import "XWMagicMoveAnimator.h" 14 | 15 | @interface XWMagicMoveFromTwoController () 16 | 17 | @end 18 | 19 | @implementation XWMagicMoveFromTwoController 20 | 21 | - (void)dealloc{ 22 | NSLog(@"toVC销毁了"); 23 | } 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | self.view.backgroundColor = [UIColor whiteColor]; 28 | for (int i = 0; i < 9; i ++) { 29 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 30 | // [button setImage:[UIImage imageNamed:[NSString stringWithFormat:@"zrx%zd.jpg", i + 1]] forState:UIControlStateNormal]; 31 | button.layer.contents = (__bridge id)[UIImage imageNamed:[NSString stringWithFormat:@"zrx%zd.jpg", i + 1]].CGImage; 32 | 33 | [button addTarget:self action:@selector(xw_clicked:) forControlEvents:UIControlEventTouchUpInside]; 34 | CGFloat spacing = 5; 35 | CGFloat edgeSpacing = 15; 36 | CGFloat width = (self.view.frame.size.width - (5 + 15) * 2) / 3.0f; 37 | CGFloat height = width; 38 | CGFloat x = edgeSpacing + (width + spacing) * (i % 3); 39 | CGFloat y = 100 + (height + spacing) * (i / 3); 40 | button.frame = CGRectMake(x, y, width, height); 41 | [self.view addSubview:button]; 42 | } 43 | //注册神奇移动转场终止视图 44 | [self xw_addMagicMoveEndViewGroup:@[self.view.subviews[1]]]; 45 | 46 | } 47 | 48 | - (void)xw_clicked:(UIButton *)sender{ 49 | XWMagicMoveToImageController *imgVC = [XWMagicMoveToImageController new]; 50 | imgVC.idx = [self.view.subviews indexOfObject:sender]; 51 | __weak typeof(self)weakSelf = self; 52 | imgVC.dismissConfig = ^(NSInteger idx){ 53 | [weakSelf xw_dismiss:idx]; 54 | }; 55 | //将点击的按钮注册为神奇移动转场开始视图 56 | [self xw_addMagicMoveStartViewGroup:@[sender]]; 57 | XWMagicMoveAnimator *animator = [XWMagicMoveAnimator new]; 58 | // animator.dampingEnable = YES; 59 | // animator.imageMode = YES; 60 | sender.magicMoveImageMode = YES; 61 | [self xw_presentViewController:imgVC withAnimator: animator]; 62 | } 63 | 64 | - (void)xw_dismiss:(NSInteger)idx{ 65 | //更改转场视图为collectionView滑动的视图 66 | [self xw_changeMagicMoveStartViewGroup:@[self.view.subviews[idx]]]; 67 | //dismiss 68 | [self dismissViewControllerAnimated:YES completion:nil]; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /XWTransitionDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /XWTransition/Category/UIViewController+XWTransition.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+XWTransition.m 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "UIViewController+XWTransition.h" 10 | #import "XWMagicMoveAnimator.h" 11 | #import 12 | 13 | @implementation UIViewController (XWTransition) 14 | 15 | - (void)xw_registerToInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(void(^)(CGPoint startPoint))tansitionConfig edgeSpacing:(CGFloat)edgeSpacing{ 16 | if (!tansitionConfig) return; 17 | XWInteractiveTransition *interactive = [XWInteractiveTransition xw_interactiveTransitionWithDirection:direction config:tansitionConfig edgeSpacing:edgeSpacing]; 18 | [interactive xw_addPanGestureForView:self.view to:YES]; 19 | objc_setAssociatedObject(self, &kXWToInteractiveKey, interactive, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 20 | 21 | } 22 | 23 | - (void)xw_registerBackInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(void(^)(CGPoint startPoint))tansitionConfig edgeSpacing:(CGFloat)edgeSpacing{ 24 | if (!tansitionConfig) return; 25 | XWInteractiveTransition *interactive = [XWInteractiveTransition xw_interactiveTransitionWithDirection:direction config:tansitionConfig edgeSpacing:edgeSpacing]; 26 | [interactive xw_addPanGestureForView:self.view to:NO]; 27 | XWTransitionAnimator *animator = objc_getAssociatedObject(self, &kXWAnimatorKey);if (animator) { 28 | [animator setValue:interactive forKey:@"backInteractive"]; 29 | } 30 | } 31 | 32 | - (void)xw_presentViewController:(UIViewController *)viewController withAnimator:(XWTransitionAnimator *)animator { 33 | if (!viewController) return; 34 | if (!animator) animator = [XWTransitionAnimator new]; 35 | viewController.transitioningDelegate = animator; 36 | XWInteractiveTransition *toInteractive = objc_getAssociatedObject(self, &kXWToInteractiveKey); 37 | if (toInteractive) { 38 | [animator setValue:toInteractive forKey:@"toInteractive"]; 39 | } 40 | objc_setAssociatedObject(viewController, &kXWAnimatorKey, animator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 41 | [self presentViewController:viewController animated:YES completion:nil]; 42 | } 43 | 44 | - (void)xw_addMagicMoveStartViewGroup:(NSArray *)group { 45 | if (!group.count) return; 46 | objc_setAssociatedObject(self, &kXWMagicMoveAnimatorStartViewVCKey, group, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 47 | } 48 | 49 | - (void)xw_addMagicMoveEndViewGroup:(NSArray *)group { 50 | if (!group.count) return; 51 | objc_setAssociatedObject(self, &kXWMagicMoveAnimatorEndViewVCKey, group, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 52 | 53 | } 54 | 55 | - (void)xw_changeMagicMoveStartViewGroup:(NSArray *)group { 56 | [self xw_addMagicMoveStartViewGroup:group]; 57 | } 58 | 59 | @end 60 | 61 | NSString *const kXWToInteractiveKey = @"kXWToInteractiveKey"; 62 | NSString *const kXWAnimatorKey = @"kXWAnimatorKey"; 63 | -------------------------------------------------------------------------------- /XWTransitionDemo/DrawerTransition/XWDrawerFromController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWDrawerFromController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/15. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWDrawerFromController.h" 10 | #import "XWDrawerToController.h" 11 | #import "XWDrawerAnimator.h" 12 | 13 | @implementation XWDrawerFromController 14 | 15 | - (void)viewDidLoad { 16 | [super viewDidLoad]; 17 | NSString *title = _type ? @"点我或向上滑动" : @"点我或从边缘向右滑动"; 18 | [self.button setTitle:title forState:UIControlStateNormal]; 19 | __weak typeof(self)weakSelf = self; 20 | XWInteractiveTransitionGestureDirection direction = _type ? XWInteractiveTransitionGestureDirectionUp : XWInteractiveTransitionGestureDirectionRight; 21 | [self xw_registerToInteractiveTransitionWithDirection:direction transitonBlock:^(CGPoint startPoint){ 22 | [weakSelf xw_transition]; 23 | } edgeSpacing:_type ? 0 : 80]; 24 | } 25 | 26 | - (void)viewDidAppear:(BOOL)animated{ 27 | [super viewDidAppear:animated]; 28 | self.navigationController.interactivePopGestureRecognizer.enabled = NO; 29 | } 30 | 31 | - (void)viewDidDisappear:(BOOL)animated{ 32 | [super viewDidDisappear:animated]; 33 | self.navigationController.interactivePopGestureRecognizer.enabled = YES; 34 | } 35 | 36 | - (void)xw_transition{ 37 | XWDrawerAnimatorDirection direction = _type ? XWDrawerAnimatorDirectionBottom : XWDrawerAnimatorDirectionLeft; 38 | CGFloat distance = _type ? 450 : 250; 39 | XWDrawerAnimator *animator = [XWDrawerAnimator xw_animatorWithDirection:direction moveDistance:distance]; 40 | animator.toDuration = 0.5; 41 | animator.backDuration = 0.5; 42 | if (_type) { 43 | animator.flipEnable = YES; 44 | }else{ 45 | animator.parallaxEnable = YES; 46 | } 47 | XWDrawerToController *toVC = [XWDrawerToController new]; 48 | toVC.type = _type; 49 | if (self.pushOrPresntSwitch.on) { 50 | [self.navigationController xw_pushViewController:toVC withAnimator:animator]; 51 | }else{ 52 | [self xw_presentViewController:toVC withAnimator:animator]; 53 | } 54 | __weak typeof(self)weakSelf = self; 55 | [animator xw_enableEdgeGestureAndBackTapWithConfig:^{ 56 | [weakSelf _xw_back]; 57 | }]; 58 | } 59 | 60 | - (void)_xw_back{ 61 | if (self.presentedViewController) { 62 | [self dismissViewControllerAnimated:YES completion:nil]; 63 | }else{ 64 | [self.navigationController popViewControllerAnimated:YES]; 65 | } 66 | } 67 | 68 | 69 | 70 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 71 | return 20; 72 | } 73 | 74 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 75 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"test"]; 76 | if (!cell) { 77 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"test"]; 78 | cell.textLabel.text = @"测试"; 79 | } 80 | return cell; 81 | } 82 | 83 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 84 | NSLog(@"选中了%zd", indexPath.row); 85 | [self xw_transition]; 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWExplode.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWExplode.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/14. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator+XWExplode.h" 10 | #import "UIView+Snapshot.h" 11 | 12 | @implementation XWCoolAnimator (XWExplode) 13 | 14 | - (void)xw_setExplodeToAnimation:(id)transitionContext { 15 | [self _xw_animation:transitionContext duration:self.toDuration]; 16 | 17 | } 18 | 19 | - (void)xw_setExplodeBackAnimation:(id)transitionContext { 20 | [self _xw_animation:transitionContext duration:self.backDuration]; 21 | 22 | } 23 | 24 | - (void)_xw_animation:(id)transitionContext duration:(NSTimeInterval)duration{ 25 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 26 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 27 | UIView *toView = toVC.view; 28 | UIView *fromView = fromVC.view; 29 | UIView *containerView = [transitionContext containerView]; 30 | [containerView insertSubview:toView atIndex:0]; 31 | CGSize size = toView.frame.size; 32 | NSMutableArray *snapshots = [NSMutableArray new]; 33 | CGFloat xNum = 10.0f; 34 | CGFloat yNum = xNum * size.height / size.width; 35 | UIView *fromViewSnapshot = [UIView new]; 36 | UIImage *fromImage = fromVC.view.snapshotImage; 37 | fromViewSnapshot.contentImage = fromImage; 38 | CGFloat fromWidth = fromVC.view.bounds.size.width; 39 | CGFloat fromHeight = fromVC.view.bounds.size.height; 40 | for (CGFloat x=0; x < size.width; x+= size.width / xNum) { 41 | for (CGFloat y=0; y < size.height; y+= size.height / yNum) { 42 | CGRect snapshotRegion = CGRectMake(x, y, size.width / xNum, size.height / yNum); 43 | UIView *snapshot = [UIView new]; 44 | snapshot.contentImage = fromImage; 45 | CGRect contentRect = CGRectMake(x / fromWidth, y / fromHeight, size.width / xNum / fromWidth, size.height / yNum / fromHeight); 46 | snapshot.layer.contentsRect = contentRect; 47 | snapshot.frame = snapshotRegion; 48 | [containerView addSubview:snapshot]; 49 | [snapshots addObject:snapshot]; 50 | } 51 | } 52 | fromView.hidden = YES; 53 | [UIView animateWithDuration:duration animations:^{ 54 | for (UIView *view in snapshots) { 55 | CGFloat xOffset = [self _xw_randomFloatBetween:-100.0 and:100.0]; 56 | CGFloat yOffset = [self _xw_randomFloatBetween:-100.0 and:100.0]; 57 | view.frame = CGRectOffset(view.frame, xOffset, yOffset); 58 | view.alpha = 0.0; 59 | view.transform = CGAffineTransformScale(CGAffineTransformMakeRotation([self _xw_randomFloatBetween:-10.0 and:10.0]), 0.01, 0.01); 60 | } 61 | } completion:^(BOOL finished) { 62 | for (UIView *view in snapshots) { 63 | [view removeFromSuperview]; 64 | } 65 | fromView.hidden = NO; 66 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 67 | }]; 68 | } 69 | 70 | - (float)_xw_randomFloatBetween:(float)smallNumber and:(float)bigNumber { 71 | float diff = bigNumber - smallNumber; 72 | return (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + smallNumber; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /XWTransition/Category/UINavigationController+XWTransition.m: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationController+XWTransition.m 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "UINavigationController+XWTransition.h" 10 | #import "UIViewController+XWTransition.h" 11 | #import "XWTransitionAnimator.h" 12 | #import 13 | #import 14 | 15 | @implementation UINavigationController (XWTransition) 16 | 17 | + (void)load{ 18 | method_exchangeImplementations(class_getInstanceMethod([self class], @selector(pushViewController:animated:)), class_getInstanceMethod([self class], @selector(_xw_pushViewController:animated:))); 19 | } 20 | 21 | - (void)xw_pushViewController:(UIViewController *)viewController withAnimator:(XWTransitionAnimator *)animator { 22 | if (!viewController) return; 23 | XWInteractiveTransition *toInteractive = objc_getAssociatedObject(self.topViewController, &kXWToInteractiveKey); 24 | if (toInteractive) { 25 | [animator setValue:toInteractive forKey:@"toInteractive"]; 26 | } 27 | if (animator) { 28 | objc_setAssociatedObject(viewController, &kXWAnimatorKey, animator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 29 | } 30 | [self pushViewController:viewController animated:YES]; 31 | static dispatch_once_t onceToken; 32 | dispatch_once(&onceToken, ^{ 33 | [self _xw_swizzeViewControlelrDealloc]; 34 | }); 35 | } 36 | 37 | - (void)_xw_swizzeViewControlelrDealloc{ 38 | Class swizzleClass = [UIViewController class]; 39 | @synchronized(swizzleClass) { 40 | SEL deallocSelector = sel_registerName("dealloc"); 41 | __block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL; 42 | __weak typeof(self)weakSelf = self; 43 | id newDealloc = ^(__unsafe_unretained UIViewController *objSelf){ 44 | [weakSelf _xw_checkDelegate]; 45 | if (originalDealloc == NULL) { 46 | struct objc_super superInfo = { 47 | .receiver = objSelf, 48 | .super_class = class_getSuperclass(swizzleClass) 49 | }; 50 | void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper; 51 | msgSend(&superInfo, deallocSelector); 52 | }else{ 53 | originalDealloc(objSelf, deallocSelector); 54 | } 55 | }; 56 | IMP newDeallocIMP = imp_implementationWithBlock(newDealloc); 57 | if (!class_addMethod(swizzleClass, deallocSelector, newDeallocIMP, "v@:")) { 58 | Method deallocMethod = class_getInstanceMethod(swizzleClass, deallocSelector); 59 | originalDealloc = (void(*)(__unsafe_unretained id, SEL))method_getImplementation(deallocMethod); 60 | originalDealloc = (void(*)(__unsafe_unretained id, SEL))method_setImplementation(deallocMethod, newDeallocIMP); 61 | } 62 | } 63 | } 64 | 65 | - (void)_xw_checkDelegate{ 66 | XWTransitionAnimator *animator = objc_getAssociatedObject(self.topViewController, &kXWAnimatorKey); 67 | if (animator) { 68 | self.delegate = animator; 69 | }else{ 70 | self.delegate = nil; 71 | } 72 | } 73 | 74 | - (void)_xw_pushViewController:(UIViewController *)viewController animated:(BOOL)animated{ 75 | XWTransitionAnimator *animator = objc_getAssociatedObject(viewController, &kXWAnimatorKey); 76 | if (animator) { 77 | self.delegate = animator; 78 | }else if([self.delegate isKindOfClass:[XWTransitionAnimator class]]){ 79 | self.delegate = nil; 80 | } 81 | [self _xw_pushViewController:viewController animated:animated]; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWScanning.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWScanning.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/14. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator+XWScanning.h" 10 | 11 | @implementation XWCoolAnimator (XWScanning) 12 | 13 | - (void)xw_setScanningToAnimation:(id)transitionContext direction:(NSUInteger)direction { 14 | [self _xw_animateTransition:transitionContext duration:self.toDuration direction:direction]; 15 | 16 | } 17 | 18 | - (void)xw_setScanningBackAnimation:(id)transitionContext direction:(NSUInteger)direction { 19 | [self _xw_animateTransition:transitionContext duration:self.toDuration direction:direction]; 20 | 21 | } 22 | 23 | - (void)_xw_animateTransition:(id )transitionContext duration:(NSTimeInterval)duration direction:(NSInteger)direction{ 24 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 25 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 26 | UIView *containerView = [transitionContext containerView]; 27 | [containerView insertSubview:toVC.view atIndex:0]; 28 | UIView *maskView = [UIView new]; 29 | maskView.backgroundColor = [UIColor whiteColor]; 30 | maskView.frame = containerView.bounds; 31 | fromVC.view.maskView = maskView; 32 | UIView *scanView = [UIView new]; 33 | scanView.layer.contents = (__bridge id)[UIImage imageNamed:@"line"].CGImage; 34 | [containerView addSubview:scanView]; 35 | CGFloat width = containerView.frame.size.width; 36 | CGFloat height = containerView.frame.size.height; 37 | CGAffineTransform transfrom = CGAffineTransformIdentity; 38 | if (direction == 0){ 39 | scanView.bounds = CGRectMake(0, 0, 18, height * 1.5); 40 | scanView.center = CGPointMake(-4, containerView.center.y); 41 | transfrom = CGAffineTransformMakeTranslation(width, 0); 42 | } 43 | if (direction == 1){ 44 | scanView.bounds = CGRectMake(0, 0, 18, height * 1.5); 45 | scanView.center = CGPointMake(width + 4, containerView.center.y); 46 | transfrom = CGAffineTransformMakeTranslation(-width, 0); 47 | } 48 | if (direction == 2){ 49 | scanView.bounds = CGRectMake(0, 0,width * 1.5, 18); 50 | scanView.center = CGPointMake(containerView.center.x, -4); 51 | transfrom = CGAffineTransformMakeTranslation(0, height); 52 | } 53 | if (direction == 3){ 54 | scanView.bounds = CGRectMake(0, 0, width * 1.5, 18); 55 | scanView.center = CGPointMake(containerView.center.x, height + 4); 56 | transfrom = CGAffineTransformMakeTranslation(0, -height); 57 | } 58 | [UIView animateKeyframesWithDuration:duration delay:0.0 options:0 59 | animations:^{ 60 | [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.7 animations:^{ 61 | maskView.transform = transfrom; 62 | scanView.transform = transfrom; 63 | }]; 64 | [UIView addKeyframeWithRelativeStartTime:0.7 relativeDuration:0.3 animations:^{ 65 | scanView.transform = CGAffineTransformIdentity; 66 | }]; 67 | 68 | } completion:^(BOOL finished) { 69 | fromVC.view.maskView = nil; 70 | [scanView removeFromSuperview]; 71 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 72 | }]; 73 | 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /XWTransitionDemo/MagicMoveTransiton/XWMagicMoveToImageController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWMagicMoveToImageController.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/19. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWMagicMoveToImageController.h" 10 | #import "UIViewController+XWTransition.h" 11 | 12 | @interface XWMagicMoveToImageController () 13 | @property (nonatomic, weak) UICollectionView *mainView; 14 | @property (nonatomic, weak) UIView *tempView; 15 | @end 16 | 17 | @implementation XWMagicMoveToImageController 18 | 19 | - (void)dealloc{ 20 | NSLog(@"toVC销毁了"); 21 | } 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | [self xw_initailizeUI]; 26 | //根据点击的idx设置collectionView的滚动位置 27 | [_mainView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:_idx inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO]; 28 | //注意:由于在转场过程中cell还没有加载,所以无法注册cell为神奇移动视图,这种情况需要生产一个零时视图注册为转场视图来使用 29 | //下面创建一个零时的转场视图 30 | UIView *tempView = [UIView new]; 31 | tempView.layer.contents = (__bridge id)[UIImage imageNamed:[NSString stringWithFormat:@"zrx%zd.jpg", _idx + 1]].CGImage; 32 | [self.view addSubview:tempView]; 33 | _tempView = tempView; 34 | //配置tempView的图片和位置和cell完全重合 35 | tempView.center = self.view.center; 36 | tempView.bounds = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width); 37 | //将该零时视图注册为神奇移动结束视图 38 | [self xw_addMagicMoveEndViewGroup:@[tempView]]; 39 | //隐藏collectionView 40 | _mainView.hidden = YES; 41 | __weak typeof(self)weakSelf = self; 42 | //注册back手势,左滑动黑色部分可以back 43 | [self xw_registerBackInteractiveTransitionWithDirection:XWInteractiveTransitionGestureDirectionLeft transitonBlock:^(CGPoint startPoint){ 44 | [weakSelf collectionView:weakSelf.mainView didSelectItemAtIndexPath:[weakSelf.mainView indexPathsForVisibleItems].firstObject]; 45 | } edgeSpacing:0]; 46 | } 47 | 48 | #pragma mark - initialize methods 49 | 50 | - (void)xw_initailizeUI{ 51 | self.view.backgroundColor = [UIColor blackColor]; 52 | UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; 53 | layout.itemSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.width); 54 | layout.minimumLineSpacing = 0; 55 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 56 | UICollectionView *mainView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; 57 | mainView.backgroundColor = [UIColor blackColor]; 58 | _mainView = mainView; 59 | mainView.pagingEnabled = YES; 60 | mainView.delegate = self; 61 | mainView.dataSource = self; 62 | [mainView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"xw_XWMagicMoveToImageController_cell"]; 63 | [self.view addSubview:mainView]; 64 | mainView.center = self.view.center; 65 | mainView.bounds = CGRectMake(0, 0, layout.itemSize.width, layout.itemSize.height); 66 | } 67 | 68 | - (void)viewDidAppear:(BOOL)animated{ 69 | [super viewDidAppear:animated]; 70 | //转场结束后,我们需要隐藏零时视图,同时显示collectionView,转场完成 71 | _mainView.hidden = NO; 72 | _tempView.hidden = YES; 73 | } 74 | 75 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ 76 | return 9; 77 | } 78 | 79 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 80 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"xw_XWMagicMoveToImageController_cell" forIndexPath:indexPath]; 81 | cell.layer.contents = (__bridge id)[UIImage imageNamed:[NSString stringWithFormat:@"zrx%zd.jpg", indexPath.item + 1]].CGImage; 82 | return cell; 83 | } 84 | 85 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ 86 | //back的时候,我们继续调出临时视图来转场,同时设置临时视图的图片为当前图片 87 | _tempView.hidden = NO; 88 | _mainView.hidden = YES; 89 | _tempView.layer.contents = (__bridge id)[UIImage imageNamed:[NSString stringWithFormat:@"zrx%zd.jpg", indexPath.item + 1]].CGImage; 90 | //将dismiss操作传递给presentingController,因为此时转场回去的视图已经改变,而且本来dismiss操作最好也应该有presentingController来完成 91 | if (_dismissConfig) { 92 | _dismissConfig(indexPath.item); 93 | } 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWPageFlip.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWPageFlip.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator+XWPageFlip.h" 10 | #import "UIView+Snapshot.h" 11 | #import 12 | 13 | static NSString *const kPageFlipTempViewKey = @"kPageFlipTempViewKey"; 14 | 15 | @implementation XWCoolAnimator (XWPageFlip) 16 | 17 | - (void)xw_setPageFlipToAnimation:(id)transitionContext { 18 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 19 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 20 | UIView *tempView = [UIView new]; 21 | tempView.contentImage = fromVC.view.snapshotImage; 22 | tempView.frame = fromVC.view.frame; 23 | UIView *containerView = [transitionContext containerView]; 24 | [containerView addSubview:toVC.view]; 25 | [containerView addSubview:tempView]; 26 | fromVC.view.hidden = YES; 27 | [containerView insertSubview:toVC.view atIndex:0]; 28 | [self _xw_setAnchorPoint:CGPointMake(0, 0.5) forView:tempView]; 29 | CATransform3D transfrom3d = CATransform3DIdentity; 30 | transfrom3d.m34 = -0.002; 31 | containerView.layer.sublayerTransform = transfrom3d; 32 | CAGradientLayer *fromGradient = [CAGradientLayer layer]; 33 | fromGradient.frame = fromVC.view.bounds; 34 | fromGradient.colors = @[(id)[UIColor blackColor].CGColor, 35 | (id)[UIColor blackColor].CGColor]; 36 | fromGradient.startPoint = CGPointMake(0.0, 0.5); 37 | fromGradient.endPoint = CGPointMake(0.8, 0.5); 38 | UIView *fromShadow = [[UIView alloc]initWithFrame:fromVC.view.bounds]; 39 | fromShadow.backgroundColor = [UIColor clearColor]; 40 | [fromShadow.layer insertSublayer:fromGradient atIndex:1]; 41 | fromShadow.alpha = 0.0; 42 | [tempView addSubview:fromShadow]; 43 | CAGradientLayer *toGradient = [CAGradientLayer layer]; 44 | toGradient.frame = fromVC.view.bounds; 45 | toGradient.colors = @[(id)[UIColor blackColor].CGColor, 46 | (id)[UIColor blackColor].CGColor]; 47 | toGradient.startPoint = CGPointMake(0.0, 0.5); 48 | toGradient.endPoint = CGPointMake(0.8, 0.5); 49 | UIView *toShadow = [[UIView alloc]initWithFrame:fromVC.view.bounds]; 50 | toShadow.backgroundColor = [UIColor clearColor]; 51 | [toShadow.layer insertSublayer:toGradient atIndex:1]; 52 | toShadow.alpha = 1.0; 53 | [toVC.view addSubview:toShadow]; 54 | objc_setAssociatedObject(self, &kPageFlipTempViewKey, tempView, OBJC_ASSOCIATION_ASSIGN); 55 | [UIView animateWithDuration:self.toDuration animations:^{ 56 | tempView.layer.transform = CATransform3DMakeRotation(-M_PI_2, 0, 1, 0); 57 | fromShadow.alpha = 1.0; 58 | toShadow.alpha = 0.0; 59 | } completion:^(BOOL finished) { 60 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 61 | if ([transitionContext transitionWasCancelled]) { 62 | [tempView removeFromSuperview]; 63 | fromVC.view.hidden = NO; 64 | } 65 | }]; 66 | 67 | } 68 | 69 | - (void)xw_setPageFlipBackAnimation:(id)transitionContext { 70 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 71 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 72 | UIView *containerView = [transitionContext containerView]; 73 | UIView *tempView = objc_getAssociatedObject(self, &kPageFlipTempViewKey); 74 | [containerView addSubview:toVC.view]; 75 | [UIView animateWithDuration:self.backDuration animations:^{ 76 | tempView.layer.transform = CATransform3DIdentity; 77 | fromVC.view.subviews.lastObject.alpha = 1.0; 78 | tempView.subviews.lastObject.alpha = 0.0; 79 | } completion:^(BOOL finished) { 80 | if ([transitionContext transitionWasCancelled]) { 81 | [transitionContext completeTransition:NO]; 82 | }else{ 83 | [transitionContext completeTransition:YES]; 84 | [tempView removeFromSuperview]; 85 | toVC.view.hidden = NO; 86 | } 87 | }]; 88 | } 89 | 90 | - (void)_xw_setAnchorPoint:(CGPoint)point forView:(UIView *)view{ 91 | view.frame = CGRectOffset(view.frame, (point.x - view.layer.anchorPoint.x) * view.frame.size.width, (point.y - view.layer.anchorPoint.y) * view.frame.size.height); 92 | view.layer.anchorPoint = point; 93 | } 94 | @end 95 | -------------------------------------------------------------------------------- /XWTransition/XWCircleSpreadAnimator/XWCircleSpreadAnimator.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCircleSpreadAnimator.m 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCircleSpreadAnimator.h" 10 | 11 | @interface XWCircleSpreadAnimator () 12 | @property (nonatomic, assign) CGPoint startPoint; 13 | @property (nonatomic, assign) CGFloat startRadius; 14 | @property (nonatomic, strong) UIBezierPath *startPath; 15 | @property (nonatomic, strong) UIView *containerView; 16 | @property (nonatomic, strong) CAShapeLayer *maskLayer; 17 | 18 | @end 19 | 20 | @implementation XWCircleSpreadAnimator 21 | 22 | + (instancetype)xw_animatorWithStartCenter:(CGPoint)point radius:(CGFloat)radius { 23 | return [[self alloc] _initWithStartCenter:point radius:radius]; 24 | } 25 | 26 | - (instancetype)_initWithStartCenter:(CGPoint)point radius:(CGFloat)radius 27 | { 28 | self = [super init]; 29 | if (self) { 30 | _startPoint = point; 31 | _startRadius = radius == 0 ? 0.01 : radius; 32 | self.needInteractiveTimer = YES; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)xw_setToAnimation:(id)transitionContext{ 38 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 39 | UIView *containerView = [transitionContext containerView]; 40 | [containerView addSubview:toVC.view]; 41 | UIBezierPath *startCycle = [UIBezierPath bezierPathWithArcCenter:self.startPoint radius:self.startRadius startAngle:0 endAngle:M_PI * 2 clockwise:YES]; 42 | CGFloat x = self.startPoint.x; 43 | CGFloat y = self.startPoint.y; 44 | CGFloat endX = MAX(x, containerView.frame.size.width - x); 45 | CGFloat endY = MAX(y, containerView.frame.size.height - y); 46 | CGFloat radius = sqrtf(pow(endX, 2) + pow(endY, 2)); 47 | UIBezierPath *endCycle = [UIBezierPath bezierPathWithArcCenter:self.startPoint radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES]; 48 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 49 | maskLayer.path = endCycle.CGPath; 50 | toVC.view.layer.mask = maskLayer; 51 | self.startPath = startCycle; 52 | self.maskLayer = maskLayer; 53 | self.containerView = containerView; 54 | CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; 55 | maskLayerAnimation.fromValue = (__bridge id)(startCycle.CGPath); 56 | maskLayerAnimation.toValue = (__bridge id)((endCycle.CGPath)); 57 | maskLayerAnimation.duration = self.toDuration; 58 | maskLayerAnimation.delegate = self; 59 | [maskLayerAnimation setValue:transitionContext forKey:@"transitionContext"]; 60 | [maskLayer addAnimation:maskLayerAnimation forKey:@"xw_path"]; 61 | } 62 | 63 | - (void)xw_setBackAnimation:(id)transitionContext{ 64 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 65 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 66 | UIView *containerView = [transitionContext containerView]; 67 | [containerView insertSubview:toVC.view atIndex:0]; 68 | UIBezierPath *endCycle = [UIBezierPath bezierPathWithArcCenter:self.startPoint radius:self.startRadius startAngle:0 endAngle:M_PI * 2 clockwise:YES]; 69 | CAShapeLayer *maskLayer = (CAShapeLayer *)fromVC.view.layer.mask; 70 | CGPathRef startPath = maskLayer.path; 71 | maskLayer.path = endCycle.CGPath; 72 | self.maskLayer = maskLayer; 73 | self.startPath = [UIBezierPath bezierPathWithCGPath:startPath]; 74 | self.containerView = containerView; 75 | CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; 76 | maskLayerAnimation.fromValue = (__bridge id)(startPath); 77 | maskLayerAnimation.toValue = (__bridge id)(endCycle.CGPath); 78 | maskLayerAnimation.duration = self.backDuration; 79 | maskLayerAnimation.delegate = self; 80 | [maskLayerAnimation setValue:transitionContext forKey:@"transitionContext"]; 81 | [maskLayer addAnimation:maskLayerAnimation forKey:@"xw_path"]; 82 | } 83 | 84 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ 85 | id transitionContext = [anim valueForKey:@"transitionContext"]; 86 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 87 | } 88 | 89 | - (void)xw_interactiveTransitionWillBeginTimerAnimation:(XWInteractiveTransition *)interactiveTransition{ 90 | _containerView.userInteractionEnabled = NO; 91 | } 92 | 93 | - (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition willEndWithSuccessFlag:(BOOL)flag percent:(CGFloat)percent{ 94 | if (!flag) { 95 | //防止失败后的闪烁 96 | _maskLayer.path = _startPath.CGPath; 97 | } 98 | _containerView.userInteractionEnabled = YES; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /XWTransition/Main/XWTransitionAnimator.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWTransitionAnimator.m 3 | // XWTADemo 4 | // 5 | // Created by wazrx on 16/6/7. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWTransitionAnimator.h" 10 | #import 11 | #import 12 | 13 | #pragma mark - 私有转场动画管理者 14 | 15 | typedef void(^XWTransitionAnimationConfig)(id transitionContext); 16 | 17 | @interface _XWTransitionObject : NSObject 18 | 19 | 20 | - (instancetype)_initObjectWithDuration:(NSTimeInterval)duration animationBlock:(void(^)(id transitionContext)) config; 21 | 22 | @end 23 | 24 | @implementation _XWTransitionObject{ 25 | NSTimeInterval _duration; 26 | XWTransitionAnimationConfig _config; 27 | } 28 | 29 | - (instancetype)_initObjectWithDuration:(NSTimeInterval)duration animationBlock:(XWTransitionAnimationConfig)config{ 30 | self = [super init]; 31 | if (self) { 32 | _duration = duration; 33 | _config = config; 34 | } 35 | return self; 36 | } 37 | 38 | #pragma mark - 39 | 40 | - (NSTimeInterval)transitionDuration:(id)transitionContext{ 41 | return _duration; 42 | } 43 | 44 | - (void)animateTransition:(id)transitionContext{ 45 | if (_config) { 46 | _config(transitionContext); 47 | } 48 | 49 | } 50 | 51 | @end 52 | 53 | @interface XWTransitionAnimator () 54 | @property (nonatomic, strong) _XWTransitionObject *toTransition; 55 | @property (nonatomic, strong) _XWTransitionObject *backTranstion; 56 | @property (nonatomic, strong) XWInteractiveTransition *toInteractive; 57 | @property (nonatomic, strong) XWInteractiveTransition *backInteractive; 58 | @property (nonatomic, assign) UINavigationControllerOperation operation; 59 | @property (nonatomic, assign) BOOL toType; 60 | 61 | @end 62 | 63 | @implementation XWTransitionAnimator 64 | 65 | 66 | - (instancetype)init 67 | { 68 | self = [super init]; 69 | if (self) { 70 | _toDuration = _backDuration = 0.5f; 71 | } 72 | return self; 73 | } 74 | 75 | - (_XWTransitionObject *)toTransition{ 76 | if (!_toTransition) { 77 | __weak typeof(self)weakSelf = self; 78 | _toTransition = [[_XWTransitionObject alloc] _initObjectWithDuration:_toDuration animationBlock:^(id transitionContext) { 79 | [weakSelf xw_setToAnimation:transitionContext]; 80 | }]; 81 | } 82 | return _toTransition; 83 | } 84 | 85 | - (_XWTransitionObject *)backTranstion{ 86 | if (!_backTranstion) { 87 | __weak typeof(self)weakSelf = self; 88 | _backTranstion = [[_XWTransitionObject alloc] _initObjectWithDuration:_backDuration animationBlock:^(id transitionContext) { 89 | [weakSelf xw_setBackAnimation:transitionContext]; 90 | }]; 91 | } 92 | return _backTranstion; 93 | } 94 | 95 | - (void)setToInteractive:(XWInteractiveTransition *)toInteractive{ 96 | _toInteractive = toInteractive; 97 | toInteractive.delegate = self; 98 | toInteractive.timerEable = _needInteractiveTimer; 99 | 100 | } 101 | 102 | - (void)setBackInteractive:(XWInteractiveTransition *)backInteractive{ 103 | _backInteractive = backInteractive; 104 | backInteractive.delegate = self; 105 | backInteractive.timerEable = _needInteractiveTimer; 106 | 107 | } 108 | 109 | - (void)xw_setToAnimation:(id)transitionContext{ 110 | //交给子类实现 111 | } 112 | 113 | - (void)xw_setBackAnimation:(id)transitionContext{ 114 | //交给子类实现 115 | } 116 | 117 | #pragma mark - 118 | 119 | - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{ 120 | return self.toTransition; 121 | } 122 | 123 | - (id)animationControllerForDismissedController:(UIViewController *)dismissed{ 124 | return self.backTranstion; 125 | } 126 | 127 | - (id)interactionControllerForDismissal:(id)animator{ 128 | return self.backInteractive.interation ? self.backInteractive : nil; 129 | } 130 | 131 | - (id)interactionControllerForPresentation:(id)animator{ 132 | return self.toInteractive.interation ? self.toInteractive : nil; 133 | } 134 | 135 | #pragma mark - 136 | 137 | - (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{ 138 | _operation = operation; 139 | return operation == UINavigationControllerOperationPush ? self.toTransition : self.backTranstion; 140 | } 141 | 142 | - (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id)animationController{ 143 | XWInteractiveTransition *inter = _operation == UINavigationControllerOperationPush ? self.toInteractive : self.backInteractive; 144 | return inter.interation ? inter : nil; 145 | } 146 | 147 | @end 148 | 149 | 150 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterTransitionView.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWBlurView.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterTransitionView.h" 10 | 11 | @interface _XWDisplayRatioLayer : CALayer 12 | 13 | @property (nonatomic, assign) CGFloat ratio; 14 | @property (nonatomic, copy) void(^ratioUpdating)(CGFloat ratio); 15 | 16 | @end 17 | 18 | @implementation _XWDisplayRatioLayer 19 | 20 | @dynamic ratio; 21 | 22 | + (BOOL)needsDisplayForKey:(NSString *)key{ 23 | if ([key isEqualToString:@"ratio"]) { 24 | return YES; 25 | } 26 | return [super needsDisplayForKey:key]; 27 | } 28 | 29 | - (void)display{ 30 | if (_ratioUpdating) { 31 | _ratioUpdating([[self presentationLayer] ratio]); 32 | } 33 | } 34 | 35 | @end 36 | 37 | @interface XWFilterTransitionView () 38 | @property (nonatomic, weak) _XWDisplayRatioLayer *ratioLayer; 39 | @property (nonatomic, assign) CGFloat ratio; 40 | @property (nonatomic, copy) CIImage *(^animationConfig)(CGFloat ratio, CIImage *fromImg, CIImage * toImg, CIFilter * filter); 41 | @property (nonatomic, copy) void(^completion)(BOOL finish); 42 | @property (nonatomic, assign) CGFloat lastRatio; 43 | 44 | @end 45 | 46 | @implementation XWFilterTransitionView{ 47 | CIImage *_fromImg; 48 | CIImage *_toImg; 49 | CIContext *_saveContext; 50 | CGRect _imgRect; 51 | CIVector *_vector; 52 | } 53 | 54 | - (instancetype)initWithFrame:(CGRect)frame 55 | fromImage:(UIImage *)fromImage 56 | toImage:(UIImage *)toImage{ 57 | self = [super initWithFrame:frame]; 58 | if (!self) return nil; 59 | _fromImg = [CIImage imageWithCGImage:fromImage.CGImage]; 60 | _toImg = [CIImage imageWithCGImage:toImage.CGImage]; 61 | _vector = [CIVector vectorWithX:0 Y:0 Z:fromImage.size.width * fromImage.scale W:fromImage.size.height * fromImage.scale]; 62 | CGFloat width = fromImage.size.width * fromImage.scale; 63 | CGFloat height = fromImage.size.height * fromImage.scale; 64 | _imgRect = CGRectMake(0, 0, width, height); 65 | self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 66 | _saveContext = [CIContext contextWithEAGLContext:self.context]; 67 | _XWDisplayRatioLayer *layer = [_XWDisplayRatioLayer new]; 68 | _ratioLayer = layer; 69 | _ratioLayer.frame = CGRectMake(0, 0, 100, 100); 70 | __weak typeof(self)weakSelf = self; 71 | _ratioLayer.ratioUpdating = ^(CGFloat ratio){ 72 | weakSelf.ratio = ratio; 73 | [weakSelf setNeedsDisplay]; 74 | }; 75 | [self.layer insertSublayer:_ratioLayer atIndex:0]; 76 | self.delegate = self; 77 | return self; 78 | } 79 | 80 | - (CAAnimation *)_xw_filterBasicAnimation{ 81 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"ratio"]; 82 | animation.fromValue = @0; 83 | animation.toValue = @1; 84 | return animation; 85 | } 86 | 87 | - (CIImage *)_xw_filterBasicImageForTransition 88 | { 89 | [_filter setValue:_fromImg forKey:kCIInputImageKey]; 90 | [_filter setValue:_toImg forKey:kCIInputTargetImageKey]; 91 | [_filter setValue:@(_ratio) forKey:kCIInputTimeKey]; 92 | CIImage *transitionImage = [_filter valueForKey:kCIOutputImageKey]; 93 | return transitionImage; 94 | } 95 | 96 | - (CIImage *)_xw_filterBlurImageForTransition{ 97 | CGFloat radius = 0; 98 | if (_ratio < 0.5) { 99 | [_filter setValue:_fromImg forKey:kCIInputImageKey]; 100 | radius = _ratio * 0.5 * 200; 101 | } 102 | else { 103 | [_filter setValue:_toImg forKey:kCIInputImageKey]; 104 | radius = (1.0 - _ratio) * 200; 105 | } 106 | [_filter setValue:@(radius) forKey:kCIInputRadiusKey]; 107 | CIImage *transitionImage = [_filter valueForKey:kCIOutputImageKey]; 108 | return transitionImage; 109 | } 110 | - (void)_xw_filterViewDoAnimation:(NSTimeInterval)duration completion:(void (^ __nullable)(BOOL finished))completion{ 111 | _completion = completion; 112 | CAAnimation *animation = [self _xw_filterBasicAnimation]; 113 | animation.duration = duration; 114 | animation.delegate = self; 115 | [_ratioLayer addAnimation:animation forKey:@"xw_filterAnimation"]; 116 | } 117 | 118 | #pragma mark - 119 | 120 | - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{ 121 | if (_ratio >= 1 || _ratio <= 0) { 122 | _ratio = _lastRatio > 0.5 ? 1 : 0; 123 | } 124 | if (!_filter) return; 125 | CIImage *image = _blurType ? [self _xw_filterBlurImageForTransition] : [self _xw_filterBasicImageForTransition]; 126 | if (!image) return; 127 | CGFloat scale = [[UIScreen mainScreen] scale]; 128 | CGRect nativeBounds = [[UIScreen mainScreen] nativeBounds]; 129 | CGRect destRect = CGRectMake(0, self.bounds.size.height * scale - _imgRect.size.height, 130 | nativeBounds.size.width, 131 | nativeBounds.size.height); 132 | [_saveContext drawImage:image 133 | inRect:destRect 134 | fromRect:_imgRect]; 135 | _lastRatio = _ratio; 136 | } 137 | 138 | 139 | #pragma mark - 140 | 141 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ 142 | if (_completion) { 143 | _completion(flag); 144 | } 145 | _completion = nil; 146 | } 147 | 148 | + (void)xw_animationWith:(XWFilterTransitionView *)filterView duration:(NSTimeInterval)duration completion:(void (^ __nullable)(BOOL finished))completion { 149 | [filterView _xw_filterViewDoAnimation:duration completion:completion]; 150 | } 151 | 152 | - (CAAnimation *)xw_getInnerAnimation { 153 | return [self _xw_filterBasicAnimation]; 154 | } 155 | 156 | - (CIVector *)xw_getInnerVector { 157 | return _vector; 158 | } 159 | @end 160 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWLines.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWVerticalLines.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/14. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator+XWLines.h" 10 | 11 | @implementation XWCoolAnimator (XWLines) 12 | 13 | static inline float XWRandomFloat(float max, float min){ 14 | return ((float)arc4random() / 0x100000000) * (max - min) + min; 15 | } 16 | 17 | - (void)xw_setLinesToAnimation:(id)transitionContext vertical:(BOOL)vertical { 18 | [self _xw_animateTransition:transitionContext duration:self.toDuration to:YES vertical:vertical]; 19 | 20 | } 21 | 22 | - (void)xw_setLinesBackAnimation:(id)transitionContext vertical:(BOOL)vertical { 23 | [self _xw_animateTransition:transitionContext duration:self.toDuration to:NO vertical:vertical]; 24 | 25 | } 26 | 27 | 28 | #define HLINEHEIGHT 4.0 29 | - (void)_xw_animateTransition:(id )transitionContext duration:(NSTimeInterval)duration to:(BOOL)flag vertical:(BOOL)vertical{ 30 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 31 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 32 | UIView *toView = toVC.view; 33 | UIView *containerView = [transitionContext containerView]; 34 | [containerView insertSubview:toView atIndex:0]; 35 | NSArray *outgoingLineViews = [self _xw_lineViews:fromVC.view intoSlicesOfDis:HLINEHEIGHT Offset:fromVC.view.frame.origin.y containerView:containerView vertical:vertical]; 36 | NSArray *incomingLineViews = [self _xw_lineViews:toView intoSlicesOfDis:HLINEHEIGHT Offset:toView.frame.origin.y containerView:containerView vertical:vertical]; 37 | CGFloat toViewStart = vertical ? toView.frame.origin.y : toView.frame.origin.x; 38 | BOOL presenting = flag; 39 | vertical ? [self _xw_repositionViewSlices:incomingLineViews moveFirstFrameUp:NO]:[self _xw_repositionViewSlices:incomingLineViews moveLeft:!presenting]; 40 | fromVC.view.hidden = YES; 41 | toView.hidden = YES; 42 | [UIView animateWithDuration:duration - 0.01 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ 43 | vertical ? [self _xw_repositionViewSlices:outgoingLineViews moveFirstFrameUp:YES] : [self _xw_repositionViewSlices:outgoingLineViews moveLeft:presenting]; 44 | [self _xw_resetViewSlices:incomingLineViews toOrigin:toViewStart vertical:vertical]; 45 | } completion:^(BOOL finished) { 46 | fromVC.view.hidden = NO; 47 | toView.hidden = NO; 48 | [toView setNeedsUpdateConstraints]; 49 | for (UIView *v in incomingLineViews) { 50 | [v removeFromSuperview]; 51 | } 52 | for (UIView *v in outgoingLineViews) { 53 | [v removeFromSuperview]; 54 | } 55 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 56 | }]; 57 | } 58 | 59 | - (UIImage *)_xw_ImageFromsnapshotView:(UIView *)view{ 60 | CALayer *layer = view.layer; 61 | UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.opaque, 0); 62 | CGContextRef context = UIGraphicsGetCurrentContext(); 63 | [layer renderInContext:context]; 64 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 65 | UIGraphicsEndImageContext(); 66 | return image; 67 | } 68 | 69 | //弃用了原作者的截取若干小图的方法,由于toView刚开始无法截图,原作者采用延迟0.001秒后来截图,但是这种方式不是对手势和转场失败的效果有很大的干扰,所以我转换思路换了一种方式实现了小图,采用的是contentsRect 70 | - (NSArray *)_xw_lineViews:(UIView *)view intoSlicesOfDis:(float)dis Offset:(float)yOffset containerView:(UIView *)containerView vertical:(BOOL)vertical{ 71 | CGFloat width = vertical ? CGRectGetHeight(view.frame) : CGRectGetWidth(view.frame); 72 | CGFloat height = !vertical ? CGRectGetHeight(view.frame) : CGRectGetWidth(view.frame); 73 | UIImage *img = [self _xw_ImageFromsnapshotView:view]; 74 | NSMutableArray *lineViews = [NSMutableArray array]; 75 | for (int i = 0; i < height; i += dis) { 76 | CGRect subrect = vertical ? CGRectMake(i, 0, dis, width) : CGRectMake(0, i, width, dis); 77 | UIView *subsnapshot = [UIView new]; 78 | subsnapshot.layer.contents= (__bridge id)img.CGImage; 79 | subsnapshot.layer.contentsRect = vertical ? CGRectMake((float)i / view.frame.size.width, 0.0, dis / view.frame.size.width, 1.0) : CGRectMake(0, (float)i / view.frame.size.height, 1.0, dis / view.frame.size.height); 80 | subrect.origin.x += yOffset; 81 | subsnapshot.frame = subrect; 82 | [lineViews addObject:subsnapshot]; 83 | [containerView addSubview:subsnapshot]; 84 | } 85 | return lineViews; 86 | } 87 | 88 | 89 | -(void)_xw_repositionViewSlices:(NSArray *)views moveLeft:(BOOL)left{ 90 | CGRect frame; 91 | float width; 92 | for (UIView *line in views) { 93 | frame = line.frame; 94 | width = CGRectGetWidth(frame) * XWRandomFloat(1.0, 8.0); 95 | frame.origin.x += (left)?-width:width; 96 | line.frame = frame; 97 | } 98 | } 99 | 100 | -(void)_xw_repositionViewSlices:(NSArray *)views moveFirstFrameUp:(BOOL)startUp{ 101 | 102 | BOOL up = startUp; 103 | CGRect frame; 104 | float height; 105 | for (UIView *line in views) { 106 | frame = line.frame; 107 | height = CGRectGetHeight(frame) * XWRandomFloat(1.0, 4.0); 108 | frame.origin.y += (up)?-height:height; 109 | line.frame = frame; 110 | 111 | up = !up; 112 | } 113 | } 114 | 115 | -(void)_xw_resetViewSlices:(NSArray *)views toOrigin:(CGFloat)o vertical:(BOOL)vertical{ 116 | CGRect frame; 117 | for (UIView *line in views) { 118 | frame = line.frame; 119 | if (vertical) { 120 | frame.origin.y = o; 121 | }else{ 122 | frame.origin.x = o; 123 | } 124 | line.frame = frame; 125 | } 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWPortal.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWPortal.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/16. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator+XWPortal.h" 10 | #import "UIView+Snapshot.h" 11 | 12 | @implementation XWCoolAnimator (XWPortal) 13 | 14 | 15 | - (void)xw_setPortalToAnimation:(id)transitionContext { 16 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 17 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 18 | UIView *toView = toVC.view; 19 | UIView *fromView = fromVC.view; 20 | UIView *containerView = [transitionContext containerView]; 21 | UIView *toViewSnapshot = [UIView new]; 22 | toViewSnapshot.contentImage = toView.snapshotImage; 23 | toViewSnapshot.frame = containerView.bounds; 24 | CATransform3D scale = CATransform3DIdentity; 25 | toViewSnapshot.layer.transform = CATransform3DScale(scale, 0.8, 0.8, 1); 26 | [containerView addSubview:toViewSnapshot]; 27 | [containerView sendSubviewToBack:toViewSnapshot]; 28 | CGRect leftSnapshotRegion = CGRectMake(0, 0, fromView.frame.size.width / 2, fromView.frame.size.height); 29 | UIView *leftHandView = [UIView new]; 30 | leftHandView.contentImage = fromView.snapshotImage; 31 | leftHandView.layer.contentsRect = CGRectMake(0, 0, 0.5, 1.0); 32 | leftHandView.frame = leftSnapshotRegion; 33 | [containerView addSubview:leftHandView]; 34 | CGRect rightSnapshotRegion = CGRectMake(fromView.frame.size.width / 2, 0, fromView.frame.size.width / 2, fromView.frame.size.height); 35 | UIView *rightHandView = [UIView new]; 36 | rightHandView.contentImage = leftHandView.contentImage; 37 | rightHandView.layer.contentsRect = CGRectMake(0.5, 0, 0.5, 1.0); 38 | rightHandView.frame = rightSnapshotRegion; 39 | [containerView addSubview:rightHandView]; 40 | fromView.hidden = YES; 41 | [UIView animateWithDuration:self.toDuration 42 | delay:0.0 43 | options:UIViewAnimationOptionCurveEaseOut 44 | animations:^{ 45 | leftHandView.frame = CGRectOffset(leftHandView.frame, - leftHandView.frame.size.width, 0); 46 | rightHandView.frame = CGRectOffset(rightHandView.frame, rightHandView.frame.size.width, 0); 47 | toViewSnapshot.center = toView.center; 48 | toViewSnapshot.frame = toView.frame; 49 | } completion:^(BOOL finished) { 50 | fromView.hidden = NO; 51 | if ([transitionContext transitionWasCancelled]) { 52 | [containerView addSubview:fromView]; 53 | [self _xw_removeOtherViews:fromView]; 54 | } else { 55 | [containerView addSubview:toView]; 56 | [self _xw_removeOtherViews:toView]; 57 | } 58 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 59 | }]; 60 | } 61 | 62 | - (void)xw_setPortalBackAnimation:(id)transitionContext { 63 | 64 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 65 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 66 | UIView *toView = toVC.view; 67 | UIView *fromView = fromVC.view; 68 | UIView *containerView = [transitionContext containerView]; 69 | [containerView addSubview:fromView]; 70 | toView.frame = [transitionContext finalFrameForViewController:toVC]; 71 | toView.frame = CGRectOffset(toView.frame, toView.frame.size.width, 0); 72 | [containerView addSubview:toView]; 73 | CGRect leftSnapshotRegion = CGRectMake(0, 0, toView.frame.size.width / 2, toView.frame.size.height); 74 | UIView *leftHandView = [UIView new]; 75 | leftHandView.contentImage = toView.snapshotImage; 76 | leftHandView.layer.contentsRect = CGRectMake(0, 0, 0.5, 1.0); 77 | leftHandView.frame = leftSnapshotRegion; 78 | leftHandView.frame = CGRectOffset(leftHandView.frame, - leftHandView.frame.size.width, 0); 79 | [containerView addSubview:leftHandView]; 80 | CGRect rightSnapshotRegion = CGRectMake(toView.frame.size.width / 2, 0, toView.frame.size.width / 2, toView.frame.size.height); 81 | UIView *rightHandView = [UIView new]; 82 | rightHandView.contentImage = leftHandView.contentImage; 83 | rightHandView.layer.contentsRect = CGRectMake(0.5, 0, 0.5, 1.0); 84 | rightHandView.frame = rightSnapshotRegion; 85 | rightHandView.frame = CGRectOffset(rightHandView.frame, rightHandView.frame.size.width, 0); 86 | [containerView addSubview:rightHandView]; 87 | [UIView animateWithDuration:self.backDuration 88 | delay:0.0 89 | options:UIViewAnimationOptionCurveEaseOut 90 | animations:^{ 91 | leftHandView.frame = CGRectOffset(leftHandView.frame, leftHandView.frame.size.width, 0); 92 | rightHandView.frame = CGRectOffset(rightHandView.frame, - rightHandView.frame.size.width, 0); 93 | CATransform3D scale = CATransform3DIdentity; 94 | fromView.layer.transform = CATransform3DScale(scale, 0.8, 0.8, 1); 95 | } completion:^(BOOL finished) { 96 | if ([transitionContext transitionWasCancelled]) { 97 | [self _xw_removeOtherViews:fromView]; 98 | } else { 99 | [self _xw_removeOtherViews:toView]; 100 | toView.frame = containerView.bounds; 101 | } 102 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 103 | }]; 104 | } 105 | 106 | - (void)_xw_removeOtherViews:(UIView*)viewToKeep { 107 | UIView *containerView = viewToKeep.superview; 108 | for (UIView *view in containerView.subviews) { 109 | if (view != viewToKeep) { 110 | [view removeFromSuperview]; 111 | } 112 | } 113 | } 114 | @end 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XWTransition 2 | 3 | ###是什么 4 | XWTransition是用来帮助你快速集成自定义转场的工具,使用它你无需关注转场的逻辑和长长的delegate方法,只需要选择相应效果的转场效果器,然后几乎就像以前的push和present操作一样进行转场工作,当然你也可以很简单自定义自己的效果器完成你独特的转场创意而无需关注转场逻辑,你只需要专心关注你的动画逻辑即可,其它的东西都已经为你处理好了 5 | 6 | ###效果图(可下载demo真机运行效果更好) 7 | 截图中,左上角的开关代表push和present,所有效果都支持手势,我就不一一演示了 8 | 9 | 1、CircleSpreadTransition 小圆点扩散 10 | 11 | ![CircleSpreadTransition.gif](http://upload-images.jianshu.io/upload_images/1154055-15cbfb7aefe2efcc.gif?imageMogr2/auto-orient/strip) 12 | 13 | 2、MagicMoveTransition 神奇移动 14 | 15 | 16 | ![MagicMoveTransition1.gif](http://upload-images.jianshu.io/upload_images/1154055-7f2a7f9ff4590611.gif?imageMogr2/auto-orient/strip) 17 | ![MagicMoveTransition2.gif](http://upload-images.jianshu.io/upload_images/1154055-3593e3b356bcf1de.gif?imageMogr2/auto-orient/strip) 18 | 19 | 3、XWDrawerAnimator 抽屉效果,仿照QQ和淘宝 20 | 21 | ![XWDrawerAnimator1.gif](http://upload-images.jianshu.io/upload_images/1154055-7ce100b7d8de68d0.gif?imageMogr2/auto-orient/strip) 22 | ![XWDrawerAnimator2.gif](http://upload-images.jianshu.io/upload_images/1154055-a955134f8fc57edd.gif?imageMogr2/auto-orient/strip) 23 | 24 | 4、XWCoolAnimator 自定义一些效果 25 | 26 | ![XWCoolAnimator2.gif](http://upload-images.jianshu.io/upload_images/1154055-b91aaa380658aea2.gif?imageMogr2/auto-orient/strip) 27 | ![XWCoolAnimator1.gif](http://upload-images.jianshu.io/upload_images/1154055-11463b1600954cbf.gif?imageMogr2/auto-orient/strip) 28 | ![XWCoolAnimator3.gif](http://upload-images.jianshu.io/upload_images/1154055-865c860ae815dee3.gif?imageMogr2/auto-orient/strip) 29 | ![XWCoolAnimator4.gif](http://upload-images.jianshu.io/upload_images/1154055-4427d7a13724cab2.gif?imageMogr2/auto-orient/strip) 30 | ![XWCoolAnimator5.gif](http://upload-images.jianshu.io/upload_images/1154055-16bb0fb9435edaa2.gif?imageMogr2/auto-orient/strip) 31 | ![XWCoolAnimator6.gif](http://upload-images.jianshu.io/upload_images/1154055-7005cabfc86bff65.gif?imageMogr2/auto-orient/strip) 32 | ![XWCoolAnimator7.gif](http://upload-images.jianshu.io/upload_images/1154055-491415eac763bd58.gif?imageMogr2/auto-orient/strip) 33 | 34 | 5、XWFilterAnimator 通过CIFilter滤镜自定义一些效果,请在真机上运行 35 | 36 | ![XWFilterAnimator1.gif](http://upload-images.jianshu.io/upload_images/1154055-de1a3e6ca1ce5c7a.gif?imageMogr2/auto-orient/strip) 37 | ![XWFilterAnimator6.gif](http://upload-images.jianshu.io/upload_images/1154055-9f3805ba6198ac2b.gif?imageMogr2/auto-orient/strip) 38 | ![XWFilterAnimator5.gif](http://upload-images.jianshu.io/upload_images/1154055-d98e03b7a08e8352.gif?imageMogr2/auto-orient/strip) 39 | ![XWFilterAnimator4.gif](http://upload-images.jianshu.io/upload_images/1154055-b3ff2938f4079bd9.gif?imageMogr2/auto-orient/strip) 40 | ![XWFilterAnimator3.gif](http://upload-images.jianshu.io/upload_images/1154055-931ca82d418e3801.gif?imageMogr2/auto-orient/strip) 41 | ![XWFilterAnimator2.gif](http://upload-images.jianshu.io/upload_images/1154055-2aa75294d5097e20.gif?imageMogr2/auto-orient/strip) 42 | ![XWFilterAnimator8.gif](http://upload-images.jianshu.io/upload_images/1154055-adbaa9592d501e00.gif?imageMogr2/auto-orient/strip) 43 | ![XWFilterAnimator7.gif](http://upload-images.jianshu.io/upload_images/1154055-50bb0975c6fc4801.gif?imageMogr2/auto-orient/strip) 44 | 45 | ###基本使用 46 | 47 | 1、clone后将XWTranstion文件夹导入工程 48 | 49 | 2、导入`UINavigationController+XWTransition.h`或者`UIViewController+XWTransition.h`两个分类 50 | 51 | 3、选择你需要的效果器进行根据初始化方法进行初始化,比如下面的小圆点扩散,初始化指定开始圆心和半径 52 | 53 | ``` 54 | XWCircleSpreadAnimator *animator = [XWCircleSpreadAnimator xw_animatorWithStartCenter:self.button.center radius:20]; 55 | 56 | ``` 57 | 58 | 4、通过初始化的效果器转场,根据分类提供两个方法进行push或者present,就完成了! 59 | 60 | ``` 61 | /** 62 | * 通过指定的转场animator来push控制器,达到不同的转场效果 63 | * 64 | * @param viewController 被push的控制器 65 | * @param animator 转场Animator 66 | */ 67 | - (void)xw_pushViewController:(UIViewController *)viewController withAnimator:(XWTransitionAnimator *)animator; 68 | 69 | /** 70 | * 通过指定的转场animator来present控制器 71 | * 72 | * @param viewController 被modal出的控制器 73 | * @param animator 转场animator 74 | */ 75 | - (void)xw_presentViewController:(UIViewController *)viewController withAnimator:(XWTransitionAnimator *)animator; 76 | 77 | //事例代码如下 78 | [self.navigationController xw_pushViewController:toVC withAnimator:animator]; 79 | 或者 80 | [self xw_presentViewController:toVC withAnimator:animator]; 81 | 82 | ``` 83 | 84 | ###手势驱动(所有的效果都支持手势驱动) 85 | 1、在`UIViewController+XWTransition.h`分类中提供了两个方法,用来注册手势驱动,在viewDidLoad的时候调用注册手势就可以了,详见demo,注意避免循环引用,手势支持边缘属性 86 | 87 | ``` 88 | /** 89 | * 注册to手势(push或者Present手势) 90 | * 91 | * @param direction 手势方向 92 | * @param tansitionConfig 手势触发的block,block中需要包含你的push或者Present的逻辑代码,注意避免循环引用问题 93 | * @param edgeSpacing 手势触发的边缘距离,该值为0,表示在整个控制器视图上都有效,否者这在边缘的edgeSpacing之类有效 94 | */ 95 | 96 | - (void)xw_registerToInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(dispatch_block_t)tansitionConfig edgeSpacing:(CGFloat)edgeSpacing; 97 | 98 | /** 99 | * 注册back手势(pop或者dismiss手势) 100 | * 101 | * @param direction 手势方向 102 | * @param tansitionConfig 手势触发的block,block中需要包含你的pop或者dismiss的逻辑代码,注意避免循环引用问题 103 | * @param edgeSpacing 手势触发的边缘距离,该值为0,表示在整个控制器视图上都有效,否者这在边缘的edgeSpacing之类有效 104 | */ 105 | 106 | - (void)xw_registerBackInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction transitonBlock:(dispatch_block_t)tansitionConfig edgeSpacing:(CGFloat)edgeSpacing; 107 | 108 | ``` 109 | 110 | 2、事例代码 111 | 112 | ``` 113 | __weak typeof(self)weakSelf = self; 114 | //注册一个全屏的back转场 115 | [self xw_registerBackInteractiveTransitionWithDirection:XWInteractiveTransitionGestureDirectionDown transitonBlock:^{ 116 | //pop或者dismiss操作 117 | [weakSelf xw_transiton]; 118 | } edgeSpacing:0]; 119 | 120 | ``` 121 | 122 | 123 | ###关于自定义转场效果 124 | 你只需要继承于`XWTransitionAnimator`,就像内置实现的所有效果器一样,然后复写需要的属性和两个必须的方法即可,然后你就可以使用你自定义的效果器转场,`XWTransitionAnimator`头文件如下: 125 | 126 | ``` 127 | @interface XWTransitionAnimator : NSObject 128 | 129 | //to转场时间 默认0.5 130 | @property (nonatomic, assign) NSTimeInterval toDuration; 131 | //back转场时间 默认0.5 132 | @property (nonatomic, assign) NSTimeInterval backDuration; 133 | //是否需要开启手势timer,某些转场如果在转成过程中所开手指,不会有动画过渡,显得很生硬,开启timer后,松开手指,会用timer不断的刷新转场百分比,消除生硬的缺点 134 | @property (nonatomic, assign) BOOL needInteractiveTimer; 135 | 136 | /** 137 | * 配置To过程动画(push, present),自定义转场动画应该复写该方法 138 | */ 139 | - (void)xw_setToAnimation:(id)transitionContext; 140 | /** 141 | * 配置back过程动画(pop, dismiss),自定义转场动画应该复写该方法 142 | */ 143 | - (void)xw_setBackAnimation:(id)transitionContext; 144 | 145 | @end 146 | ``` 147 | 148 | ####更多原理和使用细节请前往我的简书博客:[几句代码快速集成自定义转场效果+ 全手势驱动](http://www.jianshu.com/p/e498b956491c) 149 | 150 | 151 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator.h" 10 | #import "XWCoolAnimator+XWPortal.h" 11 | #import "XWCoolAnimator+XWPageFlip.h" 12 | #import "XWCoolAnimator+XWFold.h" 13 | #import "XWCoolAnimator+XWMiddlePageFlip.h" 14 | #import "XWCoolAnimator+XWExplode.h" 15 | #import "XWCoolAnimator+XWLines.h" 16 | #import "XWCoolAnimator+XWScanning.h" 17 | 18 | @interface XWCoolAnimator () 19 | @property (nonatomic, weak) UIView *pageFlipTempView; 20 | @end 21 | 22 | @implementation XWCoolAnimator{ 23 | XWCoolTransitionAnimatorType _type; 24 | } 25 | 26 | - (void)dealloc{ 27 | NSLog(@"coolAnimator销毁了"); 28 | } 29 | 30 | 31 | + (instancetype)xw_animatorWithType:(XWCoolTransitionAnimatorType)type { 32 | return [[self alloc] _initWithTransitionType:type]; 33 | } 34 | 35 | - (instancetype)_initWithTransitionType:(XWCoolTransitionAnimatorType)type{ 36 | self = [super init]; 37 | if (self) { 38 | _type = type; 39 | _foldCount = 4; 40 | } 41 | return self; 42 | } 43 | 44 | 45 | 46 | - (void)xw_setToAnimation:(id)transitionContext{ 47 | switch (_type) { 48 | case XWCoolTransitionAnimatorTypePageFlip: { 49 | [self xw_setPageFlipToAnimation:transitionContext]; 50 | break; 51 | } 52 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromLeft: { 53 | [self xw_setMiddlePageFlipToAnimation:transitionContext direction:XWMiddlePageFlipDirectionLeft]; 54 | break; 55 | } 56 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromRight: { 57 | [self xw_setMiddlePageFlipToAnimation:transitionContext direction:XWMiddlePageFlipDirectionRight]; 58 | break; 59 | } 60 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromTop: { 61 | [self xw_setMiddlePageFlipToAnimation:transitionContext direction:XWMiddlePageFlipDirectionTop]; 62 | break; 63 | } 64 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromBottom: { 65 | [self xw_setMiddlePageFlipToAnimation:transitionContext direction:XWMiddlePageFlipDirectionBottom]; 66 | break; 67 | } 68 | case XWCoolTransitionAnimatorTypePortal: { 69 | [self xw_setPortalToAnimation:transitionContext]; 70 | break; 71 | } 72 | case XWCoolTransitionAnimatorTypeFoldFromLeft: { 73 | [self xw_setFoldToAnimation:transitionContext leftFlag:YES]; 74 | break; 75 | } 76 | case XWCoolTransitionAnimatorTypeFoldFromRight: { 77 | [self xw_setFoldToAnimation:transitionContext leftFlag:NO]; 78 | break; 79 | } 80 | case XWCoolTransitionAnimatorTypeExplode: { 81 | [self xw_setExplodeToAnimation:transitionContext]; 82 | break; 83 | } 84 | case XWCoolTransitionAnimatorTypeHorizontalLines: { 85 | [self xw_setLinesToAnimation:transitionContext vertical:NO]; 86 | break; 87 | } 88 | case XWCoolTransitionAnimatorTypeVerticalLines: { 89 | [self xw_setLinesToAnimation:transitionContext vertical:YES]; 90 | break; 91 | } 92 | case XWCoolTransitionAnimatorTypeScanningFromLeft: { 93 | [self xw_setScanningToAnimation:transitionContext direction:0]; 94 | break; 95 | } 96 | case XWCoolTransitionAnimatorTypeScanningFromRight: { 97 | [self xw_setScanningToAnimation:transitionContext direction:1]; 98 | break; 99 | } 100 | case XWCoolTransitionAnimatorTypeScanningFromTop: { 101 | [self xw_setScanningToAnimation:transitionContext direction:2]; 102 | break; 103 | } 104 | case XWCoolTransitionAnimatorTypeScanningFromBottom: { 105 | [self xw_setScanningToAnimation:transitionContext direction:3]; 106 | break; 107 | } 108 | } 109 | } 110 | 111 | - (void)xw_setBackAnimation:(id)transitionContext{ 112 | switch (_type) { 113 | case XWCoolTransitionAnimatorTypePageFlip: { 114 | [self xw_setPageFlipBackAnimation:transitionContext]; 115 | break; 116 | } 117 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromLeft: { 118 | [self xw_setMiddlePageFlipBackAnimation:transitionContext direction:XWMiddlePageFlipDirectionRight]; 119 | break; 120 | } 121 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromRight: { 122 | [self xw_setMiddlePageFlipBackAnimation:transitionContext direction:XWMiddlePageFlipDirectionLeft]; 123 | break; 124 | } 125 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromTop: { 126 | [self xw_setMiddlePageFlipBackAnimation:transitionContext direction:XWMiddlePageFlipDirectionBottom]; 127 | break; 128 | } 129 | case XWCoolTransitionAnimatorTypePageMiddleFlipFromBottom: { 130 | [self xw_setMiddlePageFlipBackAnimation:transitionContext direction:XWMiddlePageFlipDirectionTop]; 131 | break; 132 | } 133 | case XWCoolTransitionAnimatorTypePortal: { 134 | [self xw_setPortalBackAnimation:transitionContext]; 135 | break; 136 | } 137 | case XWCoolTransitionAnimatorTypeFoldFromLeft: { 138 | [self xw_setFoldBackAnimation:transitionContext leftFlag:NO]; 139 | break; 140 | } 141 | case XWCoolTransitionAnimatorTypeFoldFromRight: { 142 | [self xw_setFoldBackAnimation:transitionContext leftFlag:YES]; 143 | break; 144 | } 145 | case XWCoolTransitionAnimatorTypeExplode: { 146 | [self xw_setExplodeBackAnimation:transitionContext]; 147 | break; 148 | } 149 | case XWCoolTransitionAnimatorTypeHorizontalLines: { 150 | [self xw_setLinesBackAnimation:transitionContext vertical:NO]; 151 | break; 152 | } 153 | case XWCoolTransitionAnimatorTypeVerticalLines: { 154 | [self xw_setLinesBackAnimation:transitionContext vertical:YES]; 155 | break; 156 | } 157 | case XWCoolTransitionAnimatorTypeScanningFromLeft: { 158 | [self xw_setScanningBackAnimation:transitionContext direction:1]; 159 | break; 160 | } 161 | case XWCoolTransitionAnimatorTypeScanningFromRight: { 162 | [self xw_setScanningBackAnimation:transitionContext direction:0]; 163 | break; 164 | } 165 | case XWCoolTransitionAnimatorTypeScanningFromTop: { 166 | [self xw_setScanningBackAnimation:transitionContext direction:3]; 167 | break; 168 | } 169 | case XWCoolTransitionAnimatorTypeScanningFromBottom: { 170 | [self xw_setScanningBackAnimation:transitionContext direction:2]; 171 | break; 172 | } 173 | } 174 | } 175 | 176 | 177 | 178 | 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /XWTransition/XWFilterAnimator/XWFilterAnimator.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWFilterAnimator.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/17. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWFilterAnimator.h" 10 | #import "XWFilterAnimator+XWBoxBlur.h" 11 | #import "XWFilterAnimator+XWSwipe.h" 12 | #import "XWFilterAnimator+XWBarSwipe.h" 13 | #import "XWFilterAnimator+XWMask.h" 14 | #import "XWFilterAnimator+XWFlash.h" 15 | #import "XWFilterAnimator+XWMod.h" 16 | #import "XWFilterAnimator+XWPageCurl.h" 17 | #import "XWFilterAnimator+XWRipple.h" 18 | #import "XWFilterAnimator+XWCopyMachine.h" 19 | 20 | @implementation XWFilterAnimator{ 21 | UIView *_containerView; 22 | XWFilterAnimatorType _type; 23 | } 24 | 25 | 26 | 27 | + (instancetype)xw_animatorWithType:(XWFilterAnimatorType)type { 28 | return[[self alloc] _initWithType:type]; 29 | } 30 | 31 | - (instancetype)_initWithType:(XWFilterAnimatorType)type{ 32 | self = [super init]; 33 | if (self) { 34 | _type = type; 35 | self.needInteractiveTimer = YES; 36 | _revers = YES; 37 | } 38 | return self; 39 | } 40 | 41 | - (void)xw_setToAnimation:(id)transitionContext{ 42 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 43 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 44 | UIView *containerView = [transitionContext containerView]; 45 | _containerView = containerView; 46 | [containerView addSubview:toVC.view]; 47 | XWFilterTransitionView *filterView = [[XWFilterTransitionView alloc] initWithFrame:containerView.bounds fromImage:[self xw_ImageFromsnapshotView:fromVC.view] toImage:[self xw_ImageFromsnapshotView:toVC.view]]; 48 | switch (_type) { 49 | case XWFilterAnimatorTypeBoxBlur: { 50 | [self xw_boxBlurAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration]; 51 | break; 52 | } 53 | case XWFilterAnimatorTypeSwipe: { 54 | [self xw_swipeAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration toFlag:YES]; 55 | break; 56 | } 57 | case XWFilterAnimatorTypeBarSwipe:{ 58 | [self xw_barSwipeAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration toFlag:YES]; 59 | break; 60 | } 61 | case XWFilterAnimatorTypeMask:{ 62 | [self xw_maskAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration]; 63 | break; 64 | } 65 | case XWFilterAnimatorTypeFlash:{ 66 | [self xw_flashAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration]; 67 | break; 68 | } 69 | case XWFilterAnimatorTypeMod:{ 70 | [self xw_modAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration toFlag:YES]; 71 | break; 72 | } 73 | case XWFilterAnimatorTypePageCurl:{ 74 | [self xw_pageCurlAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration toFlag:YES]; 75 | break; 76 | } 77 | case XWFilterAnimatorTypeRipple:{ 78 | [self xw_rippleAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration]; 79 | break; 80 | } 81 | case XWFilterAnimatorTypeCopyMachine:{ 82 | [self xw_copyMachineAnimationFor:filterView transitionContext:transitionContext duration:self.toDuration toFlag:YES]; 83 | break; 84 | } 85 | } 86 | [containerView addSubview:filterView]; 87 | } 88 | 89 | - (void)xw_setBackAnimation:(id)transitionContext{ 90 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 91 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 92 | UIView *containerView = [transitionContext containerView]; 93 | [containerView insertSubview:toVC.view atIndex:0]; 94 | _containerView = containerView; 95 | XWFilterTransitionView *filterView = [[XWFilterTransitionView alloc] initWithFrame:containerView.bounds fromImage:[self xw_ImageFromsnapshotView:fromVC.view] toImage:[self xw_ImageFromsnapshotView:toVC.view]]; 96 | switch (_type) { 97 | case XWFilterAnimatorTypeBoxBlur: { 98 | [self xw_boxBlurAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration]; 99 | break; 100 | } 101 | case XWFilterAnimatorTypeSwipe: { 102 | [self xw_swipeAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration toFlag:NO]; 103 | break; 104 | } 105 | case XWFilterAnimatorTypeBarSwipe:{ 106 | [self xw_barSwipeAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration toFlag:NO]; 107 | break; 108 | } 109 | case XWFilterAnimatorTypeMask:{ 110 | [self xw_maskAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration]; 111 | break; 112 | } 113 | case XWFilterAnimatorTypeFlash:{ 114 | [self xw_flashAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration]; 115 | break; 116 | } 117 | case XWFilterAnimatorTypeMod:{ 118 | [self xw_modAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration toFlag:NO]; 119 | break; 120 | } 121 | case XWFilterAnimatorTypePageCurl:{ 122 | [self xw_pageCurlAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration toFlag:NO]; 123 | break; 124 | } 125 | case XWFilterAnimatorTypeRipple:{ 126 | [self xw_rippleAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration]; 127 | break; 128 | } 129 | case XWFilterAnimatorTypeCopyMachine:{ 130 | [self xw_copyMachineAnimationFor:filterView transitionContext:transitionContext duration:self.backDuration toFlag:NO]; 131 | break; 132 | } 133 | } 134 | [containerView addSubview:filterView]; 135 | } 136 | 137 | - (UIImage *)xw_ImageFromsnapshotView:(UIView *)view{ 138 | CALayer *layer = view.layer; 139 | UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.opaque, 0); 140 | CGContextRef context = UIGraphicsGetCurrentContext(); 141 | [layer renderInContext:context]; 142 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 143 | UIGraphicsEndImageContext(); 144 | return image; 145 | } 146 | 147 | - (void)xw_interactiveTransitionWillBeginTimerAnimation:(XWInteractiveTransition *)interactiveTransition{ 148 | _containerView.userInteractionEnabled = NO; 149 | } 150 | 151 | - (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition willEndWithSuccessFlag:(BOOL)flag percent:(CGFloat)percent{ 152 | _containerView.userInteractionEnabled = YES; 153 | } 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWFold.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWFold.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator+XWFold.h" 10 | #import "UIView+Snapshot.h" 11 | 12 | @implementation XWCoolAnimator (XWFold) 13 | 14 | - (void)xw_setFoldToAnimation:(id)transitionContext leftFlag:(BOOL)left { 15 | [self _xw_animation:transitionContext flag:left duration:self.toDuration]; 16 | 17 | } 18 | 19 | - (void)xw_setFoldBackAnimation:(id)transitionContext leftFlag:(BOOL)left { 20 | [self _xw_animation:transitionContext flag:left duration:self.backDuration]; 21 | 22 | } 23 | 24 | - (void)_xw_animation:(id)transitionContext flag:(BOOL)flag duration:(NSTimeInterval)duration{ 25 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 26 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 27 | UIView *toView = toVC.view; 28 | UIView *fromView = fromVC.view; 29 | UIView *containerView = [transitionContext containerView]; 30 | toView.frame = [transitionContext finalFrameForViewController:toVC]; 31 | toView.frame = CGRectOffset(toView.frame, toView.frame.size.width, 0); 32 | [containerView addSubview:toView]; 33 | CATransform3D transform = CATransform3DIdentity; 34 | transform.m34 = -0.005; 35 | containerView.layer.sublayerTransform = transform; 36 | CGSize size = toView.frame.size; 37 | float foldWidth = size.width * 0.5 / (float)self.foldCount ; 38 | NSMutableArray* fromViewFolds = [NSMutableArray new]; 39 | NSMutableArray* toViewFolds = [NSMutableArray new]; 40 | UIImage *fromImage = fromView.snapshotImage; 41 | UIImage *toImage = toView.snapshotImage; 42 | for (int i=0 ;i 11 | 12 | static NSString *const kXWMagicMovePropertyInViewKey = @"kXWMagicMovePropertyInViewKey"; 13 | 14 | @implementation UIView (XWTransition) 15 | 16 | - (void)setMagicMoveImageMode:(BOOL)magicMoveImageMode{ 17 | objc_setAssociatedObject(self, &kXWMagicMovePropertyInViewKey, @(magicMoveImageMode), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 18 | } 19 | 20 | - (BOOL)magicMoveImageMode{ 21 | return [objc_getAssociatedObject(self, &kXWMagicMovePropertyInViewKey) boolValue]; 22 | } 23 | 24 | 25 | @end 26 | 27 | @implementation XWMagicMoveAnimator 28 | 29 | - (void)xw_setToAnimation:(id)transitionContext{ 30 | [self _xw_doAniamtionWithContext:transitionContext fromFlag:YES]; 31 | 32 | } 33 | 34 | - (void)xw_setBackAnimation:(id)transitionContext{ 35 | [self _xw_doAniamtionWithContext:transitionContext fromFlag:NO]; 36 | 37 | } 38 | 39 | -(void)_xw_doAniamtionWithContext:(id)transitionContext fromFlag:(BOOL)flag{ 40 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 41 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 42 | UIViewController *realFromVC = [self _xw_getRealContainsGroupViewController:fromVC]; 43 | UIViewController *realToVC = [self _xw_getRealContainsGroupViewController:toVC]; 44 | NSArray *startViewGroup = objc_getAssociatedObject(realFromVC, flag ? &kXWMagicMoveAnimatorStartViewVCKey : &kXWMagicMoveAnimatorEndViewVCKey); 45 | NSArray *endViewGroup = objc_getAssociatedObject(realToVC, !flag ? &kXWMagicMoveAnimatorStartViewVCKey : &kXWMagicMoveAnimatorEndViewVCKey); 46 | if (!startViewGroup.count || !endViewGroup.count || startViewGroup.count != endViewGroup.count) { 47 | NSLog(@"神奇移动的视图为空,或者移动前后视图不相等"); 48 | [transitionContext completeTransition:NO]; 49 | return; 50 | } 51 | UIView *containerView = [transitionContext containerView]; 52 | toVC.view.alpha = 0.0f; 53 | [containerView addSubview:toVC.view]; 54 | NSArray *toRects = [self _xw_getFrameValueFromViewGroup:endViewGroup inContainerView:containerView]; 55 | NSArray *tempViewGroup = [self _xw_makeTempViewGroupWithViewGroup:startViewGroup inContainerView:containerView]; 56 | [self _xw_changeHiddenViewInGroup:startViewGroup hidden:YES]; 57 | [self _xw_changeHiddenViewInGroup:endViewGroup hidden:YES]; 58 | if (self.dampingEnable) { 59 | [UIView animateWithDuration:flag ? self.toDuration : self.backDuration delay:0.0f usingSpringWithDamping:0.55 initialSpringVelocity:1 / 0.55 options:UIViewAnimationOptionCurveLinear animations:^{ 60 | fromVC.view.alpha = 0.0f; 61 | toVC.view.alpha = 1.0f; 62 | [tempViewGroup enumerateObjectsUsingBlock:^(UIView *tempSubView, NSUInteger idx, BOOL * _Nonnull stop) { 63 | CGRect toRect = [toRects[idx] CGRectValue]; 64 | tempSubView.frame = toRect; 65 | }]; 66 | 67 | } completion:^(BOOL finished) { 68 | [tempViewGroup makeObjectsPerformSelector:@selector(removeFromSuperview)]; 69 | fromVC.view.alpha = 1.0f; 70 | [self _xw_changeHiddenViewInGroup:startViewGroup hidden:NO]; 71 | [self _xw_changeHiddenViewInGroup:endViewGroup hidden:NO]; 72 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 73 | 74 | }]; 75 | }else{ 76 | [UIView animateWithDuration:flag ? self.toDuration : self.backDuration animations:^{ 77 | fromVC.view.alpha = 0.0f; 78 | toVC.view.alpha = 1.0f; 79 | [tempViewGroup enumerateObjectsUsingBlock:^(UIView *tempSubView, NSUInteger idx, BOOL * _Nonnull stop) { 80 | CGRect toRect = [toRects[idx] CGRectValue]; 81 | tempSubView.frame = toRect; 82 | }]; 83 | } completion:^(BOOL finished) { 84 | [tempViewGroup makeObjectsPerformSelector:@selector(removeFromSuperview)]; 85 | fromVC.view.alpha = 1.0f; 86 | [self _xw_changeHiddenViewInGroup:startViewGroup hidden:NO]; 87 | [self _xw_changeHiddenViewInGroup:endViewGroup hidden:NO]; 88 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 89 | }]; 90 | } 91 | } 92 | 93 | /** 94 | * 判断当前控制器的类型,从而找到从出存有移动视图组的控制器 95 | */ 96 | - (UIViewController *)_xw_getRealContainsGroupViewController:(UIViewController *)controller{ 97 | UIViewController *realVC = controller; 98 | if ([controller isKindOfClass:[UITabBarController class]]) { 99 | UITabBarController *tabBarVC = (UITabBarController *)realVC; 100 | if ([tabBarVC.selectedViewController isKindOfClass:[UINavigationController class]]) { 101 | UINavigationController *navVC = (UINavigationController *)tabBarVC.selectedViewController; 102 | realVC = navVC.topViewController; 103 | }else{ 104 | realVC = tabBarVC.selectedViewController; 105 | } 106 | } 107 | if ([controller isKindOfClass:[UINavigationController class]]) { 108 | UINavigationController *navVC = (UINavigationController *)controller; 109 | realVC = navVC.topViewController; 110 | } 111 | return realVC; 112 | } 113 | 114 | 115 | - (NSArray *)_xw_getFrameValueFromViewGroup:(NSArray *)group inContainerView:(UIView *)containerView{ 116 | NSMutableArray *temp = @[].mutableCopy; 117 | [group enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL * _Nonnull stop) { 118 | CGRect rect = [view convertRect:view.bounds toView:containerView]; 119 | [temp addObject:[NSValue valueWithCGRect:rect]]; 120 | }]; 121 | return temp.copy; 122 | } 123 | 124 | - (NSArray *)_xw_makeTempViewGroupWithViewGroup:(NSArray *)group inContainerView:(UIView *)containerView{ 125 | NSMutableArray *temp = @[].mutableCopy; 126 | [group enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL * _Nonnull stop) { 127 | UIView *tempView = [self _xw_snapshotView:view]; 128 | tempView.frame = [view convertRect:view.bounds toView:containerView]; 129 | [containerView addSubview:tempView]; 130 | [temp addObject:tempView]; 131 | }]; 132 | return temp.copy; 133 | } 134 | 135 | - (void)_xw_changeHiddenViewInGroup:(NSArray *)group hidden:(BOOL)flag{ 136 | [group enumerateObjectsUsingBlock:^(UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 137 | obj.hidden = flag; 138 | }]; 139 | } 140 | 141 | - (UIView *)_xw_snapshotView:(UIView *)view{ 142 | CALayer *layer = view.layer; 143 | UIView *snapView = [UIView new]; 144 | snapView.frame = view.frame; 145 | BOOL imgMode = [objc_getAssociatedObject(view, &kXWMagicMovePropertyInViewKey) boolValue] || _imageMode; 146 | UIImage *img = nil; 147 | if (imgMode) {//如果开启imgMode,优先直接获取图片,避免截图时时从小到大造成的模糊 148 | if ([view isKindOfClass:[UIImageView class]]) {//取imageView中的image 149 | img = [(UIImageView *)view image]; 150 | }else if ([view isKindOfClass:[UIButton class]]){//取button中的image 151 | img = [(UIButton *)view currentImage]; 152 | } 153 | if (!img && [view isKindOfClass:[UIView class]]) {//没取到尝试取content 154 | img = [UIImage imageWithCGImage:(__bridge CGImageRef)view.layer.contents]; 155 | } 156 | } 157 | //若都没有取到,则截图 158 | if (!img) { 159 | UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.opaque, 0); 160 | CGContextRef context = UIGraphicsGetCurrentContext(); 161 | [layer renderInContext:context]; 162 | img = UIGraphicsGetImageFromCurrentImageContext(); 163 | UIGraphicsEndImageContext(); 164 | } 165 | snapView.layer.contents = (__bridge id)img.CGImage; 166 | return snapView; 167 | } 168 | 169 | 170 | @end 171 | 172 | NSString *const kXWMagicMoveAnimatorStartViewVCKey = @"kXWMagicMoveAnimatorStartViewVCKey"; 173 | NSString *const kXWMagicMoveAnimatorEndViewVCKey = @"kXWMagicMoveAnimatorEndViewVCKey"; 174 | -------------------------------------------------------------------------------- /XWTransition/Main/XWInteractiveTransition.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWInteractiveTransition.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/10. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWInteractiveTransition.h" 10 | #import 11 | 12 | typedef struct { 13 | unsigned int willBegin : 1; 14 | unsigned int isUpdating : 1; 15 | unsigned int willBeginTimer : 1; 16 | unsigned int willEnd : 1; 17 | } delegateFlag; 18 | 19 | @interface XWInteractiveTransition () 20 | @property (nonatomic, assign) XWInteractiveTransitionGestureDirection direction; 21 | @property (nonatomic, copy) void(^config)(CGPoint startPoint); 22 | @property (nonatomic, strong) CADisplayLink *timer; 23 | @property (nonatomic, assign) CGFloat percent; 24 | @property (nonatomic, assign) CGFloat timeDis; 25 | @property (nonatomic, assign) delegateFlag delegateFlag; 26 | @property (nonatomic, assign) BOOL vertical; 27 | @property (nonatomic, assign) CGFloat edgeSpacing; 28 | 29 | 30 | @end 31 | 32 | @implementation XWInteractiveTransition 33 | 34 | + (instancetype)xw_interactiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction config:(void(^)(CGPoint startPoint))config edgeSpacing:(CGFloat)edgeSpacing{ 35 | return [[self alloc] _initInteractiveTransitionWithDirection:direction config:config edgeSpacing:edgeSpacing]; 36 | } 37 | 38 | - (instancetype)_initInteractiveTransitionWithDirection:(XWInteractiveTransitionGestureDirection)direction config:(void(^)(CGPoint startPoint))config edgeSpacing:(CGFloat)edgeSpacing{ 39 | self = [super init]; 40 | if (self) { 41 | _config = config; 42 | _direction = direction; 43 | _edgeSpacing = edgeSpacing; 44 | _vertical = direction == XWInteractiveTransitionGestureDirectionDown || direction == XWInteractiveTransitionGestureDirectionUp; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)setDelegate:(id)delegate{ 50 | _delegate = delegate; 51 | _delegateFlag.willBegin = _delegate && [_delegate respondsToSelector:@selector(xw_interactiveTransitionWillBegin:)]; 52 | _delegateFlag.isUpdating = _delegate && [_delegate respondsToSelector:@selector(xw_interactiveTransition:isUpdating:)]; 53 | _delegateFlag.willBeginTimer = _delegate && [_delegate respondsToSelector:@selector(xw_interactiveTransitionWillBeginTimerAnimation:)]; 54 | _delegateFlag.willEnd = _delegate && [_delegate respondsToSelector:@selector(xw_interactiveTransition:willEndWithSuccessFlag:percent:)]; 55 | } 56 | 57 | - (void)xw_addPanGestureForView:(UIView *)view to:(BOOL)flag{ 58 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(_xw_handleGesture:)]; 59 | //为drawerAnimator记录pan手势 60 | pan.delegate = self; 61 | NSString * panType = flag ? @"xw_interactiveToPan" : @"xw_interactiveBackPan"; 62 | objc_setAssociatedObject(pan, "xw_interactivePanKey", panType, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 63 | [view addGestureRecognizer:pan]; 64 | } 65 | 66 | - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ 67 | if (_edgeSpacing <= 0) { 68 | return YES; 69 | } 70 | CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view]; 71 | BOOL should = NO; 72 | switch (_direction) { 73 | case XWInteractiveTransitionGestureDirectionLeft: { 74 | should = point.x >= gestureRecognizer.view.frame.size.width - _edgeSpacing; 75 | break; 76 | } 77 | case XWInteractiveTransitionGestureDirectionRight: { 78 | should = point.x <= _edgeSpacing; 79 | break; 80 | } 81 | case XWInteractiveTransitionGestureDirectionUp: { 82 | should = point.y >= gestureRecognizer.view.frame.size.height - _edgeSpacing; 83 | break; 84 | } 85 | case XWInteractiveTransitionGestureDirectionDown: { 86 | should = point.y <= _edgeSpacing; 87 | break; 88 | } 89 | } 90 | return should; 91 | } 92 | 93 | /** 94 | * 手势过渡的过程 95 | */ 96 | - (void)_xw_handleGesture:(UIPanGestureRecognizer *)panGesture{ 97 | switch (panGesture.state) { 98 | case UIGestureRecognizerStateBegan: 99 | if (_delegateFlag.willBegin) { 100 | [_delegate xw_interactiveTransitionWillBegin:self]; 101 | } 102 | CGPoint startPoint = [panGesture locationInView:panGesture.view]; 103 | _interation = YES; 104 | if (_config) { 105 | _config(startPoint); 106 | } 107 | [self _xw_caculateMovePercentForGesture:panGesture]; 108 | break; 109 | case UIGestureRecognizerStateChanged:{ 110 | [self _xw_caculateMovePercentForGesture:panGesture]; 111 | [self _xw_updatingWithPercent:_percent]; 112 | break; 113 | } 114 | case UIGestureRecognizerStateEnded:{ 115 | //判断是否需要timer 116 | if (!_timerEable) { 117 | _percent >= 0.5 ? [self _xw_finish] : [self _xw_cancle]; 118 | return; 119 | } 120 | //判断此时是否已经转场完成,大于1或者小于0 121 | BOOL canEnd = [self _xw_canEndInteractiveTransitionWithPercent:_percent]; 122 | if (canEnd) return; 123 | //开启timer 124 | [self _xw_setEndAnimationTimerWithPercent:_percent]; 125 | break; 126 | } 127 | default: 128 | break; 129 | } 130 | } 131 | 132 | - (BOOL)_xw_canEndInteractiveTransitionWithPercent:(CGFloat)percent{ 133 | BOOL can = NO; 134 | if (percent >= 1) { 135 | [self _xw_finish]; 136 | can = YES; 137 | } 138 | if (percent <= 0) { 139 | [self _xw_cancle]; 140 | can = YES; 141 | } 142 | return can; 143 | } 144 | 145 | - (void)_xw_caculateMovePercentForGesture:(UIPanGestureRecognizer *)panGesture{ 146 | static CGFloat baseValue = 0.0f; 147 | baseValue = _panRatioBaseValue > 0 ? _panRatioBaseValue : _vertical ? panGesture.view.frame.size.height : panGesture.view.frame.size.width; 148 | //手势百分比 149 | switch (_direction) { 150 | case XWInteractiveTransitionGestureDirectionLeft:{ 151 | CGFloat transitionX = -[panGesture translationInView:panGesture.view].x; 152 | _percent += transitionX / baseValue; 153 | } 154 | break; 155 | case XWInteractiveTransitionGestureDirectionRight:{ 156 | CGFloat transitionX = [panGesture translationInView:panGesture.view].x; 157 | _percent += transitionX / baseValue; 158 | } 159 | break; 160 | case XWInteractiveTransitionGestureDirectionUp:{ 161 | CGFloat transitionY = -[panGesture translationInView:panGesture.view].y; 162 | _percent += transitionY / baseValue; 163 | } 164 | break; 165 | case XWInteractiveTransitionGestureDirectionDown:{ 166 | CGFloat transitionY = [panGesture translationInView:panGesture.view].y; 167 | _percent += transitionY / baseValue; 168 | } 169 | break; 170 | } 171 | [panGesture setTranslation:CGPointZero inView:panGesture.view]; 172 | } 173 | 174 | //设置开启timer 175 | - (void)_xw_setEndAnimationTimerWithPercent:(CGFloat)percent{ 176 | _percent = percent; 177 | //根据失败还是成功设置刷新间隔 178 | if (percent > 0.5) { 179 | _timeDis = (1 - percent) / ((1 - percent) * 60); 180 | }else{ 181 | _timeDis = percent / (percent * 60); 182 | } 183 | if (_delegateFlag.willBeginTimer) { 184 | [_delegate xw_interactiveTransitionWillBeginTimerAnimation:self]; 185 | } 186 | //开启timer 187 | [self _xw_startTimer]; 188 | } 189 | 190 | - (void)_xw_finish{ 191 | if (_delegateFlag.willEnd) { 192 | [_delegate xw_interactiveTransition:self willEndWithSuccessFlag:YES percent:_percent]; 193 | } 194 | [self finishInteractiveTransition]; 195 | _percent = 0.0f; 196 | _interation = NO; 197 | } 198 | 199 | - (void)_xw_cancle{ 200 | if (_delegateFlag.willEnd) { 201 | [_delegate xw_interactiveTransition:self willEndWithSuccessFlag:NO percent:_percent]; 202 | } 203 | [self cancelInteractiveTransition]; 204 | _percent = 0.0f; 205 | _interation = NO; 206 | } 207 | 208 | - (void)_xw_updatingWithPercent:(CGFloat)percent{ 209 | [self updateInteractiveTransition:percent]; 210 | if (_delegateFlag.isUpdating) { 211 | [_delegate xw_interactiveTransition:self isUpdating:_percent]; 212 | } 213 | } 214 | 215 | - (void)_xw_startTimer{ 216 | if (_timer) { 217 | return; 218 | } 219 | _timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(_xw_timerEvent)]; 220 | [_timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 221 | } 222 | 223 | - (void)_xw_stopTimer{ 224 | if (!_timer) { 225 | return; 226 | } 227 | [_timer invalidate]; 228 | _timer = nil; 229 | 230 | } 231 | 232 | //timer 事件 233 | - (void)_xw_timerEvent{ 234 | if (_percent > 0.5) { 235 | _percent += _timeDis; 236 | }else{ 237 | _percent -= _timeDis; 238 | } 239 | //通过timer不断刷新转场进度 240 | [self _xw_updatingWithPercent:_percent]; 241 | BOOL canEnd = [self _xw_canEndInteractiveTransitionWithPercent:_percent]; 242 | if (canEnd) { 243 | [self _xw_stopTimer]; 244 | } 245 | } 246 | @end 247 | 248 | -------------------------------------------------------------------------------- /XWTransition/XWCoolAnimator/XWCoolAnimator+XWMiddlePageFlip.m: -------------------------------------------------------------------------------- 1 | // 2 | // XWCoolAnimator+XWMiddlePageFlip.m 3 | // XWTransitionDemo 4 | // 5 | // Created by wazrx on 16/6/13. 6 | // Copyright © 2016年 wazrx. All rights reserved. 7 | // 8 | 9 | #import "XWCoolAnimator+XWMiddlePageFlip.h" 10 | #import "UIView+Snapshot.h" 11 | 12 | @implementation XWCoolAnimator (XWMiddlePageFlip) 13 | 14 | 15 | 16 | - (void)xw_setMiddlePageFlipToAnimation:(id)transitionContext direction:(XWMiddlePageFlipDirection)direction { 17 | [self _xw_animation:transitionContext direction:direction duration:self.toDuration]; 18 | 19 | } 20 | 21 | - (void)xw_setMiddlePageFlipBackAnimation:(id)transitionContext direction:(XWMiddlePageFlipDirection)direction { 22 | [self _xw_animation:transitionContext direction:direction duration:self.backDuration]; 23 | 24 | } 25 | 26 | - (void)_xw_animation:(id)transitionContext direction:(XWMiddlePageFlipDirection)direction duration:(NSTimeInterval)duration{ 27 | UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 28 | UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 29 | UIView *toView = toVC.view; 30 | UIView *fromView = fromVC.view; 31 | UIView *containerView = [transitionContext containerView]; 32 | [containerView addSubview:toView]; 33 | [containerView sendSubviewToBack:toView]; 34 | CATransform3D transform = CATransform3DIdentity; 35 | transform.m34 = -0.002; 36 | [containerView.layer setSublayerTransform:transform]; 37 | BOOL animation = direction == XWMiddlePageFlipDirectionLeft || direction == XWMiddlePageFlipDirectionTop; 38 | NSArray* toViewSnapshots = [self _xw_animationSnapFlipView:toView withDirection:direction update:YES]; 39 | UIView* animationToView = toViewSnapshots[animation ? 1 : 0]; 40 | NSArray* fromViewSnapshots = [self _xw_animationSnapFlipView:fromView withDirection:direction update:NO]; 41 | UIView* animationFromView = fromViewSnapshots[animation ? 0 : 1]; 42 | [self _xw_addShadowWithDirection:direction fromView:animationFromView toView:animationToView]; 43 | [self _xw_setAnchorPointWithDirection:direction fromView:animationFromView toView:animationToView]; 44 | BOOL rationAngle = direction == XWMiddlePageFlipDirectionLeft || direction == XWMiddlePageFlipDirectionBottom; 45 | BOOL flipDirection = direction == XWMiddlePageFlipDirectionLeft || direction == XWMiddlePageFlipDirectionRight; 46 | animationToView.layer.transform = CATransform3DMakeRotation(rationAngle ? -M_PI_2 : M_PI_2, flipDirection ? 0.0 : 1.0, !flipDirection ? 0.0 : 1.0, 0.0); 47 | [UIView animateKeyframesWithDuration:duration 48 | delay:0.0 49 | options:0 50 | animations:^{ 51 | [UIView addKeyframeWithRelativeStartTime:0.0 52 | relativeDuration:0.5 53 | animations:^{ 54 | animationFromView.layer.transform = CATransform3DMakeRotation(rationAngle ? M_PI_2 : -M_PI_2, flipDirection ? 0.0 : 1.0, !flipDirection ? 0.0 : 1.0, 0.0); 55 | UIView *shadowView = animationFromView.subviews.lastObject; 56 | shadowView.alpha = 1.0f; 57 | }]; 58 | 59 | [UIView addKeyframeWithRelativeStartTime:0.5 60 | relativeDuration:0.5 61 | animations:^{ 62 | animationToView.hidden = NO; 63 | animationToView.layer.transform = CATransform3DMakeRotation(rationAngle ? -0.001 : 0.001, flipDirection ? 0.0 : 1.0, !flipDirection ? 0.0 : 1.0, 0.0); 64 | UIView *shadowView = animationToView.subviews.lastObject; 65 | shadowView.alpha = 0.0f; 66 | }]; 67 | } completion:^(BOOL finished) { 68 | [toViewSnapshots makeObjectsPerformSelector:@selector(removeFromSuperview)]; 69 | [fromViewSnapshots makeObjectsPerformSelector:@selector(removeFromSuperview)]; 70 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 71 | }]; 72 | } 73 | 74 | - (NSArray *)_xw_animationSnapFlipView:(UIView *)view withDirection:(XWMiddlePageFlipDirection)direction update:(BOOL)update{ 75 | UIView *containerView = view.superview; 76 | CGSize size = view.bounds.size; 77 | CGRect rectOne = CGRectZero; 78 | CGRect rectTwo = CGRectZero; 79 | switch (direction) { 80 | case XWMiddlePageFlipDirectionLeft: 81 | case XWMiddlePageFlipDirectionRight:{ 82 | rectOne = CGRectMake(0, 0, view.frame.size.width / 2.0f, view.frame.size.height); 83 | rectTwo = CGRectMake(view.frame.size.width / 2.0f, 0, view.frame.size.width / 2.0f, view.frame.size.height); 84 | break; 85 | } 86 | case XWMiddlePageFlipDirectionTop: 87 | case XWMiddlePageFlipDirectionBottom:{ 88 | rectOne = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height / 2.0f); 89 | rectTwo = CGRectMake(0, view.frame.size.height / 2.0f, view.frame.size.width, view.frame.size.height / 2.0f); 90 | break; 91 | } 92 | } 93 | UIView *viewOne = [UIView new]; 94 | viewOne.contentImage = view.snapshotImage; 95 | UIView *viewTwo = [UIView new]; 96 | viewTwo.contentImage = viewOne.contentImage; 97 | viewOne.frame = rectOne; 98 | viewTwo.frame = rectTwo; 99 | viewOne.layer.contentsRect = CGRectMake(rectOne.origin.x / size.width, rectOne.origin.y / size.height, rectOne.size.width / size.width, rectOne.size.height / size.height); 100 | viewTwo.layer.contentsRect = CGRectMake(rectTwo.origin.x / size.width, rectTwo.origin.y / size.height, rectTwo.size.width / size.width, rectTwo.size.height / size.height); 101 | [containerView addSubview:viewOne]; 102 | [containerView addSubview:viewTwo]; 103 | return @[viewOne, viewTwo]; 104 | } 105 | 106 | - (void)_xw_setAnchorPointWithDirection:(XWMiddlePageFlipDirection)direction fromView:(UIView *)fromView toView:(UIView *)toView{ 107 | switch (direction) { 108 | case XWMiddlePageFlipDirectionLeft: { 109 | [self _xw_setAnchorPointTo:CGPointMake(1, 0.5) forView:fromView]; 110 | [self _xw_setAnchorPointTo:CGPointMake(0, 0.5) forView:toView]; 111 | break; 112 | } 113 | case XWMiddlePageFlipDirectionRight: { 114 | [self _xw_setAnchorPointTo:CGPointMake(0, 0.5) forView:fromView]; 115 | [self _xw_setAnchorPointTo:CGPointMake(1, 0.5) forView:toView]; 116 | break; 117 | } 118 | case XWMiddlePageFlipDirectionTop: { 119 | [self _xw_setAnchorPointTo:CGPointMake(0.5, 1) forView:fromView]; 120 | [self _xw_setAnchorPointTo:CGPointMake(0.5, 0) forView:toView]; 121 | break; 122 | } 123 | case XWMiddlePageFlipDirectionBottom: { 124 | [self _xw_setAnchorPointTo:CGPointMake(0.5, 0) forView:fromView]; 125 | [self _xw_setAnchorPointTo:CGPointMake(0.5, 1) forView:toView]; 126 | break; 127 | } 128 | } 129 | } 130 | 131 | - (void)_xw_setAnchorPointTo:(CGPoint)point forView:(UIView *)view{ 132 | view.frame = CGRectOffset(view.frame, (point.x - view.layer.anchorPoint.x) * view.frame.size.width, (point.y - view.layer.anchorPoint.y) * view.frame.size.height); 133 | view.layer.anchorPoint = point; 134 | } 135 | 136 | - (void)_xw_addShadowWithDirection:(XWMiddlePageFlipDirection)direction fromView:(UIView *)fromView toView:(UIView *)toView{ 137 | CGPoint fstartP = CGPointZero; 138 | CGPoint fendP = CGPointZero; 139 | CGPoint tstartP = CGPointZero; 140 | CGPoint tendP = CGPointZero; 141 | switch (direction) { 142 | case XWMiddlePageFlipDirectionLeft: { 143 | fstartP = CGPointMake(0.0, 0.0); 144 | fendP = CGPointMake(1.0, 0.0); 145 | tstartP = CGPointMake(1.0, 0.0); 146 | tendP = CGPointMake(0.0, 0.0); 147 | break; 148 | } 149 | case XWMiddlePageFlipDirectionRight: { 150 | fstartP = CGPointMake(1.0, 0.0); 151 | fendP = CGPointMake(0.0, 0.0); 152 | tstartP = CGPointMake(0.0, 0.0); 153 | tendP = CGPointMake(1.0, 0.0); 154 | break; 155 | } 156 | case XWMiddlePageFlipDirectionTop: { 157 | fstartP = CGPointMake(0.0, 0.0); 158 | fendP = CGPointMake(0.0, 1.0); 159 | tstartP = CGPointMake(0.0, 1.0); 160 | tendP = CGPointMake(0.0, 0.0); 161 | break; 162 | } 163 | case XWMiddlePageFlipDirectionBottom: { 164 | fstartP = CGPointMake(0.0, 1.0); 165 | fendP = CGPointMake(0.0, 0.0); 166 | tstartP = CGPointMake(0.0, 0.0); 167 | tendP = CGPointMake(0.0, 1.0); 168 | break; 169 | } 170 | } 171 | [self _xw_addGrandientLayerWithStartPoint:fstartP endPoint:fendP forView:fromView].alpha = 0.0f; 172 | [self _xw_addGrandientLayerWithStartPoint:tstartP endPoint:tendP forView:toView].alpha = 1.0f; 173 | } 174 | 175 | - (UIView *)_xw_addGrandientLayerWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint forView:(UIView *)view{ 176 | CAGradientLayer *gradient = [CAGradientLayer layer]; 177 | gradient.frame = view.bounds; 178 | gradient.colors = @[(id)[UIColor colorWithWhite:0.0 alpha:0.0].CGColor, 179 | (id)[UIColor colorWithWhite:0.0 alpha:0.5].CGColor]; 180 | gradient.startPoint = startPoint; 181 | gradient.endPoint = endPoint; 182 | UIView* shadowView = [[UIView alloc] initWithFrame:view.bounds]; 183 | [shadowView.layer insertSublayer:gradient atIndex:0]; 184 | [view addSubview:shadowView]; 185 | return shadowView; 186 | } 187 | 188 | #pragma mark - 189 | 190 | - (void)xw_interactiveTransition:(XWInteractiveTransition *)interactiveTransition willEndWithSuccessFlag:(BOOL)flag percent:(CGFloat)percent{ 191 | //防止闪烁 192 | if (!flag && percent < 0) { 193 | [interactiveTransition updateInteractiveTransition:0.001]; 194 | } 195 | } 196 | 197 | @end 198 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------