IOS7的转场动画和CATransform3D简单使用

说来惭愧自己惭愧,由于自己开启了懒汉模式,一直没怎么研究过IOS7新的转场的动画,今天死磕的一天终于有点成效,还简单弄了下CATransform3D的内容

先看图



现在好多APP喜欢这样玩转场动画。。。于是就简单研究了一下 ,适合初学者,没有过多介绍深层的东西

说白了这就是执行了present的跳转代码

SecViewController *sec = [[SecViewController alloc]init];
    sec.transitioningDelegate = self;  //让动画变得炫酷就靠它了
    [self presentViewController:sec animated:YES completion:nil];

是不是就多了实现了一个代理?没错,靠它 我们就能实现这样的炫酷动画了。

这个代理里需要实现两个方法

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    
    _presentAnimation.duration = 1;
    self.presentAnimation.reverse = NO;
    return self.presentAnimation;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {

    self.presentAnimation.reverse = YES;
    
    return self.presentAnimation;
}

这两个带来方法从方法名称基本就明白什么意思啦?一个是present的实现方法,一个是dismiss的实现方法。

这里面返回的是什么呢?这里就是我们返回的自定义动画


下面说说这个自定义动画的类的构造吧

接口文件

/**
 *  自定义的动画类
 *  实现协议------>@protocol UIViewControllerAnimatedTransitioning
 *  这个接口负责切换的具体内容,也即“切换中应该发生什么”
 */
#import <Foundation/Foundation.h>

@interface CustomAnimatior : NSObject<UIViewControllerAnimatedTransitioning>
@property (nonatomic, assign) NSTimeInterval duration;//执行时间
@property (nonatomic, assign) BOOL reverse;//执行present或者dismiss的标识
@end

实现文件

#import <UIKit/UIKit.h>
#import "CustomAnimatior.h"
@interface CustomAnimatior()

@end
@implementation CustomAnimatior
// 系统给出一个切换上下文,我们根据上下文环境返回这个切换所需要的花费时间
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return self.duration;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *toView = toVC.view;
    UIView *fromView = fromVC.view;
    
    [self animateTransition:transitionContext fromVC:fromVC toVC:toVC fromView:fromView toView:toView];
}
// 完成容器转场动画的主要方法,我们对于切换时的UIView的设置和动画都在这个方法中完成
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext fromVC:(UIViewController *)fromVC toVC:(UIViewController *)toVC fromView:(UIView *)fromView toView:(UIView *)toView {
    
    if(self.reverse){
        [self executeReverseAnimation:transitionContext fromVC:fromVC toVC:toVC fromView:fromView toView:toView];
    } else {
        [self executeForwardsAnimation:transitionContext fromVC:fromVC toVC:toVC fromView:fromView toView:toView];
    }

}

-(void)executeReverseAnimation:(id<UIViewControllerContextTransitioning>)transitionContext fromVC:(UIViewController *)fromVC toVC:(UIViewController *)toVC fromView:(UIView *)fromView toView:(UIView *)toView {
    
    UIView* containerView = [transitionContext containerView];
    
    // positions the to- view behind the from- view
    CGRect frame = [transitionContext initialFrameForViewController:fromVC];
    toView.frame = frame;
    CATransform3D scale = CATransform3DIdentity;
    toView.layer.transform = CATransform3DScale(scale, 0.6, 0.6, 1);
    toView.alpha = 0.6;
    
    [containerView insertSubview:toView belowSubview:fromView];
    
    CGRect frameOffScreen = frame;
    frameOffScreen.origin.y = frame.size.height;
    
    CATransform3D t1 = [self firstTransform];
    
    [UIView animateKeyframesWithDuration:self.duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{
        
        // push the from- view off the bottom of the screen
        [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{
            fromView.frame = frameOffScreen;
        }];
        
        // animate the to- view into place
        [UIView addKeyframeWithRelativeStartTime:0.35f relativeDuration:0.35f animations:^{
            toView.layer.transform = t1;
            toView.alpha = 1.0;
        }];
        [UIView addKeyframeWithRelativeStartTime:0.75f relativeDuration:0.25f animations:^{
            toView.layer.transform = CATransform3DIdentity;
        }];
    } completion:^(BOOL finished) {
        if ([transitionContext transitionWasCancelled]) {
            toView.layer.transform = CATransform3DIdentity;
            toView.alpha = 1.0;
        }
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}


-(void)executeForwardsAnimation:(id<UIViewControllerContextTransitioning>)transitionContext fromVC:(UIViewController *)fromVC toVC:(UIViewController *)toVC fromView:(UIView *)fromView toView:(UIView *)toView {
    
    UIView* containerView = [transitionContext containerView];
    
    // positions the to- view off the bottom of the sceen
    CGRect frame = [transitionContext initialFrameForViewController:fromVC];
    CGRect offScreenFrame = frame;
    offScreenFrame.origin.y = offScreenFrame.size.height;
    toView.frame = offScreenFrame;
    
    [containerView insertSubview:toView aboveSubview:fromView];
    
    CATransform3D t1 = [self firstTransform];
    CATransform3D t2 = [self secondTransformWithView:fromView];
    
    [UIView animateKeyframesWithDuration:self.duration delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{
        //这里用到的是关键帧动画,也是iOS7的新特性
        
        // push the from- view to the back
        [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.4f animations:^{
            fromView.layer.transform = t1;
            fromView.alpha = 0.6;
        }];
        [UIView addKeyframeWithRelativeStartTime:0.2f relativeDuration:0.4f animations:^{
            fromView.layer.transform = t2;
        }];
        
        // slide the to- view upwards. In his original implementation Tope used a 'spring' animation, however
        // this does not work with keyframes, so we siulate it by overshooting the final location in
        // the first keyframe
        [UIView addKeyframeWithRelativeStartTime:0.6f relativeDuration:0.2f animations:^{
            toView.frame = CGRectOffset(toView.frame, 0.0, -30.0);
        }];
        [UIView addKeyframeWithRelativeStartTime:0.8f relativeDuration:0.2f animations:^{
            toView.frame = frame;
        }];
        
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
    
    
}
-(CATransform3D)firstTransform{
    CATransform3D t1 = CATransform3DIdentity;
    t1.m34 = 1.0/-500; //应该透视参数 ,这个值应该是和rotation所匹配的 ,这个值越小 透视角度越大  正负代表透视方向
    t1 = CATransform3DScale(t1, 0.95, 0.95, 1);//这个3D的缩放,x,y,z
    t1 = CATransform3DRotate(t1, 15.0f * M_PI/180.0f, 1, 0, 0);
    return t1;
    
}

-(CATransform3D)secondTransformWithView:(UIView*)view{
    
    CATransform3D t2 = CATransform3DIdentity;
    t2.m34 = [self firstTransform].m34;
    //这是视图的偏移量 tx:X轴偏移位置,往右为正数。 ty:Y轴偏移位置,往下为正数。   tz:Z轴偏移位置,往外为正数。
    t2 = CATransform3DTranslate(t2, 0, view.frame.size.height*-0.08, 0);
    t2 = CATransform3DScale(t2, 0.8, 0.8, 1);
    
    return t2;
}

在这个文件里需要引入

UIViewControllerAnimatedTransitioning的代理

并且实现两个方法

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
<pre name="code" class="objc">- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext

 
transitionContext
第一个方法是返回的时间 ,第二个就是方法就是我们需要自己自定义的动画。通过transitionContext可以获取到 当下的容器view

[transitionContext containerView]
以及formView和toView 这两个顾名思义 一个是当前的view 一个是切换的view。

viewControllerForKey:UITransitionContextFromViewControllerKey和

viewControllerForKey:UITransitionContextToViewControllerKey两个方法获取。


在创建动画的时候还用到了一个有关动画的特性就是关键帧动画

+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
这个是穿件关键帧动画的方法
下面的是穿件单个帧动画的方法
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations NS_AVAILABLE_IOS(7_0);

CATransform3D在实现上也没有什么难度.m文件里已经有了注释,靠自己的理解 ,可能有些3D参数理解有误,发现错误请评论谢谢

创建好这个类然后在ViewController实例化

@property (nonatomic, strong)CustomAnimatior *p

 _presentAnimation = [CustomAnimatior new];

一定要实例化。。。

各位没玩过码友,赶紧试试吧


源码下载地址:

https://coding.net/u/alexgaoCode/p/IOS-translationDEMO/git




import UIKit import QuartzCore import SceneKit class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // create a new scene let scene = SCNScene(named: "art.scnassets/ship.scn")! // create and add a camera to the scene let cameraNode = SCNNode() cameraNode.camera = SCNCamera() scene.rootNode.addChildNode(cameraNode) // place the camera cameraNode.position = SCNVector3(x: 0, y: 0, z: 15) // create and add a light to the scene let lightNode = SCNNode() lightNode.light = SCNLight() lightNode.light!.type = SCNLightTypeOmni lightNode.position = SCNVector3(x: 0, y: 10, z: 10) scene.rootNode.addChildNode(lightNode) // create and add an ambient light to the scene let ambientLightNode = SCNNode() ambientLightNode.light = SCNLight() ambientLightNode.light!.type = SCNLightTypeAmbient ambientLightNode.light!.color = UIColor.darkGrayColor() scene.rootNode.addChildNode(ambientLightNode) // retrieve the ship node let ship = scene.rootNode.childNodeWithName("ship", recursively: true)! // animate the 3d object ship.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0, y: 2, z: 0, duration: 1))) // retrieve the SCNView let scnView = self.view as! SCNView // set the scene to the view scnView.scene = scene // allows the user to manipulate the camera scnView.allowsCameraControl = true // show statistics such as fps and timing information scnView.showsStatistics = true // configure the view scnView.backgroundColor = UIColor.blackColor() // add a tap gesture recognizer let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:") scnView.addGestureRecognizer(tapGesture) } func handleTap(gestureRecognize: UIGestureRecognizer) { // retrieve the SCNView let scnView = self.view as! SCNView // check what nodes are tapped let p = gestureRecognize.locationInView(scnView) let hitResults = scnView.hitTest(p, options: nil) // check that we clicked on at least one object if hitResults.count > 0 { // retrieved the first clicked object let result: AnyObject! = hitResults[0] // get its material let material = result.node!.geometry!.firstMaterial! // highlight it SCNTransaction.begin() SCNTransaction.setAnimationDuration(0.5) // on completion - unhighlight SCNTransaction.setCompletionBlock { SCNTransaction.begin() SCNTransaction.setAnimationDuration(0.5) material.emission.contents = UIColor.blackColor() SCNTransaction.commit() } material.emission.contents = UIColor.redColor() SCNTransaction.commit() } } override func shouldAutorotate() -> Bool { return true } override func prefersStatusBarHidden() -> Bool { return true } override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { if UIDevice.currentDevice().userInterfaceIdiom == .Phone { return .AllButUpsideDown } else { return .All } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Release any cached data, images, etc that aren't in use. } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值