正文:
现在我们举个列子来介绍实现动作事件过渡的方法。该例子最终效果如下:
1. 我们先创建俩个视图控制器,一个是ViewController(蓝色的那个),另一个是RedViewController(红色的那个。
----ViewController.m----
@interface ViewController ()<UIViewControllerTransitioningDelegate>
@property (nonatomic, strong) PresentAnimater *presentAnimater;
@property (nonatomic, strong) DismissAnimater *dismissAnimater;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.presentAnimater = [[PresentAnimater alloc] init];
self.dismissAnimater = [[DismissAnimater alloc] init];
self.view.backgroundColor = [UIColor blueColor];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[button setTitle:@"Click me" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)buttonClicked:(UIButton *)btn
{
RedViewController *redVC = [[RedViewController alloc] init];
redVC.delegate = self;
redVC.transitioningDelegate = self;
[self presentViewController:redVC animated:YES completion:nil];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
return self.presentAnimater;
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return self.dismissAnimater;
}
---RedViewController.m---
@implementation RedViewController
- (void)viewDidLoad {
[super viewDidLoad]; self.view.backgroundColor = [UIColor redColor];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[button setTitle:@"dismiss me" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)buttonClicked:(UIButton *)btn {
[self dismissViewControllerAnimated:YES completion:nil];
}
(1) 如果需要执行自定义过渡效果,就要设置transitionDelegate代理对象。
该代理需要实现以下俩个方法:
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
分别返回呈现(present)视图控制器时的动画对象和解散(dismiss)视图控制器时的动画对象,具体的动画细节需要在动画对象中实现,动画对象需要服从UIViewControllerAnimatedTransitioning协议。第一个方法在[selfpresentViewController:redVCanimated:YEScompletion:nil];之后被调用,第二个方法在[selfdismissViewControllerAnimated:YEScompletion:nil];之后被调用。
2. 创建呈现视图控制器时的动画对象(present视图控制器时的过渡动画效果)
----PresentAnimater.m-----
@implementation PresentAnimater
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.4;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
// 1. 获取源控制器和目标控制器
UIViewController *scVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 2. 添加目标控制器的view
CGRect scFrame = scVc.view.frame;
CGRect toFrame = scFrame;
toFrame.origin.x = toFrame.size.width;
toVc.view.frame = toFrame;
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toVc.view];
// 3. 动画 源控制器的View缩小 --> 目标控制器推入
CGFloat boder = 20;
CGFloat duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration animations:^{
scVc.view.alpha = 0.5f;
scVc.view.frame = CGRectMake(boder, boder, scFrame.size.width - 2 * boder, scFrame.size.height - 2 * boder);
toVc.view.frame = scFrame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
(1) UIViewControllerAnimatedTraning协议是用来指定动画细节,一定要实现以下2个方法:
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
前者返回动画执行的时间,后者实现过渡中的具体动画效果。 transitionContext是过渡过程中的上下文,可以从中获取源视图控制器(fromVc)、目标视图控制器(toVc)等参数。(2)动画执行完成后一定要有这句[transitionContextcompleteTransition:YES];这句话是告诉系统过渡动画完成,系统会自动做些后续的清理工作。如果不写,将无法再次切换视图控制器。
3. 创建解散视图控制器时的动画对象(dismiss视图控制器时的过渡动画效果)
<span style="font-size:14px;">@implementation DismissAnimater
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.4;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *scVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
CGRect scFrame = scVc.view.frame;
CGRect toFrame = scFrame;
toFrame.origin.x = scFrame.size.width;
toVc.view.frame = CGRectInset(scFrame, 20, 20);
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toVc.view];
[containerView sendSubviewToBack:toVc.view];
CGFloat duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration animations:^{
scVc.view.frame = toFrame;
toVc.view.frame = scFrame;
toVc.view.alpha = 1;
} completion:^(BOOL finished) {
// NO : 会还原动画前所有View的位置。
[transitionContext completeTransition:YES];
}];
}</span>
和呈现视图控制器动画对象一样,就不再赘述。
demo地址--点击打开链接
动作事件过渡的实现方法很简单,但是手势交互过渡稍微复杂点,下一篇我们再说。