小結一下跳轉頁面的動畫效果實現思路酿炸!
代碼移步GitHub
總結的轉場動畫是下面幾個情況:
- 導航控制器的 Push 動畫和 Pop 動畫
- 普通控制器的 Present 動畫和 Dismiss動畫瘫絮,
思路簡析:
- 跳轉的控制器遵守
UINavigationControllerDelegate
協(xié)議,從而實現 Pop 和 Push 的跳轉動畫填硕。
通過 operation == UINavigationControllerOperationPush 或者 UINavigationControllerOperationPop 區(qū)分是 Push 還是 Pop
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC``` - 跳轉的控制器遵守
UIViewControllerTransitioningDelegate
協(xié)議麦萤, 從而實現 Present 和 Dissmiss跳轉動畫
Present:
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
Dissmiss:
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;```
- <big><u><b>上述的幾個方法都是 返回一個遵守UIViewControllerAnimatedTransitioning協(xié)議的對象鹿鳖,而主要的動畫實現就是寫在這個對象當中!我們只要封裝好這個類型的對象壮莹,在上述方法中返回對應實例對象就能實現動畫效果翅帜!</big></u></b>
UIViewControllerAnimatedTransitioning協(xié)議 主要實現兩個方法
-(NSTimeInterval)transitionDuration: transitionContext: 跳轉的時間
-(void)animateTransition: transitionContext 所要執(zhí)行的動畫在這里實現 ```
其中第二個方法傳入的參數是泛型的
UIViewControllerContextTransitioning
對象
可以通過下面它的的實例方法獲取我們需要展示動畫的相關屬性
# 這個方法獲得的是 控制整個跳轉的頁面 (API 描述:這個視圖是動畫發(fā)生的地方(畫布))(將要跳轉到的控制器的view添加到畫布上執(zhí)行動畫)
- (nullable UIView *)containerView
# Key 取值 UITransitionContextFromViewControllerKey (源控制器)UITransitionContextToViewControllerKey(目標控制器)
- (nullable __kindof UIViewController *)viewControllerForKey:(NSString *)key
# Key 取值 UITransitionContextFromViewKey(源視圖) UITransitionContextToViewKey(目標視圖)
- (nullable __kindof UIView *)viewForKey:(NSString *)key
簡單效果展示:
上代碼:
第一步: 是封裝一個實現動畫的類(PP_Transition),遵循UIViewControllerAnimatedTransitioning
協(xié)議
PP_Transition.h中
- 導入 UIKit 框架
import <UIKit/UIKit.h> ```
- 定義一個枚舉類型命满,方便我們區(qū)分場景
枚舉判斷使用場景
typedef NS_OPTIONS(NSUInteger, AnimatedScene)
{
AnimatedScenePush = 0, // 值為 0
AnimatedScenePop = 1 << 0, // 值為 2 的 0次
AnimatedScenePresent = 1 << 1, // 值為 2 的 1次
AnimatedSceneDissmiss = 1 << 2 // 值為 2 的 2次
};
- 聲明一個自定義初始化方法
>```code
- (instancetype)initWithStytle:(AnimatedScene)scene;```
-------
####PP_Transition.m中
>- 延展一個屬性 用來記錄初始化的類型
>```code
{
AnimatedScene _scenceStyle;
}```
- 實現自定義初始化方法
>```code
- (instancetype)initWithStytle:(AnimatedScene)scene
{
if (self = [super init])
{
_scenceStyle = scene;
}
return self;
}
- 實現協(xié)議方法1: 轉場動畫持續(xù)時間
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return 1.0;
}``` - 實現協(xié)議方法2: 具體去實現轉場的動畫 (這里我就是簡單的實現幾個動畫涝滴, 我們可以根據具體的情況加以實現)
- 如果我們想加一些更好的效果,可以嘗試在畫布(containerView) View 上加上一些自定義的View 用來遮擋或者當做背景(比如 Pop回來時候目標View變大時候加一個背景)胶台,記住最后移除掉就行歼疮!這是一種思路!
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
// 獲取到 containerView視圖 (我們動畫發(fā)生的載體)
UIView *containerView = [transitionContext containerView];
// 我們要去的 View
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
// 從哪個 View 去的
UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
switch (_scenceStyle)
{
case AnimatedScenePush:
{// Push 動畫 這里只是舉個例子 動畫效果可以自己去使用
// 注意點: 一定要把目的視圖(要去的 View) 添加到容器(containerView)上.
[UIView animateWithDuration:1.0 animations:^{
fromView.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:^(BOOL finished) {
[containerView addSubview:toView];
// 這個方法大概就是完成過渡動畫诈唬,更新內部視圖韩脏,控制器狀態(tài)的轉變!
[transitionContext completeTransition:YES];
}];
NSLog(@"Push 動畫效果");
}
break;
case AnimatedScenePop:
{
// Pop 動畫
[UIView animateWithDuration:1.0 animations:^{
// 讓當前的二級頁面 從下方消失
fromView.frame = CGRectMake(0, kScreenH, kScreenW, kScreenH);
} completion:^(BOOL finished) {
[containerView addSubview:toView];
[UIView animateWithDuration:1.0 animations:^{
// 讓首級頁面 由小變大
toView.transform = CGAffineTransformMakeScale(1, 1);
} completion:^(BOOL finished) {
// 完成過度動畫
[transitionContext completeTransition:YES];
}];
}];
NSLog(@"Pop 動畫效果");
}
break;
case AnimatedScenePresent:
{
toView.frame = CGRectMake(kScreenW / 2.0 , kScreenH / 2.0, 0, 0);
[containerView addSubview:toView];
[UIView animateWithDuration:1.0 animations:^{
toView.frame = CGRectMake(0 , 0, kScreenW, kScreenH);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
NSLog(@"Present 動畫效果");
}
break;
case AnimatedSceneDissmiss:
{
[UIView animateWithDuration:1.0 animations:^{
// 讓當前的二級頁面 從上方消失
fromView.frame = CGRectMake(0, -kScreenH, kScreenW, kScreenH);
} completion:^(BOOL finished) {
[containerView addSubview:toView];
// 完成過度動畫
[transitionContext completeTransition:YES];
}];
NSLog(@"Dissmiss 動畫效果");
}
break;
default:
break;
}
}
在跳轉的控制器中:
- 首先遵守
<UIViewControllerTransitioningDelegate, UINavigationControllerDelegate>
代理
- 設置代理
// 設置 導航控制器代理完成 push 和 pop
self.navigationController.delegate = self;
// 設置 模態(tài)轉場過渡代理
目的控制器Vc.transitioningDelegate = self;
目的控制器Vc.modalPresentationStyle = UIModalPresentationCustom;```
>- 代理方法實現
```code
// 導航控制器的跳轉動畫代理方法 在這里完成 Push 和 Pop 動畫
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
return operation == UINavigationControllerOperationPush ? [[PP_Transition alloc] initWithStytle:(AnimatedScenePush)] : [[PP_Transition alloc] initWithStytle:(AnimatedScenePop)];
}
// 完成轉場 Present 動畫代理
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
NSLog(@"----------->Present 一級視圖控制器中");
return [[PP_Transition alloc] initWithStytle:(AnimatedScenePresent)];
}
// 轉場 Dissmiss 動畫 代理
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
NSLog(@"----------->Dissmiss 一級視圖控制器中");
return [[PP_Transition alloc] initWithStytle:(AnimatedSceneDissmiss)];
}
最后說一句:
我開始寫的類名不太好铸磅, 弄了一半想改的話可以這樣!
.h選中要改的類名
---> 菜單欄選中 Edit
---> Refactor
---> Rename