├── GLTransitionAnimationDemo
├── Assets.xcassets
│ ├── Contents.json
│ ├── 2.imageset
│ │ ├── 2.jpg
│ │ └── Contents.json
│ ├── 3.imageset
│ │ ├── 3.png
│ │ └── Contents.json
│ ├── 4.imageset
│ │ ├── 4.jpg
│ │ └── Contents.json
│ ├── 5.imageset
│ │ ├── 5.jpg
│ │ └── Contents.json
│ ├── a.imageset
│ │ ├── a.jpg
│ │ └── Contents.json
│ ├── b.imageset
│ │ ├── b.jpg
│ │ └── Contents.json
│ ├── 00.imageset
│ │ ├── 00.jpg
│ │ └── Contents.json
│ ├── 11.imageset
│ │ ├── 11.jpg
│ │ └── Contents.json
│ ├── 12.imageset
│ │ ├── 12.png
│ │ └── Contents.json
│ ├── 加.imageset
│ │ ├── 加@2x.png
│ │ └── Contents.json
│ ├── 叉.imageset
│ │ ├── 叉@2x.png
│ │ └── Contents.json
│ ├── 圆.imageset
│ │ ├── 圆@2x.png
│ │ └── Contents.json
│ ├── 运动.imageset
│ │ ├── 运动@2x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── ViewController
│ ├── TableViewController.h
│ ├── CircleSpreadVc
│ │ ├── CircleSpreadToController.h
│ │ ├── CircleSpreadFromController.h
│ │ ├── CircleSpreadToController.m
│ │ └── CircleSpreadFromController.m
│ ├── OpenDoorVc
│ │ ├── OpenDoorToViewController.h
│ │ ├── OpenDoorFromViewController.h
│ │ ├── OpenDoorToViewController.m
│ │ └── OpenDoorFromViewController.m
│ ├── MiddlePageVc
│ │ ├── MiddlePageToViewController.h
│ │ ├── MiddlePageFromViewController.h
│ │ ├── MiddlePageToViewController.m
│ │ └── MiddlePageFromViewController.m
│ ├── CircleRectSpreadVc
│ │ ├── CircleRectSpreadToViewController.h
│ │ ├── CircleRectSpreadFromViewController.h
│ │ ├── CircleRectSpreadToViewController.m
│ │ └── CircleRectSpreadFromViewController.m
│ └── TableViewController.m
├── GLTransitionAnimation
│ ├── GLAnimation
│ │ ├── GLOpenDoorAnimation.h
│ │ ├── GLMiddlePageAnimation.h
│ │ ├── GLCircleRectSpreadAnimation.h
│ │ ├── GLCircleSpreadAnimation.h
│ │ ├── GLCircleRectSpreadAnimation.m
│ │ ├── GLCircleSpreadAnimation.m
│ │ ├── GLOpenDoorAnimation.m
│ │ └── GLMiddlePageAnimation.m
│ ├── GLTransitionAnimation.h
│ ├── GLTransitionManager.h
│ ├── GLTransitionAnimation.m
│ ├── UIViewController+GLTransition.h
│ ├── GLInteractiveTransition.h
│ ├── UIViewController+GLTransition.m
│ ├── GLInteractiveTransition.m
│ └── GLTransitionManager.m
├── AppDelegate.h
├── main.m
├── PrefixHeader.pch
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
└── AppDelegate.m
├── GLTransitionAnimationDemo.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── gaolei.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcuserdata
│ └── gaolei.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── GLTransitionAnimationDemo.xcscheme
└── project.pbxproj
└── README.md
/GLTransitionAnimationDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/2.imageset/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/2.imageset/2.jpg
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/3.imageset/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/3.imageset/3.png
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/4.imageset/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/4.imageset/4.jpg
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/5.imageset/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/5.imageset/5.jpg
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/a.imageset/a.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/a.imageset/a.jpg
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/b.imageset/b.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/b.imageset/b.jpg
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/00.imageset/00.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/00.imageset/00.jpg
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/11.imageset/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/11.imageset/11.jpg
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/12.imageset/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/12.imageset/12.png
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/加.imageset/加@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/加.imageset/加@2x.png
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/叉.imageset/叉@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/叉.imageset/叉@2x.png
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/圆.imageset/圆@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/圆.imageset/圆@2x.png
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/运动.imageset/运动@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo/Assets.xcassets/运动.imageset/运动@2x.png
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo.xcodeproj/project.xcworkspace/xcuserdata/gaolei.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gao211326/GLTransitionAnimationDemo/HEAD/GLTransitionAnimationDemo.xcodeproj/project.xcworkspace/xcuserdata/gaolei.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/TableViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewController.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TableViewController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleSpreadVc/CircleSpreadToController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.h
3 | // GLPushAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/16.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CircleSpreadToController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleSpreadVc/CircleSpreadFromController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // GLPushAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/8.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CircleSpreadFromController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/OpenDoorVc/OpenDoorToViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // OpenDoorToViewController.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/30.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface OpenDoorToViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLOpenDoorAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // GLOpenDoorAnimation.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/30.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLTransitionManager.h"
10 |
11 | @interface GLOpenDoorAnimation : GLTransitionManager
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/MiddlePageVc/MiddlePageToViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // MiddlePageToViewController.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/31.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MiddlePageToViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/OpenDoorVc/OpenDoorFromViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // OpenDoorFromViewController.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/30.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface OpenDoorFromViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLMiddlePageAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // GLMiddlePageAnimation.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/31.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLTransitionManager.h"
10 |
11 | @interface GLMiddlePageAnimation : GLTransitionManager
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/MiddlePageVc/MiddlePageFromViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // MiddlePageFromViewController.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/31.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MiddlePageFromViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/23.
6 | // Copyright © 2017年 高磊. 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 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleRectSpreadVc/CircleRectSpreadToViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRectSpreadToViewController.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CircleRectSpreadToViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleRectSpreadVc/CircleRectSpreadFromViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRectSpreadFromViewController.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CircleRectSpreadFromViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/23.
6 | // Copyright © 2017年 高磊. 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 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/00.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "00.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/11.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "11.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/12.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "12.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "2.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "3.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "4.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "5.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/a.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "a.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/b.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "b.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/加.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "加@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/叉.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "叉@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/圆.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "圆@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/运动.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "运动@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLCircleRectSpreadAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // GLCircleRectSpreadAnimation.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | // 圆形和矩形一起扩散
8 |
9 | #import "GLTransitionManager.h"
10 |
11 | @interface GLCircleRectSpreadAnimation : GLTransitionManager
12 |
13 | - (id)initWithStartPoint:(CGPoint )point;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/PrefixHeader.pch:
--------------------------------------------------------------------------------
1 | //
2 | // PrefixHeader.pch
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/29.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #ifndef PrefixHeader_pch
10 | #define PrefixHeader_pch
11 |
12 | #define UICOLOR_FROM_RGB_OxFF(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
13 | green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
14 | blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
15 |
16 |
17 | #endif /* PrefixHeader_pch */
18 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLCircleSpreadAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // GLCircleSpreadAnimation.h
3 | // GLPushAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/16.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | // 圆圈类型传播
8 |
9 | #import "GLTransitionManager.h"
10 |
11 | @interface GLCircleSpreadAnimation : GLTransitionManager
12 |
13 |
14 | /**
15 | 初始化方法
16 |
17 | @param point 扩散的中心位置
18 | @param radius 半径
19 | @return 返回
20 | */
21 | - (id)initWithStartPoint:(CGPoint)point radius:(CGFloat)radius;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo.xcodeproj/xcuserdata/gaolei.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo.xcodeproj/xcuserdata/gaolei.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | GLTransitionAnimationDemo.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | EB1BB47D1E83BD8F000B8DD0
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLTransitionAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // GLTransitionContext.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/24.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | // 自定义转场动画的具体实现
8 |
9 | #import
10 | #import
11 |
12 |
13 | /**
14 | GLTransitionAnimation 块
15 |
16 | @param contextTransition 将满足UIViewControllerContextTransitioning协议的对象传到管理内 在管理类对动画统一实现
17 | */
18 | typedef void(^GLTransitionAnimationBlock)(id contextTransition);
19 |
20 | @interface GLTransitionAnimation : NSObject
21 |
22 | @property (nonatomic,copy) GLTransitionAnimationBlock animationBlock;
23 |
24 | /**
25 | 初始化方法
26 |
27 | @param duration 转场时间
28 | @return 返回
29 | */
30 | - (id)initWithDuration:(NSTimeInterval)duration;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLTransitionManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // GLTransitionManager.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/23.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | // 转场动画管理类 push pop present dismiss均在此类中进行统一管理
8 |
9 | #import
10 | #import
11 |
12 | @interface GLTransitionManager : NSObject
13 |
14 | /**
15 | 转场动画的时间 默认为0.5s
16 | */
17 | @property (nonatomic,assign) NSTimeInterval duration;
18 |
19 | /**
20 | 入场动画
21 |
22 | @param contextTransition 实现动画
23 | */
24 | - (void)setToAnimation:(id)contextTransition;
25 |
26 |
27 | /**
28 | 退场动画
29 |
30 | @param contextTransition 实现动画
31 | */
32 | - (void)setBackAnimation:(id)contextTransition;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/OpenDoorVc/OpenDoorToViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // OpenDoorToViewController.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/30.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "OpenDoorToViewController.h"
10 | #import "UIViewController+GLTransition.h"
11 |
12 | @interface OpenDoorToViewController ()
13 |
14 | @end
15 |
16 | @implementation OpenDoorToViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | [self.view.layer setContents:(id)[UIImage imageNamed:@"00"].CGImage];
22 |
23 | __weak typeof(self)weakSelf = self;
24 | [self gl_registerBackInteractiveTransitionWithDirection:GLPanEdgeLeft eventBlcok:^{
25 | [weakSelf dismissViewControllerAnimated:YES completion:nil];
26 | }];
27 | }
28 |
29 |
30 | - (void)didReceiveMemoryWarning {
31 | [super didReceiveMemoryWarning];
32 | // Dispose of any resources that can be recreated.
33 | }
34 |
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/MiddlePageVc/MiddlePageToViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // MiddlePageToViewController.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/31.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "MiddlePageToViewController.h"
10 | #import "UIViewController+GLTransition.h"
11 |
12 | @interface MiddlePageToViewController ()
13 |
14 | @end
15 |
16 | @implementation MiddlePageToViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | [self.view.layer setContents:(id)[UIImage imageNamed:@"00"].CGImage];
22 |
23 | __weak typeof(self)weakSelf = self;
24 | [self gl_registerBackInteractiveTransitionWithDirection:GLPanEdgeLeft eventBlcok:^{
25 | [weakSelf.navigationController popViewControllerAnimated:YES];
26 | }];
27 | }
28 |
29 | - (void)didReceiveMemoryWarning {
30 | [super didReceiveMemoryWarning];
31 | // Dispose of any resources that can be recreated.
32 | }
33 |
34 |
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLTransitionAnimation.m:
--------------------------------------------------------------------------------
1 | //
2 | // GLTransitionContext.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/24.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLTransitionAnimation.h"
10 |
11 | @interface GLTransitionAnimation ()
12 |
13 |
14 | /**
15 | 动画时间
16 | */
17 | @property (nonatomic,assign) NSTimeInterval duration;
18 |
19 |
20 | @end
21 |
22 | @implementation GLTransitionAnimation
23 |
24 | - (id)initWithDuration:(NSTimeInterval)duration
25 | {
26 | self = [super init];
27 | if (self) {
28 | _duration = duration;
29 | }
30 | return self;
31 | }
32 |
33 | - (NSTimeInterval)transitionDuration:(id)transitionContext
34 | {
35 | return self.duration;
36 | }
37 |
38 | - (void)animateTransition:(id)transitionContext
39 | {
40 | if (self.animationBlock) {
41 | self.animationBlock(transitionContext);
42 | }
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleSpreadVc/CircleSpreadToController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.m
3 | // GLPushAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/16.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "CircleSpreadToController.h"
10 | #import "UIViewController+GLTransition.h"
11 | #import "GLTransitionManager.h"
12 | #import
13 |
14 | @interface CircleSpreadToController ()
15 |
16 | @property (nonatomic,strong) GLInteractiveTransition *glInteractiveTransition;
17 |
18 | @end
19 |
20 | @implementation CircleSpreadToController
21 |
22 | - (void)dealloc
23 | {
24 |
25 | }
26 |
27 | - (void)viewDidLoad {
28 | [super viewDidLoad];
29 |
30 | [self.view.layer setContents:(id)[UIImage imageNamed:@"12"].CGImage];
31 |
32 | __weak typeof(self)weakSelf = self;
33 | [self gl_registerBackInteractiveTransitionWithDirection:GLPanEdgeLeft eventBlcok:^{
34 | [weakSelf.navigationController popViewControllerAnimated:YES];
35 | }];
36 | }
37 |
38 | - (void)btnClick:(UIButton *)sender
39 | {
40 | [self.navigationController popViewControllerAnimated:YES];
41 | }
42 |
43 | - (void)didReceiveMemoryWarning {
44 | [super didReceiveMemoryWarning];
45 | // Dispose of any resources that can be recreated.
46 | }
47 |
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/MiddlePageVc/MiddlePageFromViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // MiddlePageFromViewController.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/31.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "MiddlePageFromViewController.h"
10 | #import "MiddlePageToViewController.h"
11 |
12 | #import "UIViewController+GLTransition.h"
13 | #import "GLMiddlePageAnimation.h"
14 |
15 | @interface MiddlePageFromViewController ()
16 |
17 | @end
18 |
19 | @implementation MiddlePageFromViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 |
24 | [self.view.layer setContents:(id)[UIImage imageNamed:@"b"].CGImage];
25 |
26 | __weak typeof(self)weakSelf = self;
27 | [self gl_registerToInteractiveTransitionWithDirection:GLPanEdgeRight eventBlcok:^{
28 |
29 | MiddlePageToViewController *middlePageToVc = [[MiddlePageToViewController alloc] init];
30 | GLMiddlePageAnimation *middlePageAnimation = [[GLMiddlePageAnimation alloc] init];
31 | middlePageAnimation.duration = 1;
32 |
33 | [weakSelf gl_pushViewControler:middlePageToVc withAnimation:middlePageAnimation];
34 |
35 | }];
36 | }
37 |
38 | - (void)didReceiveMemoryWarning {
39 | [super didReceiveMemoryWarning];
40 | // Dispose of any resources that can be recreated.
41 | }
42 |
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/UIViewController+GLTransition.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+GLTransition.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/24.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | // UIViewController的转场category
8 |
9 | #import
10 | #import "GLInteractiveTransition.h"
11 |
12 | extern NSString *const kAnimationKey;
13 | extern NSString *const kToAnimationKey;
14 |
15 | @class GLTransitionManager;
16 |
17 | @interface UIViewController (GLTransition)
18 |
19 | /**
20 | push动画
21 |
22 | @param viewController 被push viewController
23 | @param transitionManager 控制类
24 | */
25 | - (void)gl_pushViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager*)transitionManager;
26 |
27 |
28 | /**
29 | present动画
30 |
31 | @param viewController 被present viewController
32 | @param transitionManager 控制类
33 | */
34 | - (void)gl_presentViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager*)transitionManager;
35 |
36 |
37 | /**
38 | 注册入场手势
39 |
40 | @param direction 方向
41 | @param blcok 手势转场触发的点击事件
42 | */
43 | - (void)gl_registerToInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok;
44 |
45 | /**
46 | 注册返回手势
47 |
48 | @param direction 侧滑方向
49 | @param blcok 手势转场触发的点击事件
50 | */
51 | - (void)gl_registerBackInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok;
52 |
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLInteractiveTransition.h:
--------------------------------------------------------------------------------
1 | //
2 | // GLInteractiveTransition.h
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/24.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | // 手势转场控制类
8 |
9 | #import
10 |
11 |
12 | /**
13 | 手势的方向枚举
14 |
15 | - GLPanEdgeTop:屏幕上方
16 | - GLPanEdgeLeft:屏幕左侧
17 | - GLPanEdgeBottom: 屏幕下方
18 | - GLPanEdgeRight: 屏幕右方
19 | */
20 | typedef NS_ENUM(NSInteger,GLEdgePanGestureDirection) {
21 | GLPanEdgeTop = 0,
22 | GLPanEdgeLeft,
23 | GLPanEdgeBottom,
24 | GLPanEdgeRight
25 | };
26 |
27 |
28 | ///**
29 | // 手势转场类型
30 | //
31 | // - GLInteractiveTransitionPush: push
32 | // - GLInteractiveTransitionPop: pop
33 | // - GLInteractiveTransitionPresent: present
34 | // - GLInteractiveTransitionDismiss: dismiss
35 | // */
36 | //typedef NS_ENUM(NSInteger,GLInteractiveTransitionType) {
37 | // GLInteractiveTransitionPush = 0,
38 | // GLInteractiveTransitionPop,
39 | // GLInteractiveTransitionPresent ,
40 | // GLInteractiveTransitionDismiss
41 | //};
42 |
43 |
44 | @interface GLInteractiveTransition : UIPercentDrivenInteractiveTransition
45 |
46 | /**
47 | 是否满足侧滑手势交互
48 | */
49 | @property (nonatomic,assign) BOOL isPanGestureInteration;
50 |
51 |
52 | /**
53 | 转场时的操作 不用传参数的block
54 | */
55 | @property (nonatomic,copy) dispatch_block_t eventBlcok;
56 |
57 | /**
58 | 添加侧滑手势
59 |
60 | @param view 添加手势的view
61 | @param direction 手势的方向
62 | */
63 | - (void)addEdgePageGestureWithView:(UIView *)view direction:(GLEdgePanGestureDirection)direction;
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/TableViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewController.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "TableViewController.h"
10 |
11 |
12 | @interface TableViewController ()
13 |
14 | @property (nonatomic,copy) NSArray *dataSource;
15 | @property (nonatomic,copy) NSArray *dataVcs;
16 |
17 | @end
18 |
19 | @implementation TableViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 |
24 | self.dataSource = @[@"CircleSpread",@"CircleRectSpread",@"OpenDoor",@"MiddlePage"];
25 | self.dataVcs = @[@"CircleSpreadFromController",@"CircleRectSpreadFromViewController",@"OpenDoorFromViewController",@"MiddlePageFromViewController"];
26 | self.tableView.tableFooterView = [[UIView alloc] init];
27 | }
28 |
29 | - (void)didReceiveMemoryWarning {
30 | [super didReceiveMemoryWarning];
31 | }
32 |
33 | #pragma mark - Table view data source
34 |
35 |
36 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
37 |
38 | return self.dataSource.count;
39 | }
40 |
41 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
42 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"testcell" forIndexPath:indexPath];
43 |
44 | cell.textLabel.text = self.dataSource[indexPath.row];
45 |
46 | return cell;
47 | }
48 |
49 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
50 | {
51 | UIViewController *pushVC = [[NSClassFromString(self.dataVcs[indexPath.row]) alloc] init];
52 | [self.navigationController pushViewController:pushVC animated:YES];
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/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 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/OpenDoorVc/OpenDoorFromViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // OpenDoorFromViewController.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/30.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "OpenDoorFromViewController.h"
10 | #import "OpenDoorToViewController.h"
11 |
12 | #import "UIViewController+GLTransition.h"
13 | #import "GLOpenDoorAnimation.h"
14 |
15 | @interface OpenDoorFromViewController ()
16 |
17 | @property (nonatomic,strong) UIButton *animationButton;
18 |
19 | @end
20 |
21 | @implementation OpenDoorFromViewController
22 |
23 | - (void)viewDidLoad {
24 | [super viewDidLoad];
25 |
26 | [self.view.layer setContents:(id)[UIImage imageNamed:@"11"].CGImage];
27 |
28 | [self.view addSubview:self.animationButton];
29 | }
30 |
31 |
32 | #pragma mark == event response
33 | - (void)animationButtonClick:(UIButton *)sender
34 | {
35 | GLOpenDoorAnimation *openDoorAnimation = [[GLOpenDoorAnimation alloc] init];
36 | openDoorAnimation.duration = 0.5;
37 |
38 | OpenDoorToViewController *openDoorToVc = [[OpenDoorToViewController alloc] init];
39 | [self gl_presentViewControler:openDoorToVc withAnimation:openDoorAnimation];
40 | }
41 |
42 | #pragma mark == 懒加载
43 | - (UIButton *)animationButton
44 | {
45 | if (nil == _animationButton)
46 | {
47 | _animationButton = [UIButton buttonWithType:UIButtonTypeCustom];
48 | _animationButton.frame = CGRectMake(0, 0, 60, 60);
49 | _animationButton.center = self.view.center;
50 | _animationButton.layer.cornerRadius = 30;
51 | [_animationButton addTarget:self action:@selector(animationButtonClick:) forControlEvents:UIControlEventTouchUpInside];
52 | [_animationButton setImage:[UIImage imageNamed:@"圆"] forState:UIControlStateNormal];
53 | _animationButton.adjustsImageWhenHighlighted = NO;
54 | }
55 | return _animationButton;
56 | }
57 |
58 |
59 | - (void)didReceiveMemoryWarning {
60 | [super didReceiveMemoryWarning];
61 | // Dispose of any resources that can be recreated.
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleRectSpreadVc/CircleRectSpreadToViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRectSpreadToViewController.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "CircleRectSpreadToViewController.h"
10 | #import "UIViewController+GLTransition.h"
11 |
12 |
13 |
14 | @interface CircleRectSpreadToViewController ()
15 |
16 | @property (nonatomic,strong) UIButton *animationButton;
17 |
18 | @end
19 |
20 | @implementation CircleRectSpreadToViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 |
25 | self.view.backgroundColor = UICOLOR_FROM_RGB_OxFF(0x4876FF);
26 |
27 | UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(0, 150, self.view.frame.size.width, 50)];
28 | lable.font = [UIFont systemFontOfSize:40];
29 | lable.textColor = [UIColor whiteColor];
30 | lable.textAlignment = NSTextAlignmentCenter;
31 | lable.text = @"Hello World!";
32 | [self.view addSubview:lable];
33 |
34 | [self.view addSubview:self.animationButton];
35 | }
36 |
37 | #pragma mark == event response
38 | - (void)animationButtonClick:(UIButton *)sender
39 | {
40 | [self dismissViewControllerAnimated:YES completion:nil];
41 | }
42 |
43 | #pragma mark == 懒加载
44 | - (UIButton *)animationButton
45 | {
46 | if (nil == _animationButton)
47 | {
48 | _animationButton = [UIButton buttonWithType:UIButtonTypeCustom];
49 | _animationButton.frame = CGRectMake((self.view.frame.size.width - 60)/2.0, self.view.frame.size.height-120, 60, 60);
50 | _animationButton.layer.cornerRadius = 30;
51 | [_animationButton addTarget:self action:@selector(animationButtonClick:) forControlEvents:UIControlEventTouchUpInside];
52 | [_animationButton setImage:[UIImage imageNamed:@"叉"] forState:UIControlStateNormal];
53 | _animationButton.adjustsImageWhenHighlighted = NO;
54 | }
55 | return _animationButton;
56 | }
57 |
58 | - (void)didReceiveMemoryWarning {
59 | [super didReceiveMemoryWarning];
60 | // Dispose of any resources that can be recreated.
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleSpreadVc/CircleSpreadFromController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // GLPushAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/8.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "CircleSpreadFromController.h"
10 | #import "GLCircleSpreadAnimation.h"
11 | #import "UIViewController+GLTransition.h"
12 | #import "CircleSpreadToController.h"
13 |
14 | @interface CircleSpreadFromController ()
15 |
16 | @property (nonatomic,strong) UIButton *animationButton;
17 |
18 | @end
19 |
20 | @implementation CircleSpreadFromController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 |
25 | [self.view.layer setContents:(id)[UIImage imageNamed:@"4"].CGImage];
26 |
27 | [self.view addSubview:self.animationButton];
28 | }
29 |
30 |
31 | - (void)viewDidDisappear:(BOOL)animated
32 | {
33 | [super viewDidDisappear:animated];
34 | }
35 |
36 | #pragma mark == event response
37 | - (void)animationButtonClick:(UIButton *)sender
38 | {
39 | GLCircleSpreadAnimation *circleSpreadAnimation = [[GLCircleSpreadAnimation alloc] initWithStartPoint:self.animationButton.center radius:30];
40 |
41 | CircleSpreadToController *secondVc = [[CircleSpreadToController alloc] init];
42 |
43 | [self gl_pushViewControler:secondVc withAnimation:circleSpreadAnimation];
44 | // [self gl_presentViewControler:secondVc withAnimation:circleSpreadAnimation];
45 | }
46 |
47 |
48 | #pragma mark == 懒加载
49 | - (UIButton *)animationButton
50 | {
51 | if (nil == _animationButton)
52 | {
53 | _animationButton = [UIButton buttonWithType:UIButtonTypeCustom];
54 | _animationButton.frame = CGRectMake(80, 120, 60, 60);
55 | _animationButton.layer.cornerRadius = 30;
56 | [_animationButton addTarget:self action:@selector(animationButtonClick:) forControlEvents:UIControlEventTouchUpInside];
57 | [_animationButton setImage:[UIImage imageNamed:@"运动"] forState:UIControlStateNormal];
58 | }
59 | return _animationButton;
60 | }
61 |
62 |
63 | - (void)didReceiveMemoryWarning {
64 | [super didReceiveMemoryWarning];
65 | // Dispose of any resources that can be recreated.
66 | }
67 |
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/ViewController/CircleRectSpreadVc/CircleRectSpreadFromViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRectSpreadFromViewController.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "CircleRectSpreadFromViewController.h"
10 | #import "CircleRectSpreadToViewController.h"
11 | #import "UIViewController+GLTransition.h"
12 | #import "GLCircleRectSpreadAnimation.h"
13 |
14 | @interface CircleRectSpreadFromViewController ()
15 |
16 | @property (nonatomic,strong) UIButton *animationButton;
17 |
18 | @end
19 |
20 | @implementation CircleRectSpreadFromViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 |
25 | self.view.backgroundColor = [UIColor whiteColor];
26 |
27 | [self.view addSubview:self.animationButton];
28 | }
29 |
30 |
31 |
32 | #pragma mark == event response
33 | - (void)animationButtonClick:(UIButton *)sender
34 | {
35 | GLCircleRectSpreadAnimation *circleSpreadAnimation = [[GLCircleRectSpreadAnimation alloc] initWithStartPoint:self.animationButton.center];
36 | circleSpreadAnimation.duration = 0.5;
37 |
38 | CircleRectSpreadToViewController *secondVc = [[CircleRectSpreadToViewController alloc] init];
39 |
40 | [self gl_presentViewControler:secondVc withAnimation:circleSpreadAnimation];
41 | }
42 |
43 | - (void)didReceiveMemoryWarning {
44 | [super didReceiveMemoryWarning];
45 | // Dispose of any resources that can be recreated.
46 | }
47 |
48 | #pragma mark == 懒加载
49 | - (UIButton *)animationButton
50 | {
51 | if (nil == _animationButton)
52 | {
53 | _animationButton = [UIButton buttonWithType:UIButtonTypeCustom];
54 | _animationButton.frame = CGRectMake((self.view.frame.size.width - 60)/2.0, self.view.frame.size.height-120, 60, 60);
55 | _animationButton.layer.cornerRadius = 30;
56 | [_animationButton addTarget:self action:@selector(animationButtonClick:) forControlEvents:UIControlEventTouchUpInside];
57 | [_animationButton setImage:[UIImage imageNamed:@"加"] forState:UIControlStateNormal];
58 | _animationButton.adjustsImageWhenHighlighted = NO;
59 | }
60 | return _animationButton;
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/23.
6 | // Copyright © 2017年 高磊. 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 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/UIViewController+GLTransition.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+GLTransition.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/24.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+GLTransition.h"
10 | #import "GLTransitionManager.h"
11 | #import
12 |
13 | NSString *const kAnimationKey = @"kAnimationKey";
14 | NSString *const kToAnimationKey = @"kToAnimationKey";
15 |
16 |
17 | @implementation UIViewController (GLTransition)
18 |
19 |
20 |
21 |
22 | #pragma mark == public method
23 |
24 |
25 | - (void)gl_pushViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager *)transitionManager
26 | {
27 | if (!viewController) {
28 | return;
29 | }
30 | if (!transitionManager) {
31 | return;
32 | }
33 |
34 | if (self.navigationController) {
35 |
36 | self.navigationController.delegate = transitionManager;
37 |
38 | GLInteractiveTransition *toInteractiveTransition = objc_getAssociatedObject(self, &kToAnimationKey);
39 | if (toInteractiveTransition) {
40 | [transitionManager setValue:toInteractiveTransition forKey:@"toInteractiveTransition"];
41 | }
42 |
43 | objc_setAssociatedObject(viewController, &kAnimationKey, transitionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
44 | [self.navigationController pushViewController:viewController animated:YES];
45 |
46 | }
47 | }
48 |
49 | - (void)gl_presentViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager *)transitionManager
50 | {
51 | if (!viewController) {
52 | return;
53 | }
54 | if (!transitionManager) {
55 | return;
56 | }
57 | //present 动画代理 被执行动画的vc设置代理
58 | viewController.transitioningDelegate = transitionManager;
59 |
60 | GLInteractiveTransition *toInteractiveTransition = objc_getAssociatedObject(self, &kToAnimationKey);
61 | if (toInteractiveTransition) {
62 | [transitionManager setValue:toInteractiveTransition forKey:@"toInteractiveTransition"];
63 | }
64 | objc_setAssociatedObject(viewController, &kAnimationKey, transitionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
65 |
66 | [self presentViewController:viewController animated:YES completion:nil];
67 | }
68 |
69 | - (void)gl_registerToInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok
70 | {
71 | GLInteractiveTransition *interactiveTransition = [[GLInteractiveTransition alloc] init];
72 | interactiveTransition.eventBlcok = blcok;
73 | [interactiveTransition addEdgePageGestureWithView:self.view direction:direction];
74 |
75 | objc_setAssociatedObject(self, &kToAnimationKey, interactiveTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
76 | }
77 |
78 | - (void)gl_registerBackInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok
79 | {
80 | GLInteractiveTransition *interactiveTransition = [[GLInteractiveTransition alloc] init];
81 | interactiveTransition.eventBlcok = blcok;
82 | [interactiveTransition addEdgePageGestureWithView:self.view direction:direction];
83 |
84 | //判读是否需要返回 然后添加侧滑
85 | GLTransitionManager *animator = objc_getAssociatedObject(self, &kAnimationKey);
86 | if (animator)
87 | {
88 | //用kvc的模式 给 animator的backInteractiveTransition 退场赋值
89 | [animator setValue:interactiveTransition forKey:@"backInteractiveTransition"];
90 | }
91 | }
92 |
93 | @end
94 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo.xcodeproj/xcuserdata/gaolei.xcuserdatad/xcschemes/GLTransitionAnimationDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLCircleRectSpreadAnimation.m:
--------------------------------------------------------------------------------
1 | //
2 | // GLCircleRectSpreadAnimation.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/27.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLCircleRectSpreadAnimation.h"
10 |
11 | @interface GLCircleRectSpreadAnimation ()
12 |
13 | @property (nonatomic,strong) UIView *startView;
14 |
15 | @property (nonatomic,assign) CGPoint centerPoint;
16 |
17 | @end
18 |
19 | @implementation GLCircleRectSpreadAnimation
20 |
21 | - (id)initWithStartPoint:(CGPoint )point
22 | {
23 | self = [super init];
24 | if (self) {
25 | self.centerPoint = point;
26 | }
27 | return self;
28 | }
29 |
30 |
31 | #pragma mark == private method
32 | - (CGRect)frameToCircle:(CGPoint)centerPoint size:(CGSize)size
33 | {
34 | CGFloat radius_x = fmax(centerPoint.x, size.width - centerPoint.x);
35 | CGFloat radius_y = fmax(centerPoint.y, size.height - centerPoint.y);
36 | CGFloat endRadius = 2 * sqrtf(pow(radius_x, 2) + pow(radius_y, 2));
37 |
38 | CGRect rect = {CGPointZero,CGSizeMake(endRadius, endRadius)};
39 |
40 | return rect;
41 | }
42 |
43 |
44 | - (void)setToAnimation:(id)contextTransition
45 | {
46 | //获取目标动画的VC
47 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
48 | UIView *containerView = [contextTransition containerView];
49 |
50 | // [toVc beginAppearanceTransition:YES animated:YES];
51 | CGPoint center = toVc.view.center;
52 |
53 | CGRect rect = [self frameToCircle:self.centerPoint size:toVc.view.bounds.size];
54 | UIView *backView = [[UIView alloc] initWithFrame:rect];
55 | backView.backgroundColor = UICOLOR_FROM_RGB_OxFF(0xFFA500);
56 | backView.center = self.centerPoint;
57 | backView.layer.cornerRadius = backView.frame.size.height / 2.0;
58 | backView.transform = CGAffineTransformMakeScale(0.01, 0.01);
59 | [containerView addSubview:backView];
60 |
61 | self.startView = backView;
62 |
63 | toVc.view.transform = CGAffineTransformMakeScale(0.01, 0.01);
64 | toVc.view.alpha = 0;
65 | toVc.view.center = self.centerPoint;
66 | [containerView addSubview:toVc.view];
67 |
68 |
69 | [UIView animateWithDuration:self.duration animations:^{
70 |
71 | backView.transform = CGAffineTransformIdentity;
72 |
73 | toVc.view.center = center;
74 | toVc.view.transform = CGAffineTransformIdentity;
75 | toVc.view.alpha = 1;
76 |
77 | } completion:^(BOOL finished) {
78 | [contextTransition completeTransition:!contextTransition.transitionWasCancelled];
79 |
80 | // [toVc endAppearanceTransition];
81 | }];
82 | }
83 |
84 | - (void)setBackAnimation:(id)contextTransition
85 | {
86 | //获取目标动画的VC
87 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
88 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
89 |
90 | UIView *containerView = [contextTransition containerView];
91 | [containerView insertSubview:toVc.view atIndex:0];
92 |
93 | [UIView animateWithDuration:self.duration animations:^{
94 | //缩小
95 | self.startView.transform = CGAffineTransformMakeScale(0.01, 0.01);
96 |
97 | fromVc.view.center = self.centerPoint;
98 | fromVc.view.transform = CGAffineTransformMakeScale(0.01, 0.01);
99 | fromVc.view.alpha = 0;
100 |
101 | } completion:^(BOOL finished) {
102 | [contextTransition completeTransition:!contextTransition.transitionWasCancelled];
103 | [self.startView removeFromSuperview];
104 | }];
105 | }
106 |
107 | @end
108 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/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 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLInteractiveTransition.m:
--------------------------------------------------------------------------------
1 | //
2 | // GLInteractiveTransition.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/24.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | // 手势转场控制类
8 |
9 | #import "GLInteractiveTransition.h"
10 |
11 | @interface GLInteractiveTransition ()
12 |
13 | /**
14 | 保存添加手势的view
15 | */
16 | @property (nonatomic,strong) UIView *gestureView;
17 |
18 | /**
19 | 屏幕侧滑手势
20 | */
21 | @property (nonatomic,strong) UIScreenEdgePanGestureRecognizer *panGesture;
22 |
23 | //@property (nonatomic,assign) GLInteractiveTransitionType transitionType;
24 |
25 | @end
26 |
27 | @implementation GLInteractiveTransition
28 |
29 | - (void)addEdgePageGestureWithView:(UIView *)view direction:(GLEdgePanGestureDirection)direction
30 | {
31 | UIScreenEdgePanGestureRecognizer *popRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePopRecognizer:)];
32 | switch (direction) {
33 | case GLPanEdgeLeft:
34 | {
35 | popRecognizer.edges = UIRectEdgeLeft;
36 | }
37 | break;
38 | case GLPanEdgeTop:
39 | {
40 | popRecognizer.edges = UIRectEdgeTop;
41 | }
42 | break;
43 | case GLPanEdgeBottom:
44 | {
45 | popRecognizer.edges = UIRectEdgeBottom;
46 | }
47 | break;
48 | case GLPanEdgeRight:
49 | {
50 | popRecognizer.edges = UIRectEdgeRight;
51 | }
52 | break;
53 | default:
54 | break;
55 | }
56 |
57 | self.gestureView = view;
58 | [self.gestureView addGestureRecognizer:popRecognizer];
59 | }
60 |
61 | - (void)handlePopRecognizer:(UIPanGestureRecognizer*)recognizer {
62 | // 计算用户手指划了多远
63 |
64 | CGFloat progress = fabs([recognizer translationInView:self.gestureView].x) / (self.gestureView.bounds.size.width * 1.0);
65 | progress = MIN(1.0, MAX(0.0, progress));
66 |
67 | switch (recognizer.state) {
68 | case UIGestureRecognizerStateBegan:
69 | {
70 | _isPanGestureInteration = YES;
71 |
72 | if (self.eventBlcok) {
73 | self.eventBlcok();
74 | }
75 |
76 | // 创建过渡对象,弹出viewController
77 | //
78 | // UIViewController *fromVc = [self gl_viewController];
79 | //
80 | // switch (self.transitionType) {
81 | // case GLInteractiveTransitionPush:
82 | // {
83 | //
84 | // }
85 | // break;
86 | // case GLInteractiveTransitionPop:
87 | // {
88 | // if (fromVc.navigationController) {
89 | // [fromVc.navigationController popViewControllerAnimated:YES];
90 | // }
91 | // }
92 | // break;
93 | // case GLInteractiveTransitionPresent:
94 | // {
95 | //
96 | // }
97 | // break;
98 | // case GLInteractiveTransitionDismiss:
99 | // {
100 | // [fromVc dismissViewControllerAnimated:YES completion:nil];
101 | // }
102 | // break;
103 | // default:
104 | // break;
105 | // }
106 | break;
107 | }
108 | case UIGestureRecognizerStateChanged:
109 | {
110 | // 更新 interactive transition 的进度
111 | [self updateInteractiveTransition:progress];
112 | break;
113 | }
114 | case UIGestureRecognizerStateEnded:
115 | case UIGestureRecognizerStateCancelled:
116 | {
117 | // NSLog(@" 打印信息:%f",progress);
118 | // 完成或者取消过渡
119 | if (progress > 0.5) {
120 | [self finishInteractiveTransition];
121 | }
122 | else {
123 | [self cancelInteractiveTransition];
124 | }
125 |
126 | _isPanGestureInteration = NO;
127 | break;
128 | }
129 | default:
130 | break;
131 | }
132 | }
133 |
134 |
135 | //- (UIViewController *)gl_viewController {
136 | // UIResponder *nextResponder = self.gestureView;
137 | // do
138 | // {
139 | // nextResponder = [nextResponder nextResponder];
140 | //
141 | // if ([nextResponder isKindOfClass:[UIViewController class]])
142 | // return (UIViewController*)nextResponder;
143 | //
144 | // } while (nextResponder != nil);
145 | //
146 | // return nil;
147 | //}
148 |
149 | @end
150 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLCircleSpreadAnimation.m:
--------------------------------------------------------------------------------
1 | //
2 | // GLCircleSpreadAnimation.m
3 | // GLPushAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/16.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLCircleSpreadAnimation.h"
10 |
11 | @interface GLCircleSpreadAnimation ()
12 |
13 | //动画的中心坐标
14 | @property (nonatomic,assign) CGPoint centerPoint;
15 | //半径
16 | @property (nonatomic,assign) CGFloat radius;
17 | //保存layer在动画结束的时候 可以根据这个来获取添加的动画
18 | @property (nonatomic,strong) CAShapeLayer *maskShapeLayer;
19 | //保存转场动画开始时的路径 当退出动画取消的时候 保存原理的样子
20 | @property (nonatomic, strong) UIBezierPath *startPath;
21 |
22 | @end
23 |
24 | @implementation GLCircleSpreadAnimation
25 |
26 | - (id)initWithStartPoint:(CGPoint)point radius:(CGFloat)radius
27 | {
28 | self = [super init];
29 | if (self) {
30 | self.centerPoint = point;
31 | self.radius = radius;
32 | }
33 | return self;
34 | }
35 |
36 | //具体实现
37 | - (void)setToAnimation:(id)contextTransition
38 | {
39 | //获取目标动画的VC
40 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
41 | UIView *containerView = [contextTransition containerView];
42 | [containerView addSubview:toVc.view];
43 |
44 | //创建UIBezierPath路径 作为后面动画的起始路径
45 | UIBezierPath *startPath = [UIBezierPath bezierPathWithArcCenter:self.centerPoint radius:self.radius startAngle:0 endAngle:2*M_PI clockwise:YES];
46 |
47 | //创建结束UIBezierPath
48 | //首先我们需要得到后面路径的半径 半径应该是距四个角最远的距离
49 | CGFloat x = self.centerPoint.x;
50 | CGFloat y = self.centerPoint.y;
51 | //取出其中距屏幕最远的距离 来求围城矩形的对角线 即我们所需要的半径
52 | CGFloat radius_x = MAX(x, containerView.frame.size.width - x);
53 | CGFloat radius_y = MAX(y, containerView.frame.size.height - y);
54 | //补充下 sqrtf求平方根 double pow(double x, double y); 求 x 的 y 次幂(次方)
55 | //通过勾股定理算出半径
56 | CGFloat endRadius = sqrtf(pow(radius_x, 2) + pow(radius_y, 2));
57 |
58 | UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:self.centerPoint radius:endRadius startAngle:0 endAngle:2*M_PI clockwise:YES];
59 |
60 | // self.endPath = endPath;
61 |
62 | //创建CAShapeLayer 用以后面的动画
63 | CAShapeLayer *shapeLayer = [CAShapeLayer layer];
64 | shapeLayer.path = endPath.CGPath;
65 | toVc.view.layer.mask = shapeLayer;
66 |
67 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
68 | animation.fromValue = (__bridge id _Nullable)(startPath.CGPath);
69 | animation.duration = self.duration;
70 | animation.delegate = (id)self;
71 | // animation.removedOnCompletion = NO;//执行后移除动画
72 | //保存contextTransition 后面动画结束的时候调用
73 | [animation setValue:contextTransition forKey:@"pathContextTransition"];
74 | [shapeLayer addAnimation:animation forKey:nil];
75 |
76 | self.maskShapeLayer = shapeLayer;
77 | }
78 |
79 | - (void)setBackAnimation:(id)contextTransition
80 | {
81 | //将tovc的view放到最下面一层
82 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
83 |
84 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
85 | UIView *containerView = [contextTransition containerView];
86 | [containerView insertSubview:toVc.view atIndex:0];
87 |
88 | //push前的 startPath 作为endPath
89 | UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:self.centerPoint radius:self.radius startAngle:0 endAngle:2*M_PI clockwise:YES];
90 |
91 | CAShapeLayer *shapeLayer = (CAShapeLayer *)fromVc.view.layer.mask;
92 | self.maskShapeLayer = shapeLayer;
93 | //将pop后的 path作为startPath
94 | UIBezierPath *startPath = [UIBezierPath bezierPathWithCGPath:shapeLayer.path];
95 | self.startPath = startPath;
96 | shapeLayer.path = endPath.CGPath;
97 |
98 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
99 | animation.fromValue = (__bridge id _Nullable)(startPath.CGPath);
100 | animation.toValue = (__bridge id _Nullable)(endPath.CGPath);
101 | animation.duration = self.duration;
102 | animation.delegate = (id)self;
103 | // animation.removedOnCompletion = NO;//执行后移除动画
104 | //保存contextTransition 后面动画结束的时候调用
105 | [animation setValue:contextTransition forKey:@"pathContextTransition"];
106 | [shapeLayer addAnimation:animation forKey:nil];
107 | }
108 |
109 |
110 | #pragma mark == CAAnimationDelegate
111 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
112 | {
113 | id contextTransition = [anim valueForKey:@"pathContextTransition"];
114 |
115 | //取消的时候 将动画还原到之前的路径
116 | if (contextTransition.transitionWasCancelled) {
117 | self.maskShapeLayer.path = self.startPath.CGPath;
118 | }
119 | // 声明过渡结束
120 | [contextTransition completeTransition:!contextTransition.transitionWasCancelled];
121 | }
122 |
123 | @end
124 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLTransitionManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // GLTransitionManager.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/23.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLTransitionManager.h"
10 | #import "GLTransitionAnimation.h"
11 | #import "GLInteractiveTransition.h"
12 |
13 | @interface GLTransitionManager ()
14 |
15 |
16 | /**
17 | 入场动画
18 | */
19 | @property (nonatomic,strong) GLTransitionAnimation *toTransitionAnimation;
20 |
21 | /**
22 | 退场动画
23 | */
24 | @property (nonatomic,strong) GLTransitionAnimation *backTransitionAnimation;
25 |
26 | /**
27 | 入场手势
28 | */
29 | @property (nonatomic,strong) GLInteractiveTransition *toInteractiveTransition;
30 |
31 | /**
32 | 退场手势
33 | */
34 | @property (nonatomic,strong) GLInteractiveTransition *backInteractiveTransition;
35 |
36 |
37 | /**
38 | 转场类型 push or pop
39 | */
40 | @property (nonatomic,assign) UINavigationControllerOperation operation;
41 |
42 | @end
43 |
44 | @implementation GLTransitionManager
45 |
46 | - (void)dealloc
47 | {
48 |
49 | }
50 |
51 | - (id)init
52 | {
53 | self = [super init];
54 | if (self) {
55 | self.duration = 0.5;
56 | }
57 | return self;
58 | }
59 |
60 |
61 | #pragma mark == public method
62 | - (void)setToAnimation:(id)contextTransition
63 | {
64 | //需在子类中进行重写
65 | }
66 |
67 | - (void)setBackAnimation:(id)contextTransition
68 | {
69 | //需在子类中进行重写
70 | }
71 |
72 |
73 | #pragma mark == UIViewControllerTransitioningDelegate
74 | //非手势转场交互 for present
75 | - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
76 | return self.toTransitionAnimation;
77 | }
78 |
79 | //非手势转场交互 for dismiss
80 | - (id)animationControllerForDismissedController:(UIViewController *)dismissed{
81 | return self.backTransitionAnimation;
82 | }
83 |
84 | //手势交互 for dismiss
85 | - (id)interactionControllerForDismissal:(id)animator{
86 | return self.backInteractiveTransition.isPanGestureInteration ? self.backInteractiveTransition:nil;
87 | }
88 |
89 | //手势交互 for present
90 | - (id)interactionControllerForPresentation:(id)animator{
91 | return self.toInteractiveTransition.isPanGestureInteration ? self.toInteractiveTransition:nil;
92 | }
93 |
94 |
95 |
96 | #pragma mark == UINavigationControllerDelegate
97 | //执行顺序 先
98 | //非手势转场交互 for push or pop
99 | /*****注释:通过 fromVC 和 toVC 我们可以在此设置需要自定义动画的类 *****/
100 | - (id )navigationController:(UINavigationController *)navigationController
101 | animationControllerForOperation:(UINavigationControllerOperation)operation
102 | fromViewController:(UIViewController *)fromVC
103 | toViewController:(UIViewController *)toVC
104 | {
105 | _operation = operation;
106 |
107 | if (operation == UINavigationControllerOperationPush)
108 | {
109 | return self.toTransitionAnimation;
110 | }
111 | else if (operation == UINavigationControllerOperationPop)
112 | {
113 | return self.backTransitionAnimation;
114 | }
115 | else
116 | {
117 | return nil;
118 | }
119 | }
120 |
121 | //手势交互 for push or pop
122 | - (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id)animationController
123 | {
124 | if (_operation == UINavigationControllerOperationPush) {
125 | return self.toInteractiveTransition.isPanGestureInteration ? self.toInteractiveTransition:nil;
126 | }
127 | else{
128 | return self.backInteractiveTransition.isPanGestureInteration ? self.backInteractiveTransition:nil;
129 | }
130 | }
131 |
132 |
133 | #pragma mark == setter
134 | - (void)setBackInteractiveTransition:(GLInteractiveTransition *)backInteractiveTransition
135 | {
136 | _backInteractiveTransition = backInteractiveTransition;
137 | }
138 |
139 | - (void)setToInteractiveTransition:(GLInteractiveTransition *)toInteractiveTransition
140 | {
141 | _toInteractiveTransition = toInteractiveTransition;
142 | }
143 |
144 | #pragma mark == 懒加载
145 | - (GLTransitionAnimation *)toTransitionAnimation
146 | {
147 | if (nil == _toTransitionAnimation) {
148 | __weak typeof(self) weakSelf = self;
149 | _toTransitionAnimation = [[GLTransitionAnimation alloc] initWithDuration:self.duration ];
150 | _toTransitionAnimation.animationBlock = ^(id contextTransition)
151 | {
152 | [weakSelf setToAnimation:contextTransition];
153 | };
154 | }
155 | return _toTransitionAnimation;
156 | }
157 |
158 | - (GLTransitionAnimation *)backTransitionAnimation
159 | {
160 | if (nil == _backTransitionAnimation) {
161 | __weak typeof(self) weakSelf = self;
162 | _backTransitionAnimation = [[GLTransitionAnimation alloc] initWithDuration:self.duration];
163 | _backTransitionAnimation.animationBlock = ^(id contextTransition)
164 | {
165 | [weakSelf setBackAnimation:contextTransition];
166 | };
167 | }
168 | return _backTransitionAnimation;
169 | }
170 |
171 |
172 |
173 | @end
174 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLOpenDoorAnimation.m:
--------------------------------------------------------------------------------
1 | //
2 | // GLOpenDoorAnimation.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/30.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLOpenDoorAnimation.h"
10 |
11 | @implementation GLOpenDoorAnimation
12 |
13 | - (void)setToAnimation:(id)contextTransition
14 | {
15 | //获取目标动画的VC
16 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
17 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
18 | UIView *containerView = [contextTransition containerView];
19 |
20 | UIView *fromView = fromVc.view;
21 | UIView *toView = toVc.view;
22 |
23 | //截图
24 | UIView *toView_snapView = [toView snapshotViewAfterScreenUpdates:YES];
25 |
26 | CGRect left_frame = CGRectMake(0, 0, CGRectGetWidth(fromView.frame) / 2.0, CGRectGetHeight(fromView.frame));
27 | CGRect right_frame = CGRectMake(CGRectGetWidth(fromView.frame) / 2.0, 0, CGRectGetWidth(fromView.frame) / 2.0, CGRectGetHeight(fromView.frame));
28 | UIView *from_left_snapView = [fromView resizableSnapshotViewFromRect:left_frame
29 | afterScreenUpdates:NO
30 | withCapInsets:UIEdgeInsetsZero];
31 |
32 | UIView *from_right_snapView = [fromView resizableSnapshotViewFromRect:right_frame
33 | afterScreenUpdates:NO
34 | withCapInsets:UIEdgeInsetsZero];
35 |
36 | toView_snapView.layer.transform = CATransform3DMakeScale(0.7, 0.7, 1);
37 | from_left_snapView.frame = left_frame;
38 | from_right_snapView.frame = right_frame;
39 |
40 | //将截图添加到 containerView 上
41 | [containerView addSubview:toView_snapView];
42 | [containerView addSubview:from_left_snapView];
43 | [containerView addSubview:from_right_snapView];
44 |
45 | fromView.hidden = YES;
46 |
47 | [UIView animateWithDuration:self.duration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
48 | //左移
49 | from_left_snapView.frame = CGRectOffset(from_left_snapView.frame, -from_left_snapView.frame.size.width, 0);
50 | //右移
51 | from_right_snapView.frame = CGRectOffset(from_right_snapView.frame, from_right_snapView.frame.size.width, 0);
52 |
53 | toView_snapView.layer.transform = CATransform3DIdentity;
54 |
55 | } completion:^(BOOL finished) {
56 | fromView.hidden = NO;
57 |
58 | [from_left_snapView removeFromSuperview];
59 | [from_right_snapView removeFromSuperview];
60 | [toView_snapView removeFromSuperview];
61 |
62 | if ([contextTransition transitionWasCancelled]) {
63 | [containerView addSubview:fromView];
64 | } else {
65 | [containerView addSubview:toView];
66 | }
67 | [contextTransition completeTransition:![contextTransition transitionWasCancelled]];
68 | }];
69 | }
70 |
71 | - (void)setBackAnimation:(id)contextTransition
72 | {
73 | //获取目标动画的VC
74 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
75 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
76 | UIView *containerView = [contextTransition containerView];
77 |
78 | UIView *fromView = fromVc.view;
79 | UIView *toView = toVc.view;
80 |
81 | //截图
82 | UIView *fromView_snapView = [fromView snapshotViewAfterScreenUpdates:YES];
83 |
84 |
85 | CGRect left_frame = CGRectMake(0, 0, CGRectGetWidth(toView.frame) / 2.0, CGRectGetHeight(toView.frame));
86 | CGRect right_frame = CGRectMake(CGRectGetWidth(toView.frame) / 2.0, 0, CGRectGetWidth(toView.frame) / 2.0, CGRectGetHeight(toView.frame));
87 | UIView *to_left_snapView = [toView resizableSnapshotViewFromRect:left_frame
88 | afterScreenUpdates:YES
89 | withCapInsets:UIEdgeInsetsZero];
90 |
91 | UIView *to_right_snapView = [toView resizableSnapshotViewFromRect:right_frame
92 | afterScreenUpdates:YES
93 | withCapInsets:UIEdgeInsetsZero];
94 |
95 | fromView_snapView.layer.transform = CATransform3DIdentity;
96 | to_left_snapView.frame = CGRectOffset(left_frame, -left_frame.size.width, 0);
97 | to_right_snapView.frame = CGRectOffset(right_frame, right_frame.size.width, 0);
98 |
99 | //将截图添加到 containerView 上
100 | [containerView addSubview:fromView_snapView];
101 | [containerView addSubview:to_left_snapView];
102 | [containerView addSubview:to_right_snapView];
103 |
104 | fromView.hidden = YES;
105 |
106 | [UIView animateWithDuration:self.duration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
107 | //右移
108 | to_left_snapView.frame = CGRectOffset(to_left_snapView.frame, to_left_snapView.frame.size.width, 0);
109 | //左移
110 | to_right_snapView.frame = CGRectOffset(to_right_snapView.frame, -to_right_snapView.frame.size.width, 0);
111 |
112 | fromView_snapView.layer.transform = CATransform3DMakeScale(0.7, 0.7, 1);
113 |
114 | } completion:^(BOOL finished) {
115 | fromView.hidden = NO;
116 | [fromView removeFromSuperview];
117 | [to_left_snapView removeFromSuperview];
118 | [to_right_snapView removeFromSuperview];
119 | [fromView_snapView removeFromSuperview];
120 |
121 | if ([contextTransition transitionWasCancelled]) {
122 | [containerView addSubview:fromView];
123 | } else {
124 | [containerView addSubview:toView];
125 | }
126 | [contextTransition completeTransition:![contextTransition transitionWasCancelled]];
127 | }];
128 | }
129 |
130 | @end
131 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo/GLTransitionAnimation/GLAnimation/GLMiddlePageAnimation.m:
--------------------------------------------------------------------------------
1 | //
2 | // GLMiddlePageAnimation.m
3 | // GLTransitionAnimationDemo
4 | //
5 | // Created by 高磊 on 2017/3/31.
6 | // Copyright © 2017年 高磊. All rights reserved.
7 | //
8 |
9 | #import "GLMiddlePageAnimation.h"
10 |
11 | @implementation GLMiddlePageAnimation
12 |
13 | - (void)setToAnimation:(id)contextTransition
14 | {
15 | //获取目标动画的VC
16 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
17 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
18 | UIView *containerView = [contextTransition containerView];
19 |
20 | //m34 这个参数有点不好理解 为透视效果 我在http://www.jianshu.com/p/e8d1985dccec这里有讲
21 | //当Z轴上有变化的时候 我们所看到的透视效果 可以对比看看 当你改成-0.1的时候 就懂了
22 | CATransform3D transform = CATransform3DIdentity;
23 | transform.m34 = -0.002;
24 | [containerView.layer setSublayerTransform:transform];
25 |
26 | UIView *fromView = fromVc.view;
27 | UIView *toView = toVc.view;
28 |
29 | //截图
30 | //当前页面的右侧
31 | CGRect from_half_right_rect = CGRectMake(fromView.frame.size.width/2.0, 0, fromView.frame.size.width/2.0, fromView.frame.size.height);
32 | //目标页面的左侧
33 | CGRect to_half_left_rect = CGRectMake(0, 0, toView.frame.size.width/2.0, toView.frame.size.height);
34 | //目标页面的右侧
35 | CGRect to_half_right_rect = CGRectMake(toView.frame.size.width/2.0, 0, toView.frame.size.width/2.0, toView.frame.size.height);
36 |
37 | //截三张图 当前页面的右侧 目标页面的左和右
38 | UIView *fromRightSnapView = [fromView resizableSnapshotViewFromRect:from_half_right_rect afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
39 | UIView *toLeftSnapView = [toView resizableSnapshotViewFromRect:to_half_left_rect afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
40 | UIView *toRightSnapView = [toView resizableSnapshotViewFromRect:to_half_right_rect afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
41 |
42 |
43 | fromRightSnapView.frame = from_half_right_rect;
44 | toLeftSnapView.frame = to_half_left_rect;
45 | toRightSnapView.frame = to_half_right_rect;
46 |
47 | //重新设置anchorPoint 分别绕自己的最左和最右旋转
48 | fromRightSnapView.layer.position = CGPointMake(CGRectGetMinX(fromRightSnapView.frame), CGRectGetMinY(fromRightSnapView.frame) + CGRectGetHeight(fromRightSnapView.frame) * 0.5);
49 | fromRightSnapView.layer.anchorPoint = CGPointMake(0, 0.5);
50 |
51 | toLeftSnapView.layer.position = CGPointMake(CGRectGetMinX(toLeftSnapView.frame) + CGRectGetWidth(toLeftSnapView.frame), CGRectGetMinY(toLeftSnapView.frame) + CGRectGetHeight(toLeftSnapView.frame) * 0.5);
52 | toLeftSnapView.layer.anchorPoint = CGPointMake(1, 0.5);
53 |
54 | //添加阴影效果
55 |
56 | UIView *fromRightShadowView = [self addShadowView:fromRightSnapView startPoint:CGPointMake(0, 1) endPoint:CGPointMake(1, 1)];
57 | UIView *toLeftShaDowView = [self addShadowView:toLeftSnapView startPoint:CGPointMake(1, 1) endPoint:CGPointMake(0, 1)];
58 |
59 | //添加视图 注意顺序
60 | [containerView insertSubview:toView atIndex:0];
61 | [containerView addSubview:toLeftSnapView];
62 | [containerView addSubview:toRightSnapView];
63 | [containerView addSubview:fromRightSnapView];
64 |
65 | toLeftSnapView.hidden = YES;
66 |
67 |
68 | //先旋转到最中间的位置
69 | toLeftSnapView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 1, 0);
70 | //StartTime 和 relativeDuration 均为百分百
71 | [UIView animateKeyframesWithDuration:self.duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
72 | [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{
73 |
74 | fromRightSnapView.layer.transform = CATransform3DMakeRotation(-M_PI_2, 0, 1, 0);
75 | fromRightShadowView.alpha = 1.0;
76 | }];
77 |
78 | [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{
79 | toLeftSnapView.hidden = NO;
80 | toLeftSnapView.layer.transform = CATransform3DIdentity;
81 | toLeftShaDowView.alpha = 0.0;
82 | }];
83 | } completion:^(BOOL finished) {
84 | [toLeftSnapView removeFromSuperview];
85 | [toRightSnapView removeFromSuperview];
86 | [fromRightSnapView removeFromSuperview];
87 | [fromView removeFromSuperview];
88 |
89 | if ([contextTransition transitionWasCancelled]) {
90 | [containerView addSubview:fromView];
91 | }
92 |
93 | [contextTransition completeTransition:![contextTransition transitionWasCancelled]];
94 | }];
95 |
96 |
97 |
98 | //本来打算用基础动画来实现 但是由于需要保存几个变量 在动画完成的代理函数中用,所以就取消这个想法了
99 | // CABasicAnimation *fromRightAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
100 | // fromRightAnimation.duration = self.duration/2.0;
101 | // fromRightAnimation.beginTime = CACurrentMediaTime();
102 | // fromRightAnimation.toValue = @(-M_PI_2);
103 | // [fromRightSnapView.layer addAnimation:fromRightAnimation forKey:nil];
104 | //
105 | //
106 | // CABasicAnimation *toLeftAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
107 | // toLeftAnimation.beginTime = CACurrentMediaTime() + self.duration/2.0;
108 | // toLeftAnimation.fromValue = @(M_PI_2);
109 | // [toLeftAnimation setValue:contextTransition forKey:@"contextTransition"];
110 | // [toLeftSnapView.layer addAnimation:toLeftAnimation forKey:@"toLeftAnimation"];
111 | }
112 |
113 | - (void)setBackAnimation:(id)contextTransition
114 | {
115 | //获取目标动画的VC
116 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
117 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
118 | UIView *containerView = [contextTransition containerView];
119 |
120 | //m34 这个参数有点不好理解 为透视效果 我在http://www.jianshu.com/p/e8d1985dccec这里有讲
121 | //当Z轴上有变化的时候 我们所看到的透视效果 可以对比看看 当你改成-0.1的时候 就懂了
122 | CATransform3D transform = CATransform3DIdentity;
123 | transform.m34 = -0.002;
124 | [containerView.layer setSublayerTransform:transform];
125 |
126 | UIView *fromView = fromVc.view;
127 | UIView *toView = toVc.view;
128 |
129 | //截图
130 | //当前页面的右侧
131 | CGRect from_half_left_rect = CGRectMake(0, 0, fromView.frame.size.width/2.0, fromView.frame.size.height);
132 | //目标页面的左侧
133 | CGRect to_half_left_rect = CGRectMake(0, 0, toView.frame.size.width/2.0, toView.frame.size.height);
134 | //目标页面的右侧
135 | CGRect to_half_right_rect = CGRectMake(toView.frame.size.width/2.0, 0, toView.frame.size.width/2.0, toView.frame.size.height);
136 |
137 | //截三张图 当前页面的右侧 目标页面的左和右
138 | UIView *fromLeftSnapView = [fromView resizableSnapshotViewFromRect:from_half_left_rect afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
139 | UIView *toLeftSnapView = [toView resizableSnapshotViewFromRect:to_half_left_rect afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
140 | UIView *toRightSnapView = [toView resizableSnapshotViewFromRect:to_half_right_rect afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
141 |
142 |
143 | fromLeftSnapView.frame = from_half_left_rect;
144 | toLeftSnapView.frame = to_half_left_rect;
145 | toRightSnapView.frame = to_half_right_rect;
146 |
147 | //重新设置anchorPoint 分别绕自己的最左和最右旋转
148 | fromLeftSnapView.layer.position = CGPointMake(CGRectGetMinX(fromLeftSnapView.frame) + CGRectGetWidth(fromLeftSnapView.frame), CGRectGetMinY(fromLeftSnapView.frame) + CGRectGetHeight(fromLeftSnapView.frame) * 0.5);
149 | fromLeftSnapView.layer.anchorPoint = CGPointMake(1, 0.5);
150 |
151 | toRightSnapView.layer.position = CGPointMake(CGRectGetMinX(toRightSnapView.frame), CGRectGetMinY(toRightSnapView.frame) + CGRectGetHeight(toRightSnapView.frame) * 0.5);
152 | toRightSnapView.layer.anchorPoint = CGPointMake(0, 0.5);
153 |
154 | //添加阴影效果
155 |
156 | UIView *fromLeftShadowView = [self addShadowView:fromLeftSnapView startPoint:CGPointMake(1, 1) endPoint:CGPointMake(0, 1)];
157 | UIView *toRightShaDowView = [self addShadowView:toRightSnapView startPoint:CGPointMake(0, 1) endPoint:CGPointMake(1, 1)];
158 |
159 | //添加视图 注意顺序
160 | [containerView insertSubview:toView atIndex:0];
161 | [containerView addSubview:toLeftSnapView];
162 | [containerView addSubview:toRightSnapView];
163 | [containerView addSubview:fromLeftSnapView];
164 |
165 | toRightSnapView.hidden = YES;
166 |
167 |
168 | //先旋转到最中间的位置
169 | toRightSnapView.layer.transform = CATransform3DMakeRotation(-M_PI_2, 0, 1, 0);
170 | //StartTime 和 relativeDuration 均为百分百
171 | [UIView animateKeyframesWithDuration:self.duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
172 | [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{
173 |
174 | fromLeftSnapView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 1, 0);
175 | fromLeftShadowView.alpha = 1.0;
176 | }];
177 |
178 | [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{
179 | toRightSnapView.hidden = NO;
180 | toRightSnapView.layer.transform = CATransform3DIdentity;
181 | toRightShaDowView.alpha = 0.0;
182 | }];
183 | } completion:^(BOOL finished) {
184 | [toLeftSnapView removeFromSuperview];
185 | [toRightSnapView removeFromSuperview];
186 | [fromLeftSnapView removeFromSuperview];
187 | [fromView removeFromSuperview];
188 |
189 | if ([contextTransition transitionWasCancelled]) {
190 | [containerView addSubview:fromView];
191 | }
192 |
193 | [contextTransition completeTransition:![contextTransition transitionWasCancelled]];
194 | }];
195 | }
196 |
197 | - (UIView *)addShadowView:(UIView *)view startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint{
198 | UIView *shadowView = [[UIView alloc] initWithFrame:view.bounds];
199 | [view addSubview:shadowView];
200 | //颜色可以渐变
201 | CAGradientLayer *gradientLayer = [CAGradientLayer layer];
202 | gradientLayer.frame = shadowView.bounds;
203 | [shadowView.layer addSublayer:gradientLayer];
204 | gradientLayer.colors = @[(id)[UIColor colorWithWhite:0 alpha:0.1].CGColor,(id)[UIColor colorWithWhite:0 alpha:0].CGColor];
205 | gradientLayer.startPoint = startPoint;
206 | gradientLayer.endPoint = endPoint;
207 |
208 | return shadowView;
209 | }
210 |
211 |
212 | @end
213 |
--------------------------------------------------------------------------------
/GLTransitionAnimationDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | EB1BB4831E83BD8F000B8DD0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = EB1BB4821E83BD8F000B8DD0 /* main.m */; };
11 | EB1BB4861E83BD8F000B8DD0 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EB1BB4851E83BD8F000B8DD0 /* AppDelegate.m */; };
12 | EB1BB48C1E83BD8F000B8DD0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EB1BB48A1E83BD8F000B8DD0 /* Main.storyboard */; };
13 | EB1BB48E1E83BD8F000B8DD0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EB1BB48D1E83BD8F000B8DD0 /* Assets.xcassets */; };
14 | EB1BB4911E83BD8F000B8DD0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EB1BB48F1E83BD8F000B8DD0 /* LaunchScreen.storyboard */; };
15 | EB1BB4A31E83BEF2000B8DD0 /* GLTransitionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = EB1BB4A21E83BEF2000B8DD0 /* GLTransitionManager.m */; };
16 | EB41A1721E84A91600C1358A /* GLTransitionAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = EB41A1711E84A91600C1358A /* GLTransitionAnimation.m */; };
17 | EB41A1751E84AA6C00C1358A /* GLInteractiveTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = EB41A1741E84AA6C00C1358A /* GLInteractiveTransition.m */; };
18 | EB41A1781E84AC4200C1358A /* UIViewController+GLTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = EB41A1771E84AC4200C1358A /* UIViewController+GLTransition.m */; };
19 | EB41A17B1E84C28B00C1358A /* GLCircleSpreadAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = EB41A17A1E84C28B00C1358A /* GLCircleSpreadAnimation.m */; };
20 | EBAA46921E8CFF1F00005E42 /* OpenDoorFromViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAA46911E8CFF1F00005E42 /* OpenDoorFromViewController.m */; };
21 | EBAA46951E8CFF3100005E42 /* OpenDoorToViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAA46941E8CFF3100005E42 /* OpenDoorToViewController.m */; };
22 | EBAA46981E8D020100005E42 /* GLOpenDoorAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAA46971E8D020100005E42 /* GLOpenDoorAnimation.m */; };
23 | EBAA46A01E8E3CB300005E42 /* GLMiddlePageAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAA469F1E8E3CB300005E42 /* GLMiddlePageAnimation.m */; };
24 | EBAA46A41E8E45E000005E42 /* MiddlePageFromViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAA46A31E8E45E000005E42 /* MiddlePageFromViewController.m */; };
25 | EBAA46A71E8E45EF00005E42 /* MiddlePageToViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBAA46A61E8E45EF00005E42 /* MiddlePageToViewController.m */; };
26 | EBABC5351E89054600B218C1 /* CircleSpreadToController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBABC5321E89054600B218C1 /* CircleSpreadToController.m */; };
27 | EBABC5361E89054600B218C1 /* CircleSpreadFromController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBABC5341E89054600B218C1 /* CircleSpreadFromController.m */; };
28 | EBABC5391E8906DF00B218C1 /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBABC5381E8906DF00B218C1 /* TableViewController.m */; };
29 | EBABC53D1E890BD400B218C1 /* CircleRectSpreadFromViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBABC53C1E890BD400B218C1 /* CircleRectSpreadFromViewController.m */; };
30 | EBABC5401E890BE500B218C1 /* CircleRectSpreadToViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EBABC53F1E890BE500B218C1 /* CircleRectSpreadToViewController.m */; };
31 | EBABC5431E890C3400B218C1 /* GLCircleRectSpreadAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = EBABC5421E890C3400B218C1 /* GLCircleRectSpreadAnimation.m */; };
32 | /* End PBXBuildFile section */
33 |
34 | /* Begin PBXFileReference section */
35 | EB1BB47E1E83BD8F000B8DD0 /* GLTransitionAnimationDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GLTransitionAnimationDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
36 | EB1BB4821E83BD8F000B8DD0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
37 | EB1BB4841E83BD8F000B8DD0 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
38 | EB1BB4851E83BD8F000B8DD0 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
39 | EB1BB48B1E83BD8F000B8DD0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
40 | EB1BB48D1E83BD8F000B8DD0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
41 | EB1BB4901E83BD8F000B8DD0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
42 | EB1BB4921E83BD8F000B8DD0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
43 | EB1BB4A11E83BEF2000B8DD0 /* GLTransitionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLTransitionManager.h; sourceTree = ""; };
44 | EB1BB4A21E83BEF2000B8DD0 /* GLTransitionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLTransitionManager.m; sourceTree = ""; };
45 | EB41A1701E84A91600C1358A /* GLTransitionAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLTransitionAnimation.h; sourceTree = ""; };
46 | EB41A1711E84A91600C1358A /* GLTransitionAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLTransitionAnimation.m; sourceTree = ""; };
47 | EB41A1731E84AA6C00C1358A /* GLInteractiveTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLInteractiveTransition.h; sourceTree = ""; };
48 | EB41A1741E84AA6C00C1358A /* GLInteractiveTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLInteractiveTransition.m; sourceTree = ""; };
49 | EB41A1761E84AC4200C1358A /* UIViewController+GLTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+GLTransition.h"; sourceTree = ""; };
50 | EB41A1771E84AC4200C1358A /* UIViewController+GLTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+GLTransition.m"; sourceTree = ""; };
51 | EB41A1791E84C28B00C1358A /* GLCircleSpreadAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLCircleSpreadAnimation.h; sourceTree = ""; };
52 | EB41A17A1E84C28B00C1358A /* GLCircleSpreadAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLCircleSpreadAnimation.m; sourceTree = ""; };
53 | EBAA46841E8B988C00005E42 /* PrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PrefixHeader.pch; sourceTree = ""; };
54 | EBAA46901E8CFF1F00005E42 /* OpenDoorFromViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenDoorFromViewController.h; sourceTree = ""; };
55 | EBAA46911E8CFF1F00005E42 /* OpenDoorFromViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenDoorFromViewController.m; sourceTree = ""; };
56 | EBAA46931E8CFF3100005E42 /* OpenDoorToViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenDoorToViewController.h; sourceTree = ""; };
57 | EBAA46941E8CFF3100005E42 /* OpenDoorToViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenDoorToViewController.m; sourceTree = ""; };
58 | EBAA46961E8D020100005E42 /* GLOpenDoorAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLOpenDoorAnimation.h; sourceTree = ""; };
59 | EBAA46971E8D020100005E42 /* GLOpenDoorAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLOpenDoorAnimation.m; sourceTree = ""; };
60 | EBAA469E1E8E3CB300005E42 /* GLMiddlePageAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLMiddlePageAnimation.h; sourceTree = ""; };
61 | EBAA469F1E8E3CB300005E42 /* GLMiddlePageAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLMiddlePageAnimation.m; sourceTree = ""; };
62 | EBAA46A21E8E45E000005E42 /* MiddlePageFromViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MiddlePageFromViewController.h; sourceTree = ""; };
63 | EBAA46A31E8E45E000005E42 /* MiddlePageFromViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MiddlePageFromViewController.m; sourceTree = ""; };
64 | EBAA46A51E8E45EF00005E42 /* MiddlePageToViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MiddlePageToViewController.h; sourceTree = ""; };
65 | EBAA46A61E8E45EF00005E42 /* MiddlePageToViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MiddlePageToViewController.m; sourceTree = ""; };
66 | EBABC5311E89054600B218C1 /* CircleSpreadToController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleSpreadToController.h; sourceTree = ""; };
67 | EBABC5321E89054600B218C1 /* CircleSpreadToController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleSpreadToController.m; sourceTree = ""; };
68 | EBABC5331E89054600B218C1 /* CircleSpreadFromController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleSpreadFromController.h; sourceTree = ""; };
69 | EBABC5341E89054600B218C1 /* CircleSpreadFromController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleSpreadFromController.m; sourceTree = ""; };
70 | EBABC5371E8906DF00B218C1 /* TableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TableViewController.h; sourceTree = ""; };
71 | EBABC5381E8906DF00B218C1 /* TableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TableViewController.m; sourceTree = ""; };
72 | EBABC53B1E890BD400B218C1 /* CircleRectSpreadFromViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleRectSpreadFromViewController.h; sourceTree = ""; };
73 | EBABC53C1E890BD400B218C1 /* CircleRectSpreadFromViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleRectSpreadFromViewController.m; sourceTree = ""; };
74 | EBABC53E1E890BE500B218C1 /* CircleRectSpreadToViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleRectSpreadToViewController.h; sourceTree = ""; };
75 | EBABC53F1E890BE500B218C1 /* CircleRectSpreadToViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleRectSpreadToViewController.m; sourceTree = ""; };
76 | EBABC5411E890C3400B218C1 /* GLCircleRectSpreadAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLCircleRectSpreadAnimation.h; sourceTree = ""; };
77 | EBABC5421E890C3400B218C1 /* GLCircleRectSpreadAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLCircleRectSpreadAnimation.m; sourceTree = ""; };
78 | /* End PBXFileReference section */
79 |
80 | /* Begin PBXFrameworksBuildPhase section */
81 | EB1BB47B1E83BD8F000B8DD0 /* Frameworks */ = {
82 | isa = PBXFrameworksBuildPhase;
83 | buildActionMask = 2147483647;
84 | files = (
85 | );
86 | runOnlyForDeploymentPostprocessing = 0;
87 | };
88 | /* End PBXFrameworksBuildPhase section */
89 |
90 | /* Begin PBXGroup section */
91 | EB1BB4751E83BD8F000B8DD0 = {
92 | isa = PBXGroup;
93 | children = (
94 | EB1BB4801E83BD8F000B8DD0 /* GLTransitionAnimationDemo */,
95 | EB1BB47F1E83BD8F000B8DD0 /* Products */,
96 | );
97 | sourceTree = "";
98 | };
99 | EB1BB47F1E83BD8F000B8DD0 /* Products */ = {
100 | isa = PBXGroup;
101 | children = (
102 | EB1BB47E1E83BD8F000B8DD0 /* GLTransitionAnimationDemo.app */,
103 | );
104 | name = Products;
105 | sourceTree = "";
106 | };
107 | EB1BB4801E83BD8F000B8DD0 /* GLTransitionAnimationDemo */ = {
108 | isa = PBXGroup;
109 | children = (
110 | EB1BB4841E83BD8F000B8DD0 /* AppDelegate.h */,
111 | EB1BB4851E83BD8F000B8DD0 /* AppDelegate.m */,
112 | EB1BB49A1E83BE11000B8DD0 /* ViewController */,
113 | EB1BB4981E83BE11000B8DD0 /* GLTransitionAnimation */,
114 | EB1BB48A1E83BD8F000B8DD0 /* Main.storyboard */,
115 | EB1BB48D1E83BD8F000B8DD0 /* Assets.xcassets */,
116 | EBAA46841E8B988C00005E42 /* PrefixHeader.pch */,
117 | EB1BB48F1E83BD8F000B8DD0 /* LaunchScreen.storyboard */,
118 | EB1BB4921E83BD8F000B8DD0 /* Info.plist */,
119 | EB1BB4811E83BD8F000B8DD0 /* Supporting Files */,
120 | );
121 | path = GLTransitionAnimationDemo;
122 | sourceTree = "";
123 | };
124 | EB1BB4811E83BD8F000B8DD0 /* Supporting Files */ = {
125 | isa = PBXGroup;
126 | children = (
127 | EB1BB4821E83BD8F000B8DD0 /* main.m */,
128 | );
129 | name = "Supporting Files";
130 | sourceTree = "";
131 | };
132 | EB1BB4981E83BE11000B8DD0 /* GLTransitionAnimation */ = {
133 | isa = PBXGroup;
134 | children = (
135 | EB1BB4991E83BE11000B8DD0 /* GLAnimation */,
136 | EB1BB4A11E83BEF2000B8DD0 /* GLTransitionManager.h */,
137 | EB1BB4A21E83BEF2000B8DD0 /* GLTransitionManager.m */,
138 | EB41A1701E84A91600C1358A /* GLTransitionAnimation.h */,
139 | EB41A1711E84A91600C1358A /* GLTransitionAnimation.m */,
140 | EB41A1731E84AA6C00C1358A /* GLInteractiveTransition.h */,
141 | EB41A1741E84AA6C00C1358A /* GLInteractiveTransition.m */,
142 | EB41A1761E84AC4200C1358A /* UIViewController+GLTransition.h */,
143 | EB41A1771E84AC4200C1358A /* UIViewController+GLTransition.m */,
144 | );
145 | path = GLTransitionAnimation;
146 | sourceTree = "";
147 | };
148 | EB1BB4991E83BE11000B8DD0 /* GLAnimation */ = {
149 | isa = PBXGroup;
150 | children = (
151 | EB41A1791E84C28B00C1358A /* GLCircleSpreadAnimation.h */,
152 | EB41A17A1E84C28B00C1358A /* GLCircleSpreadAnimation.m */,
153 | EBABC5411E890C3400B218C1 /* GLCircleRectSpreadAnimation.h */,
154 | EBABC5421E890C3400B218C1 /* GLCircleRectSpreadAnimation.m */,
155 | EBAA46961E8D020100005E42 /* GLOpenDoorAnimation.h */,
156 | EBAA46971E8D020100005E42 /* GLOpenDoorAnimation.m */,
157 | EBAA469E1E8E3CB300005E42 /* GLMiddlePageAnimation.h */,
158 | EBAA469F1E8E3CB300005E42 /* GLMiddlePageAnimation.m */,
159 | );
160 | path = GLAnimation;
161 | sourceTree = "";
162 | };
163 | EB1BB49A1E83BE11000B8DD0 /* ViewController */ = {
164 | isa = PBXGroup;
165 | children = (
166 | EBABC5371E8906DF00B218C1 /* TableViewController.h */,
167 | EBABC5381E8906DF00B218C1 /* TableViewController.m */,
168 | EBAA46A11E8E459B00005E42 /* MiddlePageVc */,
169 | EBAA468C1E8CFEEF00005E42 /* OpenDoorVc */,
170 | EBABC53A1E890BB100B218C1 /* CircleRectSpreadVc */,
171 | EBABC5301E89054600B218C1 /* CircleSpreadVc */,
172 | );
173 | path = ViewController;
174 | sourceTree = "";
175 | };
176 | EBAA468C1E8CFEEF00005E42 /* OpenDoorVc */ = {
177 | isa = PBXGroup;
178 | children = (
179 | EBAA46901E8CFF1F00005E42 /* OpenDoorFromViewController.h */,
180 | EBAA46911E8CFF1F00005E42 /* OpenDoorFromViewController.m */,
181 | EBAA46931E8CFF3100005E42 /* OpenDoorToViewController.h */,
182 | EBAA46941E8CFF3100005E42 /* OpenDoorToViewController.m */,
183 | );
184 | path = OpenDoorVc;
185 | sourceTree = "";
186 | };
187 | EBAA46A11E8E459B00005E42 /* MiddlePageVc */ = {
188 | isa = PBXGroup;
189 | children = (
190 | EBAA46A21E8E45E000005E42 /* MiddlePageFromViewController.h */,
191 | EBAA46A31E8E45E000005E42 /* MiddlePageFromViewController.m */,
192 | EBAA46A51E8E45EF00005E42 /* MiddlePageToViewController.h */,
193 | EBAA46A61E8E45EF00005E42 /* MiddlePageToViewController.m */,
194 | );
195 | path = MiddlePageVc;
196 | sourceTree = "";
197 | };
198 | EBABC5301E89054600B218C1 /* CircleSpreadVc */ = {
199 | isa = PBXGroup;
200 | children = (
201 | EBABC5331E89054600B218C1 /* CircleSpreadFromController.h */,
202 | EBABC5341E89054600B218C1 /* CircleSpreadFromController.m */,
203 | EBABC5311E89054600B218C1 /* CircleSpreadToController.h */,
204 | EBABC5321E89054600B218C1 /* CircleSpreadToController.m */,
205 | );
206 | path = CircleSpreadVc;
207 | sourceTree = "";
208 | };
209 | EBABC53A1E890BB100B218C1 /* CircleRectSpreadVc */ = {
210 | isa = PBXGroup;
211 | children = (
212 | EBABC53B1E890BD400B218C1 /* CircleRectSpreadFromViewController.h */,
213 | EBABC53C1E890BD400B218C1 /* CircleRectSpreadFromViewController.m */,
214 | EBABC53E1E890BE500B218C1 /* CircleRectSpreadToViewController.h */,
215 | EBABC53F1E890BE500B218C1 /* CircleRectSpreadToViewController.m */,
216 | );
217 | path = CircleRectSpreadVc;
218 | sourceTree = "";
219 | };
220 | /* End PBXGroup section */
221 |
222 | /* Begin PBXNativeTarget section */
223 | EB1BB47D1E83BD8F000B8DD0 /* GLTransitionAnimationDemo */ = {
224 | isa = PBXNativeTarget;
225 | buildConfigurationList = EB1BB4951E83BD8F000B8DD0 /* Build configuration list for PBXNativeTarget "GLTransitionAnimationDemo" */;
226 | buildPhases = (
227 | EB1BB47A1E83BD8F000B8DD0 /* Sources */,
228 | EB1BB47B1E83BD8F000B8DD0 /* Frameworks */,
229 | EB1BB47C1E83BD8F000B8DD0 /* Resources */,
230 | );
231 | buildRules = (
232 | );
233 | dependencies = (
234 | );
235 | name = GLTransitionAnimationDemo;
236 | productName = GLTransitionAnimationDemo;
237 | productReference = EB1BB47E1E83BD8F000B8DD0 /* GLTransitionAnimationDemo.app */;
238 | productType = "com.apple.product-type.application";
239 | };
240 | /* End PBXNativeTarget section */
241 |
242 | /* Begin PBXProject section */
243 | EB1BB4761E83BD8F000B8DD0 /* Project object */ = {
244 | isa = PBXProject;
245 | attributes = {
246 | LastUpgradeCheck = 0820;
247 | ORGANIZATIONNAME = "高磊";
248 | TargetAttributes = {
249 | EB1BB47D1E83BD8F000B8DD0 = {
250 | CreatedOnToolsVersion = 8.2.1;
251 | ProvisioningStyle = Automatic;
252 | };
253 | };
254 | };
255 | buildConfigurationList = EB1BB4791E83BD8F000B8DD0 /* Build configuration list for PBXProject "GLTransitionAnimationDemo" */;
256 | compatibilityVersion = "Xcode 3.2";
257 | developmentRegion = English;
258 | hasScannedForEncodings = 0;
259 | knownRegions = (
260 | en,
261 | Base,
262 | );
263 | mainGroup = EB1BB4751E83BD8F000B8DD0;
264 | productRefGroup = EB1BB47F1E83BD8F000B8DD0 /* Products */;
265 | projectDirPath = "";
266 | projectRoot = "";
267 | targets = (
268 | EB1BB47D1E83BD8F000B8DD0 /* GLTransitionAnimationDemo */,
269 | );
270 | };
271 | /* End PBXProject section */
272 |
273 | /* Begin PBXResourcesBuildPhase section */
274 | EB1BB47C1E83BD8F000B8DD0 /* Resources */ = {
275 | isa = PBXResourcesBuildPhase;
276 | buildActionMask = 2147483647;
277 | files = (
278 | EB1BB4911E83BD8F000B8DD0 /* LaunchScreen.storyboard in Resources */,
279 | EB1BB48E1E83BD8F000B8DD0 /* Assets.xcassets in Resources */,
280 | EB1BB48C1E83BD8F000B8DD0 /* Main.storyboard in Resources */,
281 | );
282 | runOnlyForDeploymentPostprocessing = 0;
283 | };
284 | /* End PBXResourcesBuildPhase section */
285 |
286 | /* Begin PBXSourcesBuildPhase section */
287 | EB1BB47A1E83BD8F000B8DD0 /* Sources */ = {
288 | isa = PBXSourcesBuildPhase;
289 | buildActionMask = 2147483647;
290 | files = (
291 | EBAA46A41E8E45E000005E42 /* MiddlePageFromViewController.m in Sources */,
292 | EBABC5361E89054600B218C1 /* CircleSpreadFromController.m in Sources */,
293 | EB41A1781E84AC4200C1358A /* UIViewController+GLTransition.m in Sources */,
294 | EB1BB4A31E83BEF2000B8DD0 /* GLTransitionManager.m in Sources */,
295 | EBABC5391E8906DF00B218C1 /* TableViewController.m in Sources */,
296 | EBAA46A01E8E3CB300005E42 /* GLMiddlePageAnimation.m in Sources */,
297 | EBABC53D1E890BD400B218C1 /* CircleRectSpreadFromViewController.m in Sources */,
298 | EB41A1751E84AA6C00C1358A /* GLInteractiveTransition.m in Sources */,
299 | EBAA46A71E8E45EF00005E42 /* MiddlePageToViewController.m in Sources */,
300 | EBABC5401E890BE500B218C1 /* CircleRectSpreadToViewController.m in Sources */,
301 | EB1BB4861E83BD8F000B8DD0 /* AppDelegate.m in Sources */,
302 | EBABC5431E890C3400B218C1 /* GLCircleRectSpreadAnimation.m in Sources */,
303 | EBAA46981E8D020100005E42 /* GLOpenDoorAnimation.m in Sources */,
304 | EBABC5351E89054600B218C1 /* CircleSpreadToController.m in Sources */,
305 | EBAA46951E8CFF3100005E42 /* OpenDoorToViewController.m in Sources */,
306 | EB1BB4831E83BD8F000B8DD0 /* main.m in Sources */,
307 | EB41A17B1E84C28B00C1358A /* GLCircleSpreadAnimation.m in Sources */,
308 | EBAA46921E8CFF1F00005E42 /* OpenDoorFromViewController.m in Sources */,
309 | EB41A1721E84A91600C1358A /* GLTransitionAnimation.m in Sources */,
310 | );
311 | runOnlyForDeploymentPostprocessing = 0;
312 | };
313 | /* End PBXSourcesBuildPhase section */
314 |
315 | /* Begin PBXVariantGroup section */
316 | EB1BB48A1E83BD8F000B8DD0 /* Main.storyboard */ = {
317 | isa = PBXVariantGroup;
318 | children = (
319 | EB1BB48B1E83BD8F000B8DD0 /* Base */,
320 | );
321 | name = Main.storyboard;
322 | sourceTree = "";
323 | };
324 | EB1BB48F1E83BD8F000B8DD0 /* LaunchScreen.storyboard */ = {
325 | isa = PBXVariantGroup;
326 | children = (
327 | EB1BB4901E83BD8F000B8DD0 /* Base */,
328 | );
329 | name = LaunchScreen.storyboard;
330 | sourceTree = "";
331 | };
332 | /* End PBXVariantGroup section */
333 |
334 | /* Begin XCBuildConfiguration section */
335 | EB1BB4931E83BD8F000B8DD0 /* Debug */ = {
336 | isa = XCBuildConfiguration;
337 | buildSettings = {
338 | ALWAYS_SEARCH_USER_PATHS = NO;
339 | CLANG_ANALYZER_NONNULL = YES;
340 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
341 | CLANG_CXX_LIBRARY = "libc++";
342 | CLANG_ENABLE_MODULES = YES;
343 | CLANG_ENABLE_OBJC_ARC = YES;
344 | CLANG_WARN_BOOL_CONVERSION = YES;
345 | CLANG_WARN_CONSTANT_CONVERSION = YES;
346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
347 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
348 | CLANG_WARN_EMPTY_BODY = YES;
349 | CLANG_WARN_ENUM_CONVERSION = YES;
350 | CLANG_WARN_INFINITE_RECURSION = YES;
351 | CLANG_WARN_INT_CONVERSION = YES;
352 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
353 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
354 | CLANG_WARN_UNREACHABLE_CODE = YES;
355 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
356 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
357 | COPY_PHASE_STRIP = NO;
358 | DEBUG_INFORMATION_FORMAT = dwarf;
359 | ENABLE_STRICT_OBJC_MSGSEND = YES;
360 | ENABLE_TESTABILITY = YES;
361 | GCC_C_LANGUAGE_STANDARD = gnu99;
362 | GCC_DYNAMIC_NO_PIC = NO;
363 | GCC_NO_COMMON_BLOCKS = YES;
364 | GCC_OPTIMIZATION_LEVEL = 0;
365 | GCC_PREPROCESSOR_DEFINITIONS = (
366 | "DEBUG=1",
367 | "$(inherited)",
368 | );
369 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
370 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
371 | GCC_WARN_UNDECLARED_SELECTOR = YES;
372 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
373 | GCC_WARN_UNUSED_FUNCTION = YES;
374 | GCC_WARN_UNUSED_VARIABLE = YES;
375 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
376 | MTL_ENABLE_DEBUG_INFO = YES;
377 | ONLY_ACTIVE_ARCH = YES;
378 | SDKROOT = iphoneos;
379 | };
380 | name = Debug;
381 | };
382 | EB1BB4941E83BD8F000B8DD0 /* Release */ = {
383 | isa = XCBuildConfiguration;
384 | buildSettings = {
385 | ALWAYS_SEARCH_USER_PATHS = NO;
386 | CLANG_ANALYZER_NONNULL = YES;
387 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
388 | CLANG_CXX_LIBRARY = "libc++";
389 | CLANG_ENABLE_MODULES = YES;
390 | CLANG_ENABLE_OBJC_ARC = YES;
391 | CLANG_WARN_BOOL_CONVERSION = YES;
392 | CLANG_WARN_CONSTANT_CONVERSION = YES;
393 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
394 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
395 | CLANG_WARN_EMPTY_BODY = YES;
396 | CLANG_WARN_ENUM_CONVERSION = YES;
397 | CLANG_WARN_INFINITE_RECURSION = YES;
398 | CLANG_WARN_INT_CONVERSION = YES;
399 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
400 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
401 | CLANG_WARN_UNREACHABLE_CODE = YES;
402 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
403 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
404 | COPY_PHASE_STRIP = NO;
405 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
406 | ENABLE_NS_ASSERTIONS = NO;
407 | ENABLE_STRICT_OBJC_MSGSEND = YES;
408 | GCC_C_LANGUAGE_STANDARD = gnu99;
409 | GCC_NO_COMMON_BLOCKS = YES;
410 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
411 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
412 | GCC_WARN_UNDECLARED_SELECTOR = YES;
413 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
414 | GCC_WARN_UNUSED_FUNCTION = YES;
415 | GCC_WARN_UNUSED_VARIABLE = YES;
416 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
417 | MTL_ENABLE_DEBUG_INFO = NO;
418 | SDKROOT = iphoneos;
419 | VALIDATE_PRODUCT = YES;
420 | };
421 | name = Release;
422 | };
423 | EB1BB4961E83BD8F000B8DD0 /* Debug */ = {
424 | isa = XCBuildConfiguration;
425 | buildSettings = {
426 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
427 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
428 | GCC_PREFIX_HEADER = GLTransitionAnimationDemo/PrefixHeader.pch;
429 | INFOPLIST_FILE = GLTransitionAnimationDemo/Info.plist;
430 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
431 | PRODUCT_BUNDLE_IDENTIFIER = gao.GLTransitionAnimationDemo;
432 | PRODUCT_NAME = "$(TARGET_NAME)";
433 | };
434 | name = Debug;
435 | };
436 | EB1BB4971E83BD8F000B8DD0 /* Release */ = {
437 | isa = XCBuildConfiguration;
438 | buildSettings = {
439 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
440 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
441 | GCC_PREFIX_HEADER = GLTransitionAnimationDemo/PrefixHeader.pch;
442 | INFOPLIST_FILE = GLTransitionAnimationDemo/Info.plist;
443 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
444 | PRODUCT_BUNDLE_IDENTIFIER = gao.GLTransitionAnimationDemo;
445 | PRODUCT_NAME = "$(TARGET_NAME)";
446 | };
447 | name = Release;
448 | };
449 | /* End XCBuildConfiguration section */
450 |
451 | /* Begin XCConfigurationList section */
452 | EB1BB4791E83BD8F000B8DD0 /* Build configuration list for PBXProject "GLTransitionAnimationDemo" */ = {
453 | isa = XCConfigurationList;
454 | buildConfigurations = (
455 | EB1BB4931E83BD8F000B8DD0 /* Debug */,
456 | EB1BB4941E83BD8F000B8DD0 /* Release */,
457 | );
458 | defaultConfigurationIsVisible = 0;
459 | defaultConfigurationName = Release;
460 | };
461 | EB1BB4951E83BD8F000B8DD0 /* Build configuration list for PBXNativeTarget "GLTransitionAnimationDemo" */ = {
462 | isa = XCConfigurationList;
463 | buildConfigurations = (
464 | EB1BB4961E83BD8F000B8DD0 /* Debug */,
465 | EB1BB4971E83BD8F000B8DD0 /* Release */,
466 | );
467 | defaultConfigurationIsVisible = 0;
468 | defaultConfigurationName = Release;
469 | };
470 | /* End XCConfigurationList section */
471 | };
472 | rootObject = EB1BB4761E83BD8F000B8DD0 /* Project object */;
473 | }
474 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GLTransitionAnimationDemo
2 | iOS 自定义转场动画
3 | >路漫漫其修远兮,吾将上下而求索
4 |
5 | 
6 |
7 | ##### 前记
8 | 想研究自定义转场动画很久了,时间就像海绵,挤一挤还是有的,花了差不多有10天的时间,终于对转场动画了解了一点。自从`iOS 7`以后,我们就可以自定义转场动画,实现我们想要的效果,在这之前,我们先来看一张图,大概了解下,需要知道些什么
9 |
10 |
11 | `相关类联系图`
12 |
13 | 
14 |
15 |
16 | 相信各位看官也差不多看完这张图了,下面我们就来简单了解下其中的类和相关的函数
17 |
18 | 说到转场动画,其实无非就是我们常用的`push` `pop` `present` `dismiss`四种动画,其中前面两个是成对使用,后面两个成对使用,我们先看看`push`这组在自定义转场动画中所涉及到的类
19 |
20 | 由于`push`动画组需要配合`navigationController`来使用,所以上图中的`UINavigationControllerDelegate`肯定是我们需要的类
21 |
22 | ###### UINavigationControllerDelegate
23 | 先来看看其中需要用到的函数
24 | ```
25 | - (nullable id )navigationController:(UINavigationController *)navigationController
26 | interactionControllerForAnimationController:(id ) animationController NS_AVAILABLE_IOS(7_0);
27 |
28 | - (nullable id )navigationController:(UINavigationController *)navigationController
29 | animationControllerForOperation:(UINavigationControllerOperation)operation
30 | fromViewController:(UIViewController *)fromVC
31 | toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
32 | ```
33 |
34 | 第一个函数的返回值是一个`id `值
35 | 第二个函数返回的值是一个`id `值
36 | 那么我们就先从这两个返回值入手,来看下两个函数的作用
37 |
38 | ###### UIViewControllerInteractiveTransitioning 、UIPercentDrivenInteractiveTransition
39 | 这两个类又是干什么的呢?`UIPercentDrivenInteractiveTransition`遵守协议`UIViewControllerInteractiveTransitioning`,通过查阅资料了解到,`UIPercentDrivenInteractiveTransition`这个类的对象会根据我们的手势,来决定我们的自定义过渡的完成度,也就是这两个其实是和手势交互相关联的,自然而然我们就想到了`iOS 7`引进的侧滑手势,对,就是侧滑手势,说到这里,我就顺带介绍一个类,`UIScreenEdgePanGestureRecognizer`,手势侧滑的类,具体怎么使用,后面我会陆续讲到。
40 |
41 | 涉及函数
42 | ```
43 | //更新进度
44 | - (void)updateInteractiveTransition:(CGFloat)percentComplete;
45 | //取消转场 回到转场前的效果
46 | - (void)cancelInteractiveTransition;
47 | //完成转场
48 | - (void)finishInteractiveTransition;
49 | ```
50 |
51 | ###### UIViewControllerAnimatedTransitioning
52 | 在这个类中,我们又看到了两个函数
53 | ```
54 | //转场时间
55 | - (NSTimeInterval)transitionDuration:(nullable id )transitionContext;
56 |
57 | - (void)animateTransition:(id )transitionContext;
58 | ```
59 | 其中又涉及到一个新的类`UIViewControllerContextTransitioning`,那么这个又是干什么的呢?我们等下再来了解,先来谈谈第一个函数`transitionDuration`,从返回值我们可以猜测出这是和时间有关的,没错,这就是我们自定义转场动画所需要的时间
60 | 那么下面我们就来看看`UIViewControllerContextTransitioning`
61 |
62 | ###### UIViewControllerContextTransitioning
63 | 这个类就是我们自定义转场动画所需要的核心,即转场动画的上下文,定义了转场时需要的元素,比如在转场过程中所参与的视图控制器和视图的相关属性
64 | ```
65 | //转场动画的容器
66 | @property(nonatomic, readonly) UIView *containerView;
67 | //通过对应的`key`可以得到我们需要的`vc`
68 | - (UIViewController *)viewControllerForKey:(UITransitionContextViewControllerKey)key
69 | //转场动画完成时候调用,必须调用,否则在进行其他转场没有任何效果
70 | - (void)completeTransition:(BOOL)didComplete
71 | ```
72 | 看到这里,我们现在再去看`UINavigationControllerDelegate `中的两个函数和`UIViewControllerAnimatedTransitioning `中的`animateTransition `函数,就能完全理解了
73 |
74 | ```
75 | //主要用于手势交互转场 for push or pop
76 | - (nullable id )navigationController:(UINavigationController *)navigationController
77 | interactionControllerForAnimationController:(id ) animationController NS_AVAILABLE_IOS(7_0);
78 |
79 | //非手势交互转场 for push or pop
80 | - (nullable id )navigationController:(UINavigationController *)navigationController
81 | animationControllerForOperation:(UINavigationControllerOperation)operation
82 | fromViewController:(UIViewController *)fromVC
83 | toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
84 |
85 | //实现转场动画 通过transitionContext
86 | - (void)animateTransition:(id )transitionContext;
87 |
88 | ```
89 | 到此,我们还有一个类没有了解,那就是`UIViewControllerTransitioningDelegate`有了前面的分析,我们可以很好的理解
90 |
91 | ###### UIViewControllerTransitioningDelegate
92 | 主要是针对`present`和`dismiss`动画的转场
93 | ```
94 | //非手势转场交互 for present
95 | - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
96 | //非手势转场交互 for dismiss
97 | - (id)animationControllerForDismissedController:(UIViewController *)dismissed
98 | //手势交互 for dismiss
99 | - (id)interactionControllerForDismissal:(id)animator
100 | //手势交互 for present
101 | - (id)interactionControllerForPresentation:(id)animator
102 | ```
103 | 基本定义和概览我们差不多应该有了一定的了解,正如上图中的简单描述。
104 |
105 | 了解性的东西说了这么多,下面我们就来点实际性的东西,除了第一张开门那种自定义动画,再来几个比较常用的动画
106 |
107 | 
108 |
109 | 
110 |
111 |
112 | 
113 |
114 | 这些动画都比较简单,相信许多大神都很清楚,还望见谅,下面我就对每一种进行分析分析,在分析动画之前,先来看看怎么将上面的各个类进行封装起来,使用更方便,这里不得不感谢很久之前看到的一篇文章,从他的[文章](http://www.cocoachina.com/ios/20160629/16856.html)中收获非常大。
115 |
116 | 在学习转场动画的时候,虽然对所有类的关系有了一定了解,但是封装的时候,完全没有想到还有这么好的思路,确实是学习了。下面我们就一起来看看封装思路。
117 | ##### 封装思路
118 | ###### 1. 新建一个综合管理转场动画的类
119 | 作用:主要是管理转场所需要的一些设置,诸如转场时间和转场的实现(主要是在子类中进行实现,分离开来),用户在自定义转场动画的时候,只需要继承该类并重写父类方法就可以
120 | 类名:`GLTransitionManager`,需要准守的协议有``
121 | 通过这样,就可以将`present`和`push`动画相关的操作在该类中进行管理
122 | `GLTransitionManager.h`中具体方法
123 | ```
124 | @interface GLTransitionManager : NSObject
125 |
126 | /**
127 | 转场动画的时间 默认为0.5s
128 | */
129 | @property (nonatomic,assign) NSTimeInterval duration;
130 |
131 | /**
132 | 入场动画
133 |
134 | @param contextTransition 实现动画
135 | */
136 | - (void)setToAnimation:(id)contextTransition;
137 |
138 |
139 | /**
140 | 退场动画
141 |
142 | @param contextTransition 实现动画
143 | */
144 | - (void)setBackAnimation:(id)contextTransition;
145 | ```
146 | 相信大家也看到了在入场和退场动画中都有`(id) contextTransition `这么一个参数,通过该参数,我们可以获取转场动画的相关`vc`和其他信息,进行转场动画的实现,即我们在自定义转场动画的时候,只需要重写该两个方法就可以,通过`contextTransition`来实现动画,而``又在`UIViewControllerAnimatedTransitioning`协议的方法`- (void)animateTransition:(id )transitionContext`中涉及到,于是我又新建了一个准守协议`UIViewControllerAnimatedTransitioning`的类`GLTransitionAnimation`,也就是下面我们将的类
147 |
148 | ###### 2.转场动画配置及实现类
149 | 作用:虽然是配置和实现类,但是在该类中并没有进行实现,这里也正是之前那个博主的高明之处,至少我是这么认为的。在该类中,我们用`block`的传值方法将其传入到我们的管理类中,也就是`GLTransitionManager `
150 |
151 | `GLTransitionAnimation.h`文件
152 | ```
153 | /**
154 | GLTransitionAnimation 块
155 |
156 | @param contextTransition 将满足UIViewControllerContextTransitioning协议的对象传到管理内 在管理类对动画统一实现
157 | */
158 | typedef void(^GLTransitionAnimationBlock)(id contextTransition);
159 |
160 | @interface GLTransitionAnimation : NSObject
161 |
162 | @property (nonatomic,copy) GLTransitionAnimationBlock animationBlock;
163 |
164 | /**
165 | 初始化方法
166 |
167 | @param duration 转场时间
168 | @return 返回
169 | */
170 | - (id)initWithDuration:(NSTimeInterval)duration;
171 | ```
172 | `GLTransitionAnimation.m`文件比较简单,这里就先不详说,我们先回到管理类中,来看看怎么使用
173 |
174 | `GLTransitionManager.m`文件,
175 | 在此种定义两个属性
176 | ```
177 | /**
178 | 入场动画
179 | */
180 | @property (nonatomic,strong) GLTransitionAnimation *toTransitionAnimation;
181 |
182 | /**
183 | 退场动画
184 | */
185 | @property (nonatomic,strong) GLTransitionAnimation *backTransitionAnimation;
186 | ```
187 | 实现方法
188 | ```
189 | #pragma mark == 懒加载
190 | - (GLTransitionAnimation *)toTransitionAnimation
191 | {
192 | if (nil == _toTransitionAnimation) {
193 | __weak typeof(self) weakSelf = self;
194 | _toTransitionAnimation = [[GLTransitionAnimation alloc] initWithDuration:self.duration ];
195 | _toTransitionAnimation.animationBlock = ^(id contextTransition)
196 | {
197 | [weakSelf setToAnimation:contextTransition];
198 | };
199 | }
200 | return _toTransitionAnimation;
201 | }
202 |
203 | - (GLTransitionAnimation *)backTransitionAnimation
204 | {
205 | if (nil == _backTransitionAnimation) {
206 | __weak typeof(self) weakSelf = self;
207 | _backTransitionAnimation = [[GLTransitionAnimation alloc] initWithDuration:self.duration];
208 | _backTransitionAnimation.animationBlock = ^(id contextTransition)
209 | {
210 | [weakSelf setBackAnimation:contextTransition];
211 | };
212 | }
213 | return _backTransitionAnimation;
214 | }
215 |
216 | ```
217 |
218 | 通过上面这一方法,我们就很好的将关键参数和对外接口联系起来了。这样我们就只需要在`setToAnimation`和`setBackAnimation`进行转场动画的具体实现即可。
219 | 当然这里还有一个小问题,相信各位也发现了,就是为什么将属性定义在了`.m`文件里呢?是的,这里确实是定义在了`.m`文件中,其实就是为了更少的暴露不需要的。
220 |
221 | 搞定这个之后,我们在来看看,在上面时候,调用该属性呢?
222 | 下面我们就来看具体使用的地方
223 | ```
224 | //非手势转场交互 for present
225 | - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
226 | return self.toTransitionAnimation;
227 | }
228 |
229 | //非手势转场交互 for dismiss
230 | - (id)animationControllerForDismissedController:(UIViewController *)dismissed{
231 | return self.backTransitionAnimation;
232 | }
233 |
234 | //================
235 | //非手势转场交互 for push or pop
236 | /*****注释:通过 fromVC 和 toVC 我们可以在此设置需要自定义动画的类 *****/
237 | - (id )navigationController:(UINavigationController *)navigationController
238 | animationControllerForOperation:(UINavigationControllerOperation)operation
239 | fromViewController:(UIViewController *)fromVC
240 | toViewController:(UIViewController *)toVC
241 | {
242 | _operation = operation;
243 |
244 | if (operation == UINavigationControllerOperationPush)
245 | {
246 | return self.toTransitionAnimation;
247 | }
248 | else if (operation == UINavigationControllerOperationPop)
249 | {
250 | return self.backTransitionAnimation;
251 | }
252 | else
253 | {
254 | return nil;
255 | }
256 | }
257 | ```
258 | 在这两个地方使用后,我们差不多就完成了一半了,那还一部分呢?那就是我们的手势滑动,下面我们就来看看手势滑动。
259 |
260 | ###### 3.手势交互管理类
261 |
262 | 作用:主要通过侧滑手势来管理交互,在iOS 7后引入新的类`UIPercentDrivenInteractiveTransition`,该类的对象会根据我们的手势,来决定我们的自定义过渡的完成度,所以此次我采用继承的方式,然后在继承的类中加入滑动手势类,这里加入的是侧滑手势类`UIScreenEdgePanGestureRecognizer`,这个类也就是我定义的`GLInteractiveTransition`类
263 |
264 | `GLInteractiveTransition.h`文件
265 |
266 | ```
267 |
268 | /**
269 | 手势的方向枚举
270 |
271 | - GLPanEdgeTop:屏幕上方
272 | - GLPanEdgeLeft:屏幕左侧
273 | - GLPanEdgeBottom: 屏幕下方
274 | - GLPanEdgeRight: 屏幕右方
275 | */
276 | typedef NS_ENUM(NSInteger,GLEdgePanGestureDirection) {
277 | GLPanEdgeTop = 0,
278 | GLPanEdgeLeft,
279 | GLPanEdgeBottom,
280 | GLPanEdgeRight
281 | };
282 |
283 |
284 | ///**
285 | // 手势转场类型
286 | //
287 | // - GLInteractiveTransitionPush: push
288 | // - GLInteractiveTransitionPop: pop
289 | // - GLInteractiveTransitionPresent: present
290 | // - GLInteractiveTransitionDismiss: dismiss
291 | // */
292 | //typedef NS_ENUM(NSInteger,GLInteractiveTransitionType) {
293 | // GLInteractiveTransitionPush = 0,
294 | // GLInteractiveTransitionPop,
295 | // GLInteractiveTransitionPresent ,
296 | // GLInteractiveTransitionDismiss
297 | //};
298 |
299 |
300 | @interface GLInteractiveTransition : UIPercentDrivenInteractiveTransition
301 |
302 | /**
303 | 是否满足侧滑手势交互
304 | */
305 | @property (nonatomic,assign) BOOL isPanGestureInteration;
306 |
307 |
308 | /**
309 | 转场时的操作 不用传参数的block
310 | */
311 | @property (nonatomic,copy) dispatch_block_t eventBlcok;
312 |
313 | /**
314 | 添加侧滑手势
315 |
316 | @param view 添加手势的view
317 | @param direction 手势的方向
318 | */
319 | - (void)addEdgePageGestureWithView:(UIView *)view direction:(GLEdgePanGestureDirection)direction;
320 |
321 | ```
322 |
323 | 在`.h`文件中,定义了两个属性,一个是用来判断是否需满足侧滑手势,这个在后面会讲到。另一个是用来在侧滑的时候执行所需要的转场的`block`,之前本来是没有加这个的,但是在后面使用的时候,由于想加侧滑的`present`和`push`效果,所以就加了一个。
324 |
325 | 下面看看`.m`文件滑动手势中的具体实现
326 | ```
327 | - (void)handlePopRecognizer:(UIPanGestureRecognizer*)recognizer {
328 | // 计算用户手指划了多远
329 |
330 | CGFloat progress = fabs([recognizer translationInView:self.gestureView].x) / (self.gestureView.bounds.size.width * 1.0);
331 | progress = MIN(1.0, MAX(0.0, progress));
332 |
333 | switch (recognizer.state) {
334 | case UIGestureRecognizerStateBegan:
335 | {
336 | _isPanGestureInteration = YES;
337 |
338 | if (self.eventBlcok) {
339 | self.eventBlcok();
340 | }
341 |
342 | // 创建过渡对象,弹出viewController
343 | //
344 | // UIViewController *fromVc = [self gl_viewController];
345 | //
346 | // switch (self.transitionType) {
347 | // case GLInteractiveTransitionPush:
348 | // {
349 | //
350 | // }
351 | // break;
352 | // case GLInteractiveTransitionPop:
353 | // {
354 | // if (fromVc.navigationController) {
355 | // [fromVc.navigationController popViewControllerAnimated:YES];
356 | // }
357 | // }
358 | // break;
359 | // case GLInteractiveTransitionPresent:
360 | // {
361 | //
362 | // }
363 | // break;
364 | // case GLInteractiveTransitionDismiss:
365 | // {
366 | // [fromVc dismissViewControllerAnimated:YES completion:nil];
367 | // }
368 | // break;
369 | // default:
370 | // break;
371 | // }
372 | break;
373 | }
374 | case UIGestureRecognizerStateChanged:
375 | {
376 | // 更新 interactive transition 的进度
377 | [self updateInteractiveTransition:progress];
378 | break;
379 | }
380 | case UIGestureRecognizerStateEnded:
381 | case UIGestureRecognizerStateCancelled:
382 | {
383 | // NSLog(@" 打印信息:%f",progress);
384 | // 完成或者取消过渡
385 | if (progress > 0.5) {
386 | [self finishInteractiveTransition];
387 | }
388 | else {
389 | [self cancelInteractiveTransition];
390 | }
391 |
392 | _isPanGestureInteration = NO;
393 | break;
394 | }
395 | default:
396 | break;
397 | }
398 | }
399 | ```
400 | 手势交互管理类的核心代码差不多就这么多,下面我们看看怎么使用
401 |
402 | ###### 4.`UIViewController + GLTransition`
403 |
404 | 为了和系统的转场动画的函数区分开来,这里我新建了一个`UIViewController`的`category`类`UIViewController + GLTransition`,在其中定义了四个函数,分别如下
405 | ```
406 | /**
407 | push动画
408 |
409 | @param viewController 被push viewController
410 | @param transitionManager 控制类
411 | */
412 | - (void)gl_pushViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager*)transitionManager;
413 |
414 |
415 | /**
416 | present动画
417 |
418 | @param viewController 被present viewController
419 | @param transitionManager 控制类
420 | */
421 | - (void)gl_presentViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager*)transitionManager;
422 |
423 |
424 | /**
425 | 注册入场手势
426 |
427 | @param direction 方向
428 | @param blcok 手势转场触发的点击事件
429 | */
430 | - (void)gl_registerToInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok;
431 |
432 | /**
433 | 注册返回手势
434 |
435 | @param direction 侧滑方向
436 | @param blcok 手势转场触发的点击事件
437 | */
438 | - (void)gl_registerBackInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok;
439 |
440 | ```
441 | 下面我们看看具体实现
442 | `UIViewController (GLTransition).m`文件
443 | ```
444 | - (void)gl_pushViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager *)transitionManager
445 | {
446 | if (!viewController) {
447 | return;
448 | }
449 | if (!transitionManager) {
450 | return;
451 | }
452 |
453 | if (self.navigationController) {
454 |
455 | self.navigationController.delegate = transitionManager;
456 |
457 | GLInteractiveTransition *toInteractiveTransition = objc_getAssociatedObject(self, &kToAnimationKey);
458 | if (toInteractiveTransition) {
459 | [transitionManager setValue:toInteractiveTransition forKey:@"toInteractiveTransition"];
460 | }
461 |
462 | objc_setAssociatedObject(viewController, &kAnimationKey, transitionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
463 | [self.navigationController pushViewController:viewController animated:YES];
464 |
465 | }
466 | }
467 |
468 | - (void)gl_presentViewControler:(UIViewController *)viewController withAnimation:(GLTransitionManager *)transitionManager
469 | {
470 | if (!viewController) {
471 | return;
472 | }
473 | if (!transitionManager) {
474 | return;
475 | }
476 | //present 动画代理 被执行动画的vc设置代理
477 | viewController.transitioningDelegate = transitionManager;
478 |
479 | GLInteractiveTransition *toInteractiveTransition = objc_getAssociatedObject(self, &kToAnimationKey);
480 | if (toInteractiveTransition) {
481 | [transitionManager setValue:toInteractiveTransition forKey:@"toInteractiveTransition"];
482 | }
483 | objc_setAssociatedObject(viewController, &kAnimationKey, transitionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
484 |
485 | [self presentViewController:viewController animated:YES completion:nil];
486 | }
487 |
488 | - (void)gl_registerToInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok
489 | {
490 | GLInteractiveTransition *interactiveTransition = [[GLInteractiveTransition alloc] init];
491 | interactiveTransition.eventBlcok = blcok;
492 | [interactiveTransition addEdgePageGestureWithView:self.view direction:direction];
493 |
494 | objc_setAssociatedObject(self, &kToAnimationKey, interactiveTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
495 | }
496 |
497 | - (void)gl_registerBackInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok
498 | {
499 | GLInteractiveTransition *interactiveTransition = [[GLInteractiveTransition alloc] init];
500 | interactiveTransition.eventBlcok = blcok;
501 | [interactiveTransition addEdgePageGestureWithView:self.view direction:direction];
502 |
503 | //判读是否需要返回 然后添加侧滑
504 | GLTransitionManager *animator = objc_getAssociatedObject(self, &kAnimationKey);
505 | if (animator)
506 | {
507 | //用kvc的模式 给 animator的backInteractiveTransition 退场赋值
508 | [animator setValue:interactiveTransition forKey:@"backInteractiveTransition"];
509 | }
510 | }
511 | ```
512 |
513 | 在`push`和`present`中,有几个需要注意的地方
514 | 1、`self.navigationController.delegate = transitionManager`
515 | 2、`viewController.transitioningDelegate = transitionManager`
516 | 上面两个主要是将`navigationController`的代理和`viewController`的`transitioningDelegate`指向对象`transitionManager`,这个对象是准守了``两个协议的,这样我们就能够在`push`和`present`的时候,简单的去调协议方法。
517 |
518 | 3、设置手势交互转场
519 | ```
520 | GLInteractiveTransition *toInteractiveTransition = objc_getAssociatedObject(self, &kToAnimationKey);
521 | if (toInteractiveTransition) {
522 | [transitionManager setValue:toInteractiveTransition forKey:@"toInteractiveTransition"];
523 | }
524 | ```
525 | 在`push`和`present`方法中,都有这样的代码,这里为了减少不必要的暴露,在`GLTransitionManager.m`文件中,我还定义了两个属性
526 | ```
527 | /**
528 | 入场手势
529 | */
530 | @property (nonatomic,strong) GLInteractiveTransition *toInteractiveTransition;
531 |
532 | /**
533 | 退场手势
534 | */
535 | @property (nonatomic,strong) GLInteractiveTransition *backInteractiveTransition;
536 | ```
537 | 并且通过`kvc`的方式对其进行赋值,当转场动画进行的时候,会先去调用非转场动画的方法,比如`push`的时候,会先调用
538 | ```
539 | - (id )navigationController:(UINavigationController *)navigationController
540 | animationControllerForOperation:(UINavigationControllerOperation)operation
541 | fromViewController:(UIViewController *)fromVC
542 | toViewController:(UIViewController *)toVC
543 | ```
544 | 然后再调用手势交互
545 | ```
546 | //手势交互 for push or pop
547 | - (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id)animationController
548 | ```
549 | 这个时候,我们就需要加一个判断,也就是通过`GLInteractiveTransition`类中的是否满足侧滑手势交互`isPanGestureInteration`这个属性来判断,前面在侧滑手势刚刚进行的时候,就对其进行了赋值,并设置为`yes`,对应的实现代码就是
550 | ```
551 | - (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id)animationController
552 | {
553 | if (_operation == UINavigationControllerOperationPush) {
554 | return self.toInteractiveTransition.isPanGestureInteration ? self.toInteractiveTransition:nil;
555 | }
556 | else{
557 | return self.backInteractiveTransition.isPanGestureInteration ? self.backInteractiveTransition:nil;
558 | }
559 | }
560 | ```
561 | 如果返回的为`nil`,那么就不会去调用手势交互类,否则则会调用。同理,`present`的时候也是一样
562 | 所以就有了下面的代码
563 | ```
564 | //手势交互 for dismiss
565 | - (id)interactionControllerForDismissal:(id)animator{
566 | return self.backInteractiveTransition.isPanGestureInteration ? self.backInteractiveTransition:nil;
567 | }
568 |
569 | //手势交互 for present
570 | - (id)interactionControllerForPresentation:(id)animator{
571 | return self.toInteractiveTransition.isPanGestureInteration ? self.toInteractiveTransition:nil;
572 | }
573 | ```
574 | 在`UIViewController + GLTransition`中的`push`和`present`函数中,还有一个需要注意的地方,那就是
575 | ```
576 | objc_setAssociatedObject(viewController, &kAnimationKey, transitionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
577 | ```
578 | 这里通过`runtime`的方式给`vc`设置了一个属性值,为什么这么做呢?因为在`arc`下,如果我们在使用`GLTransitionManager`的时候去创建一个对象而非`vc`的属性,那么在`push`的时候`GLTransitionManager`这个对象就会被系统释放掉,这样我们后面所有有关转场的操作就不能再实现了,或许我们可以给`vc`建一个`base`类,然后添加一个`GLTransitionManager`对象的属性,但是这样或许有点复杂,所有这里就这样处理了。
579 |
580 | 在`UIViewController + GLTransition`中还有两个函数的实现,其原理,我相信大家应该都能看明白了,就不再详细说明了
581 | ```
582 | - (void)gl_registerToInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok
583 | {
584 | GLInteractiveTransition *interactiveTransition = [[GLInteractiveTransition alloc] init];
585 | interactiveTransition.eventBlcok = blcok;
586 | [interactiveTransition addEdgePageGestureWithView:self.view direction:direction];
587 |
588 | objc_setAssociatedObject(self, &kToAnimationKey, interactiveTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
589 | }
590 |
591 | - (void)gl_registerBackInteractiveTransitionWithDirection:(GLEdgePanGestureDirection)direction eventBlcok:(dispatch_block_t)blcok
592 | {
593 | GLInteractiveTransition *interactiveTransition = [[GLInteractiveTransition alloc] init];
594 | interactiveTransition.eventBlcok = blcok;
595 | [interactiveTransition addEdgePageGestureWithView:self.view direction:direction];
596 |
597 | //判读是否需要返回 然后添加侧滑
598 | GLTransitionManager *animator = objc_getAssociatedObject(self, &kAnimationKey);
599 | if (animator)
600 | {
601 | //用kvc的模式 给 animator的backInteractiveTransition 退场赋值
602 | [animator setValue:interactiveTransition forKey:@"backInteractiveTransition"];
603 | }
604 | }
605 | ```
606 | 整个封装的思路差不多到这里就完了,希望对大家有用
607 |
608 | 文章有点长,希望大家能够理解,因为后面还有。。。。
609 |
610 | ##### 几个动画的具体实现
611 | ###### 1、开门动画
612 |
613 | 由于我们已经有了基类``,所以当我们需要实现什么动画的时候,只需要集成该类就可以了
614 |
615 | 针对开门动画我新建了下面这么一个类`GLTransitionManager`
616 | ```
617 | @interface GLOpenDoorAnimation : GLTransitionManager
618 |
619 | @end
620 | ```
621 | 然后在重新父类的方法
622 | ```
623 | - (void)setToAnimation:(id)contextTransition
624 | ```
625 | 具体实现
626 | 1、根据`id`对象先得到几个关键值,目标`vc`和当前`vc`和容器`containerView`
627 | ```
628 | //获取目标动画的VC
629 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
630 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
631 | UIView *containerView = [contextTransition containerView];
632 | ```
633 |
634 | 2、由于是开门动画,所以其过程大概是这样的:当前`vc`逐渐缩小,目标`vc`慢慢从屏幕两边移到中间,但是我们又不能把目标`vc`的`view`分成两个部分,所以这里我们可以利用截图,来给用户造成一个假象。先截两个图,然后分别让其坐标居于屏幕外,然后用动画让其慢慢移动到屏幕中间,动画完成的时候,移除当前两个截图。这里有个小问题,那就是当前`vc`的缩放,虽然我们能够使其缩小,但是这样,如果涉及到侧滑手势的话,问题就来了。因为`view`的宽发生了变化,这样我们根据宽度来计算滑动的距离,从而更新转场动画的时候就会出现问题,导致
635 | ```
636 | - (void)handlePopRecognizer:(UIPanGestureRecognizer*)recognizer {
637 | // 计算用户手指划了多远
638 |
639 | CGFloat progress = fabs([recognizer translationInView:self.gestureView].x) / (self.gestureView.bounds.size.width * 1.0);
640 | progress = MIN(1.0, MAX(0.0, progress));
641 | ```
642 |
643 | 中的`progress `出现问题。所以这里也就采用了截图的方式,对该截图进行缩放,而不去修改`vc`的`view`。
644 |
645 | 下面看下核心代码
646 | ```
647 | - (void)setToAnimation:(id)contextTransition
648 | {
649 | //获取目标动画的VC
650 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
651 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
652 | UIView *containerView = [contextTransition containerView];
653 |
654 | UIView *fromView = fromVc.view;
655 | UIView *toView = toVc.view;
656 |
657 | //截图
658 | UIView *toView_snapView = [toView snapshotViewAfterScreenUpdates:YES];
659 |
660 | CGRect left_frame = CGRectMake(0, 0, CGRectGetWidth(fromView.frame) / 2.0, CGRectGetHeight(fromView.frame));
661 | CGRect right_frame = CGRectMake(CGRectGetWidth(fromView.frame) / 2.0, 0, CGRectGetWidth(fromView.frame) / 2.0, CGRectGetHeight(fromView.frame));
662 | UIView *from_left_snapView = [fromView resizableSnapshotViewFromRect:left_frame
663 | afterScreenUpdates:NO
664 | withCapInsets:UIEdgeInsetsZero];
665 |
666 | UIView *from_right_snapView = [fromView resizableSnapshotViewFromRect:right_frame
667 | afterScreenUpdates:NO
668 | withCapInsets:UIEdgeInsetsZero];
669 |
670 | toView_snapView.layer.transform = CATransform3DMakeScale(0.7, 0.7, 1);
671 | from_left_snapView.frame = left_frame;
672 | from_right_snapView.frame = right_frame;
673 |
674 | //将截图添加到 containerView 上
675 | [containerView addSubview:toView_snapView];
676 | [containerView addSubview:from_left_snapView];
677 | [containerView addSubview:from_right_snapView];
678 |
679 | fromView.hidden = YES;
680 |
681 | [UIView animateWithDuration:self.duration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
682 | //左移
683 | from_left_snapView.frame = CGRectOffset(from_left_snapView.frame, -from_left_snapView.frame.size.width, 0);
684 | //右移
685 | from_right_snapView.frame = CGRectOffset(from_right_snapView.frame, from_right_snapView.frame.size.width, 0);
686 |
687 | toView_snapView.layer.transform = CATransform3DIdentity;
688 |
689 | } completion:^(BOOL finished) {
690 | fromView.hidden = NO;
691 |
692 | [from_left_snapView removeFromSuperview];
693 | [from_right_snapView removeFromSuperview];
694 | [toView_snapView removeFromSuperview];
695 |
696 | if ([contextTransition transitionWasCancelled]) {
697 | [containerView addSubview:fromView];
698 | } else {
699 | [containerView addSubview:toView];
700 | }
701 | [contextTransition completeTransition:![contextTransition transitionWasCancelled]];
702 | }];
703 | }
704 | ```
705 | `setBackAnimation`动画和上面的大同小异,就不再详细说明,文章后面有`demo`地址,大家可以看看。
706 | ###### 2、圆圈逐渐放大转场动画
707 |
708 | 在做动画之前,我们先要了解其大概原理
709 | 这里我简单的做了个草图
710 |
711 |
712 | 
713 | 小圆和大圆分别表示动画前和动画后
714 | 这里我们采用的是`UIBezierPath + mask + CAShapeLayer`的策略对其进行实习
715 |
716 | 大家都知道,`UIBezierPath`可以画圆形,而`CAShapeLayer`又具备`CGPathRef path`属性,可以和`UIBezierPath`联系起来,而`UIView`又具备`CALayer *mask`属性,这样三者就这么巧妙的联系起来了。
717 | 在这里,我们使用`CABasicAnimation`动画,通过对其设置`[CABasicAnimation animationWithKeyPath:@"path"]`来让其执行我们想要的`path`路径动画
718 | 于是就有了下面的代码
719 | ```
720 | - (void)setToAnimation:(id)contextTransition
721 | {
722 | //获取目标动画的VC
723 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
724 | UIView *containerView = [contextTransition containerView];
725 | [containerView addSubview:toVc.view];
726 |
727 | //创建UIBezierPath路径 作为后面动画的起始路径
728 | UIBezierPath *startPath = [UIBezierPath bezierPathWithArcCenter:self.centerPoint radius:self.radius startAngle:0 endAngle:2*M_PI clockwise:YES];
729 |
730 | //创建结束UIBezierPath
731 | //首先我们需要得到后面路径的半径 半径应该是距四个角最远的距离
732 | CGFloat x = self.centerPoint.x;
733 | CGFloat y = self.centerPoint.y;
734 | //取出其中距屏幕最远的距离 来求围城矩形的对角线 即我们所需要的半径
735 | CGFloat radius_x = MAX(x, containerView.frame.size.width - x);
736 | CGFloat radius_y = MAX(y, containerView.frame.size.height - y);
737 | //补充下 sqrtf求平方根 double pow(double x, double y); 求 x 的 y 次幂(次方)
738 | //通过勾股定理算出半径
739 | CGFloat endRadius = sqrtf(pow(radius_x, 2) + pow(radius_y, 2));
740 |
741 | UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:self.centerPoint radius:endRadius startAngle:0 endAngle:2*M_PI clockwise:YES];
742 |
743 | // self.endPath = endPath;
744 |
745 | //创建CAShapeLayer 用以后面的动画
746 | CAShapeLayer *shapeLayer = [CAShapeLayer layer];
747 | shapeLayer.path = endPath.CGPath;
748 | toVc.view.layer.mask = shapeLayer;
749 |
750 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
751 | animation.fromValue = (__bridge id _Nullable)(startPath.CGPath);
752 | animation.duration = self.duration;
753 | animation.delegate = (id)self;
754 | // animation.removedOnCompletion = NO;//执行后移除动画
755 | //保存contextTransition 后面动画结束的时候调用
756 | [animation setValue:contextTransition forKey:@"pathContextTransition"];
757 | [shapeLayer addAnimation:animation forKey:nil];
758 |
759 | self.maskShapeLayer = shapeLayer;
760 | }
761 | ```
762 | 由于代码中有比较详细的说明,所以这里就不再详细说明,`setBackAnimation`也大同小异
763 |
764 | ###### 3、圆圈和目标vc共同缩放转场动画
765 |
766 | 这个比较简单,主要是利用`UIView`的缩放进行的,由于目标`vc`的上角和圆是相切的,所以,这里我们可以先假设目标`vc`处于正常状态,然后再跟进小圆的中心,画一个大圆,让其和目标`vc`一起缩放就是。这里留了一个缺陷,那就是不支持侧滑,因为我是用目标`vc`进行缩放的,而没有截图,大家可以试试。
767 | 其实现大概为
768 |
769 | ```
770 | - (CGRect)frameToCircle:(CGPoint)centerPoint size:(CGSize)size
771 | {
772 | CGFloat radius_x = fmax(centerPoint.x, size.width - centerPoint.x);
773 | CGFloat radius_y = fmax(centerPoint.y, size.height - centerPoint.y);
774 | CGFloat endRadius = 2 * sqrtf(pow(radius_x, 2) + pow(radius_y, 2));
775 |
776 | CGRect rect = {CGPointZero,CGSizeMake(endRadius, endRadius)};
777 |
778 | return rect;
779 | }
780 |
781 |
782 | - (void)setToAnimation:(id)contextTransition
783 | {
784 | //获取目标动画的VC
785 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
786 | UIView *containerView = [contextTransition containerView];
787 |
788 | // [toVc beginAppearanceTransition:YES animated:YES];
789 | CGPoint center = toVc.view.center;
790 |
791 | CGRect rect = [self frameToCircle:self.centerPoint size:toVc.view.bounds.size];
792 | UIView *backView = [[UIView alloc] initWithFrame:rect];
793 | backView.backgroundColor = UICOLOR_FROM_RGB_OxFF(0xFFA500);
794 | backView.center = self.centerPoint;
795 | backView.layer.cornerRadius = backView.frame.size.height / 2.0;
796 | backView.transform = CGAffineTransformMakeScale(0.01, 0.01);
797 | [containerView addSubview:backView];
798 |
799 | self.startView = backView;
800 |
801 | toVc.view.transform = CGAffineTransformMakeScale(0.01, 0.01);
802 | toVc.view.alpha = 0;
803 | toVc.view.center = self.centerPoint;
804 | [containerView addSubview:toVc.view];
805 |
806 |
807 | [UIView animateWithDuration:self.duration animations:^{
808 |
809 | backView.transform = CGAffineTransformIdentity;
810 |
811 | toVc.view.center = center;
812 | toVc.view.transform = CGAffineTransformIdentity;
813 | toVc.view.alpha = 1;
814 |
815 | } completion:^(BOOL finished) {
816 | [contextTransition completeTransition:!contextTransition.transitionWasCancelled];
817 |
818 | // [toVc endAppearanceTransition];
819 | }];
820 | }
821 | ```
822 | `setBackAnimation`也大同小异,就不再说明
823 |
824 | ###### 4、翻书效果
825 |
826 | 这个还是花了些时间,主要不在思想上,而是在翻书有个阴影效果哪里,等下我会讲到。先说说思路,主要还是通过截图来实现。首先需要截当前`vc`的部分,如果向左滑则截右边,向右则截左,然后还需要截目标`vc`的两部分图,分别加到`containerView`上,假如现在向左翻,那么就要将目标`vc`的左边截图加到`containerView`的左边并且隐藏起来,让其绕`y`轴旋转`M_PI_2`,就是直插屏幕的样子,那么目标`vc`的右边截图就需要放到当前`vc`的下面,这样当当前`vc`在滑动的时候,我们就能看到下面的图了。当当前`vc`绕`y`轴旋转`-M_PI_2`的时候,目标`vc`的左边截图显示出来,并恢复原状,完成整副动画。
827 | 需要注意的是,截图在绕`y`轴旋转的时候,因为我们的`layer`的默认`anchorPoint`为`(0.5,0.5)`,所以需要改变`anchorPoint`的只,否则就绕中心在旋转了。
828 |
829 | 说了这么多,还是看看核心代码吧
830 | ```
831 | p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #3d71ff}p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #4dbf56}p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #00afca}p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #3d71ff; min-height: 16.0px}p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #2337da}p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px 'PingFang SC'; color: #4dbf56}span.s1 {font-variant-ligatures: no-common-ligatures}span.s2 {font-variant-ligatures: no-common-ligatures; color: #c2349b}span.s3 {font-variant-ligatures: no-common-ligatures; color: #00afca}span.s4 {font-variant-ligatures: no-common-ligatures; color: #3d71ff}span.s5 {font: 14.0px 'PingFang SC'; font-variant-ligatures: no-common-ligatures}span.s6 {font-variant-ligatures: no-common-ligatures; color: #4dbf56}span.s7 {font: 14.0px 'PingFang SC'; font-variant-ligatures: no-common-ligatures; color: #4dbf56}span.s8 {font: 14.0px Menlo; font-variant-ligatures: no-common-ligatures; color: #2337da}span.s9 {font: 14.0px Menlo; font-variant-ligatures: no-common-ligatures; color: #3d71ff}span.s10 {font: 14.0px Menlo; font-variant-ligatures: no-common-ligatures}span.s11 {font-variant-ligatures: no-common-ligatures; color: #8b84cf}span.s12 {font-variant-ligatures: no-common-ligatures; color: #93c96a}span.s13 {font-variant-ligatures: no-common-ligatures; color: #d28f5a}
832 |
833 | - (void)setToAnimation:(id)contextTransition
834 | {
835 | //获取目标动画的VC
836 | UIViewController *toVc = [contextTransition viewControllerForKey:UITransitionContextToViewControllerKey];
837 | UIViewController *fromVc = [contextTransition viewControllerForKey:UITransitionContextFromViewControllerKey];
838 | UIView *containerView = [contextTransition containerView];
839 |
840 | //m34 这个参数有点不好理解 为透视效果 我在http://www.jianshu.com/p/e8d1985dccec这里有讲
841 | //当Z轴上有变化的时候 我们所看到的透视效果 可以对比看看 当你改成-0.1的时候 就懂了
842 | CATransform3D transform = CATransform3DIdentity;
843 | transform.m34 = -0.002;
844 | [containerView.layer setSublayerTransform:transform];
845 |
846 | UIView *fromView = fromVc.view;
847 | UIView *toView = toVc.view;
848 |
849 | //截图
850 | //当前页面的右侧
851 | CGRect from_half_right_rect = CGRectMake(fromView.frame.size.width/2.0, 0, fromView.frame.size.width/2.0, fromView.frame.size.height);
852 | //目标页面的左侧
853 | CGRect to_half_left_rect = CGRectMake(0, 0, toView.frame.size.width/2.0, toView.frame.size.height);
854 | //目标页面的右侧
855 | CGRect to_half_right_rect = CGRectMake(toView.frame.size.width/2.0, 0, toView.frame.size.width/2.0, toView.frame.size.height);
856 |
857 | //截三张图 当前页面的右侧 目标页面的左和右
858 | UIView *fromRightSnapView = [fromView resizableSnapshotViewFromRect:from_half_right_rect afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
859 | UIView *toLeftSnapView = [toView resizableSnapshotViewFromRect:to_half_left_rect afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
860 | UIView *toRightSnapView = [toView resizableSnapshotViewFromRect:to_half_right_rect afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
861 |
862 |
863 | fromRightSnapView.frame = from_half_right_rect;
864 | toLeftSnapView.frame = to_half_left_rect;
865 | toRightSnapView.frame = to_half_right_rect;
866 |
867 | //重新设置anchorPoint 分别绕自己的最左和最右旋转
868 | fromRightSnapView.layer.position = CGPointMake(CGRectGetMinX(fromRightSnapView.frame), CGRectGetMinY(fromRightSnapView.frame) + CGRectGetHeight(fromRightSnapView.frame) * 0.5);
869 | fromRightSnapView.layer.anchorPoint = CGPointMake(0, 0.5);
870 |
871 | toLeftSnapView.layer.position = CGPointMake(CGRectGetMinX(toLeftSnapView.frame) + CGRectGetWidth(toLeftSnapView.frame), CGRectGetMinY(toLeftSnapView.frame) + CGRectGetHeight(toLeftSnapView.frame) * 0.5);
872 | toLeftSnapView.layer.anchorPoint = CGPointMake(1, 0.5);
873 |
874 | //添加阴影效果
875 |
876 | UIView *fromRightShadowView = [self addShadowView:fromRightSnapView startPoint:CGPointMake(0, 1) endPoint:CGPointMake(1, 1)];
877 | UIView *toLeftShaDowView = [self addShadowView:toLeftSnapView startPoint:CGPointMake(1, 1) endPoint:CGPointMake(0, 1)];
878 |
879 | //添加视图 注意顺序
880 | [containerView insertSubview:toView atIndex:0];
881 | [containerView addSubview:toLeftSnapView];
882 | [containerView addSubview:toRightSnapView];
883 | [containerView addSubview:fromRightSnapView];
884 |
885 | toLeftSnapView.hidden = YES;
886 |
887 |
888 | //先旋转到最中间的位置
889 | toLeftSnapView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 1, 0);
890 | //StartTime 和 relativeDuration 均为百分百
891 | [UIView animateKeyframesWithDuration:self.duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
892 | [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{
893 |
894 | fromRightSnapView.layer.transform = CATransform3DMakeRotation(-M_PI_2, 0, 1, 0);
895 | fromRightShadowView.alpha = 1.0;
896 | }];
897 |
898 | [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{
899 | toLeftSnapView.hidden = NO;
900 | toLeftSnapView.layer.transform = CATransform3DIdentity;
901 | toLeftShaDowView.alpha = 0.0;
902 | }];
903 | } completion:^(BOOL finished) {
904 | [toLeftSnapView removeFromSuperview];
905 | [toRightSnapView removeFromSuperview];
906 | [fromRightSnapView removeFromSuperview];
907 | [fromView removeFromSuperview];
908 |
909 | if ([contextTransition transitionWasCancelled]) {
910 | [containerView addSubview:fromView];
911 | }
912 |
913 | [contextTransition completeTransition:![contextTransition transitionWasCancelled]];
914 | }];
915 |
916 |
917 |
918 | //本来打算用基础动画来实现 但是由于需要保存几个变量 在动画完成的代理函数中用,所以就取消这个想法了
919 | // CABasicAnimation *fromRightAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
920 | // fromRightAnimation.duration = self.duration/2.0;
921 | // fromRightAnimation.beginTime = CACurrentMediaTime();
922 | // fromRightAnimation.toValue = @(-M_PI_2);
923 | // [fromRightSnapView.layer addAnimation:fromRightAnimation forKey:nil];
924 | //
925 | //
926 | // CABasicAnimation *toLeftAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
927 | // toLeftAnimation.beginTime = CACurrentMediaTime() + self.duration/2.0;
928 | // toLeftAnimation.fromValue = @(M_PI_2);
929 | // [toLeftAnimation setValue:contextTransition forKey:@"contextTransition"];
930 | // [toLeftSnapView.layer addAnimation:toLeftAnimation forKey:@"toLeftAnimation"];
931 | }
932 | ```
933 | 写到这里,差不多转场动画我能够写的就到这里了,文章实在是有点长,不是故意为之,只是我想写的稍微详细点,对自己也是一个很好的提升。如果能帮到你,还请给个`star`,嘿嘿~
934 | 下面就附上[demo](https://github.com/gao211326/GLTransitionAnimationDemo)地址
935 | 如果有什么不对的地方,还请多多指教,共同成长。
936 |
937 |
--------------------------------------------------------------------------------