zoukankan      html  css  js  c++  java
  • 动画技术

    每次看到别人的招聘信息,好多都是要求熟练使用Core Animation(CA)。木办法呀,那就学习吧。看到那些很长的名字的类还有很长的方法等等等等,就头疼,觉得太难了。你是不是也有这种情况?

    我只想说:世上无难事,只怕有心人。只要我们能够静下心认真的看看,其实也不是那么难的。不罗嗦了。开始正题:

    ------------------------------------------------------------------------文章比较长,做好心理准备哈------------------------------------------------------------------------

    这里主要介绍以下几块:(参考《iOS图形图像、动画和多媒体编程技术最佳实践》)

    1、视图动画

    2、iOS7自定的视图的过渡动画

    3、iOS7 UIKit力学

    4、iOS 7 运动效果(Motion Effects)

    5、Core Animation

    废话不多说,开始第一块:

    视图动画

    最简单的动画:

    - (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion NS_AVAILABLE_IOS(5_0);

    简单把,我们用代码进行视图切换的时候都会用到这个,其中的flag就是用来开启动画的。所以平常我们都会用到动画,只不过是没有注意罢了。

    下面来看个比较简单的一个动画:

    先看看要实现的效果:

    怎么实现的呢?看看代码:

    - (IBAction)buttonAction:(id)sender {
    //    //方法1
    //    _myButton.alpha = 0;
    //    [UIView beginAnimations:@"animation" context:nil];
    //
    //    [UIView setAnimationDuration:1.5];
    //    [UIView setAnimationDelegate:self];
    //    [UIView setAnimationDidStopSelector:@selector(showButton)];
    //        _ballLabel.frame = CGRectMake(_ballLabel.frame.origin.x, _ballLabel.frame.origin.y+200*flag, _ballLabel.frame.size.width, _ballLabel.frame.size.height);
    //    flag = -flag;
    //    [UIView commitAnimations];
    
    //    //方法2:没控制按钮隐藏显示
    //    [UIView animateWithDuration:1.5 animations:^{
    //        CGRect frame = self.ballLabel.frame;
    //        frame.origin.y += 200*flag;
    //        self.ballLabel.frame = frame;
    //        flag = -flag;
    //    }];
        //动画3:当小球动时按钮消失,当小球不动时按钮出现
         _myButton.alpha = 0;
        [UIView animateWithDuration:1.5 animations:^{
           
            CGRect frame = self.ballLabel.frame;
            frame.origin.y +=200*flag;
            self.ballLabel.frame = frame;
            flag = -flag;
        } completion:^(BOOL finished) {
            _myButton.alpha = 1;
        }];
    }
    - (void)showButton {
        _myButton.alpha = 1;
    }

    上面的三种方法都能实现相同的效果。

    在iOS4之前,如果我们想获取动画开始和结束事件,我们需要设置委托对象,然后通过下面两个方法来设置:

    + (void)setAnimationWillStartSelector:(SEL)selector;                // default = NULL. -animationWillStart:(NSString *)animationID context:(void *)context
    + (void)setAnimationDidStopSelector:(SEL)selector;  

    第一个是动画刚开始要触发的动作,第二个市动画结束时要触发的动作。

    后来iOS升级后可以在回调中进行处理了。就像动画3一样。

    如果针对我们平时用到的简单动画,用UIView这种就可以了。

    简单的动画就这样完了????里面的额函数什么意思呢???那就看一下最重要的两个吧。

    + (void)beginAnimations:(NSString *)animationID context:(void *)context;

    标记动画开始(或执行)块的开头。

    + (void)commitAnimations;

    标记动画开始(执行)块的结束,并且安排动画执行。

    我们可以在中间写上一些自定义的东西。比如我们需要设置动画重复次数,开始时间,或者其他的。

    ------------------------------------------------应该能够接受吧,耐心看看------------------------------------------------

    看看第三种方法:

    + (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

    这个方法高度封装,你可以不用上面说的第一种方法来标记开始和结束了。直接用这个方法。

    duration:动画执行的时间。

    animations:后面的block是动画执行的内容。

    completion:后面的block是当动画结束时的操作。

    个人建议还是使用下面那种方法,毕竟新版本的东西。

    累么?不累看看下面的过渡动画。

    过渡动画就是两个视图进行切换的时候的动画。先看看效果:

    直接看看代码:

    /**
     动画还有很多属性:例如动画曲线、过渡(界面跳转)动画、重复次数和自动反转等。
     */
    - (IBAction)transitionAction1:(UIButton *)sender {
        [UIView beginAnimations:@"animagtionID" context:nil];
        [UIView setAnimationDuration:1.0];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];  //设置动画曲线:这里有四种UIViewAnimationCurveEaseInOut:缓入缓出。设置出场或者入场的速度。
        [UIView setAnimationRepeatAutoreverses:NO];   //如果设置成yes,那么会执行在返回。
        switch (sender.tag) {
            case 1:
                [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.view cache:YES];
                break;
            case 2:
                [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
                break;
            case 3:
                [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.view cache:YES];
                break;
            case 4:
                [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
                break;
            default:
                break;
        }
        [UIView commitAnimations];
        //在ios4后添加了+transitionWithView:duration:options:animations:completion:指定的视图容器内创建动画过渡。+transitionFromView:toView:duration:options:completion:在指定的两个视图之间创建动画过渡。
        
    }

    其实也很简单,只不过在原来简单动画的基础上添加了一个:

    + (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;

    typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
        UIViewAnimationTransitionNone,
        UIViewAnimationTransitionFlipFromLeft,
        UIViewAnimationTransitionFlipFromRight,
        UIViewAnimationTransitionCurlUp,
        UIViewAnimationTransitionCurlDown,
    };

    这就是UIViewAnimationTransition的枚举。里面就是这几种类型。感兴趣可以自己试试。

    ----------------------------------------------------------------------打断一下----------------------------------------------------------------------

    transition:过渡;转变;转换;变调的意思。

    ----------------------------------------------------------------------打断结束----------------------------------------------------------------------

    所以遇到animationTransition不要觉得它很难以理解:就是动画过渡的意思。

    接下来的iOS7自定义动画只是简单介绍一下吧。因为。。。。。。。。。。。。。。

    视图过渡有两种情况:树形结构导航和模态导航。

    树形的就类似与表格点击cell进入另一个视图。是通过UINavigationController控制器堆栈实现的视图过渡。

    模态导航:是通过UIViewController控制器实现的。

    树形的自定义动画需要涉及两个协议:UIViewControllerAnimatedTransitioning和UINavigationAnimatedTransitioning协议

    @protocol UIViewControllerAnimatedTransitioning <NSObject>
    
    // This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
    // synchronize with the main animation. 
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext;
    // This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
    
    
    @optional

    这是UIViewControllerAnimatedTransitioning的协议内容。要想去自定义动画就去实现这两个代理方法。

    我只知道下面两句:

      UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    通过transitionContext可以得到从哪个视图的那个视图和到哪个视图的那个视图。。。(有点绕,,,)

    然后剩下的多查看一些资料学习把。

    模态导航自定义过渡动画需要在视图控制器实现UIViewControllerTransitioningDelegate协议。

    @protocol UIViewControllerTransitioningDelegate <NSObject>
    
    @optional
    - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
    
    - (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
    
    - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator;
    
    - (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
    
    - (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0);
    
    @end

    这个是协议内容。具体的实现自定义模态视图就是在这些代理方法中设置的。

    ------------------------------------------------------------------------------UIKit力学来了------------------------------------------------------------------------------

    先复习一下英语:

    dynamics:动力学,力学。

    attachment:附件;依恋

    collision:碰撞,冲突

    gravity:重力

    snap:

    突然折断,拉断;猛咬;啪地关上。

    开始力学学习。

    UIKit力学可以使得视图对象具有真实的物理运动效果。在游戏中能够实现物理效果的技术叫物理引擎

    力学中用到的类:

    UIDynamicAnimator:它可以理解为动态的动画师,它为他的动态的元素提供物理相关的能力和动画,并且提供动画环境。是用来存放要使用的力学行为(UIDynamicBehavior)。

    UIDynamicBehavior有6个类:

    UIAttachmentBehavior:吸附

    UICollisionBehavior:碰撞

    UIGravityBehavior:重力

    UIPushBehavior:推

    UISnapBehavior:甩

    UIDynamicItemBehavior:

    对于每个力学行为都有多个力学项目:(UIDynamicItem)。其中UIDynamicAnimator的ReferenceView属性指向了所要呈现的视图。

    总体概括:一个UIDynamicAnimator可以包含多个力学行为,通过addBehavior方法添加力学行为。一个力学行为可以包括多个力学项目,通过addItem添加。还有UIDynamicAnimator与ReferenceView之间是1:1关系,即一个UIDynamicAnimator只有一个ReferenceView与之对应。

    --------------------------------------------------下面的行为触发为了方便都是在视图加载出现后触发的--------------------------------------------------

    重力行为:

    - (void)viewDidLoad {
        [super viewDidLoad];
        _gravityButton.backgroundColor = [UIColor blackColor];
        _gravityButton.layer.cornerRadius = _gravityButton.frame.size.height/2;
    
    
        
    }
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:YES];
        animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];   //存放要使用的力学行为
        gravity = [[UIGravityBehavior alloc] init];   //新建一个重力力学行为
        [animator addBehavior:gravity];   //将重力力学行为添加到力学行为里
        //设置重力方向
        CGVector gravityDirection = {0.0,0.5};//设置重力方向
        [gravity setGravityDirection:gravityDirection];
        [gravity addItem:_gravityButton];   //将_gravityButton对象添加到力学行为gravity对象中,其中_gravityButton是模拟重力行为的视图对象。
    }

    主要是我用了一个button,然后刚进入这个界面,button就会由于重力作用自由落体。效果如下:

    简单介绍一下实现:

    首先需要创建一个动画师(UIDynamicAnimator)用于存放要使用的重力行为。referenceView你可以理解为为动态动画师准备的视图。

    然后是设置重力方向,其中的CGVector:

    struct CGVector {
      CGFloat dx;
      CGFloat dy;
    };

    就是一个结构体而已。定义了重力的 方向。(感兴趣的可以自己调整查看效果)

    然后就是把重力行为添加到animator中。

    其中

     [gravity addItem:_gravityButton];   //将_gravityButton对象添加到力学行为gravity对象中,其中_gravityButton是模拟重力行为的视图对象。

    添加元素你就可以理解成那个对象需要使用该力学行为,就把那个元素添加进去。

    ---------------------------------------------------------------重力行为结束---------------------------------------------------------------

    碰撞行为:

    - (void)viewDidLoad {
        [super viewDidLoad];
        _myButton.layer.cornerRadius = _myButton.frame.size.height/2;
    
        // Do any additional setup after loading the view.
    }
    //碰撞行为中特有的方法是碰撞检测,我们可以检测运动的物体和ReferenceView:[collsion setTranslatesReferenceBoundsIntoBoundary:YES];
    //检测是否与其他物体边界发生碰撞的方法:
    /*
     CGPoint p1 = barrier.frame.origin;
     CGPoint p2 = CGPointMake(p1*x+barrier.frame.size.width,p1.y);
     [collision addBoundaryWithdIdentifier:@"barrier" fromPoint:p1 toPoint:p2];
     */
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:YES];
        animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
        garvity = [[UIGravityBehavior alloc] initWithItems:@[_myButton]];
        CGVector vector = {0.0,1.9};
        [garvity setGravityDirection:vector];
        [animator addBehavior:garvity];
        
        
        //碰撞行为
        collision = [[UICollisionBehavior alloc] initWithItems:@[_myButton]];
        collision.translatesReferenceBoundsIntoBoundary = YES;
        [animator addBehavior:collision];
    }

    效果图:

    具体实现就不多说了,加了一个重力行为,然后落地后设置碰撞。

    这里主要介绍亮点:

    第一:检测是否与ReferenceView边界发生碰撞方法如下:

    [collision setTranslatesReferenceBoundsIntoBoundary:YES];

    第二:检测是否与其他物体边界发生碰撞方法如下:

     CGPoint p1 = barrier.frame.origin;
     CGPoint p2 = CGPointMake(p1*x+barrier.frame.size.width,p1.y);
     [collision addBoundaryWithdIdentifier:@"barrier" fromPoint:p1 toPoint:p2];

    其中的barrier就是其他视图对象。具体可以理解一下慢慢。

    ---------------------------------------------------------------碰撞行为结束---------------------------------------------------------------

    吸附行为:

    - (void)viewDidLoad {
        [super viewDidLoad];
    //    self.view.backgroundColor = []
    }
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:YES];
        animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
        
        //重力行为
        gravity = [[UIGravityBehavior alloc] initWithItems:@[_boxImageView]];
        [animator addBehavior:gravity];
        
        //碰撞行为
        collision = [[UICollisionBehavior alloc] initWithItems:@[_boxImageView]];
        [collision addBoundaryWithIdentifier:@"barrier" fromPoint:_barrier.frame.origin toPoint:CGPointMake(_barrier.frame.origin.x+_barrier.frame.size.width, _barrier.frame.origin.y)];
        
        collision.translatesReferenceBoundsIntoBoundary = YES;
        collision.collisionDelegate = self;
        [animator addBehavior:collision];
        /*
         UIDynamicItemBehavior是行为限制,
         */
        UIDynamicItemBehavior *itemBehaver = [[UIDynamicItemBehavior alloc] initWithItems:@[_boxImageView]];
        itemBehaver.elasticity = 0.5;
        [animator addBehavior:itemBehaver];
    }
    #pragma mark -
    - (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p {
        attach = [[UIAttachmentBehavior alloc] initWithItem:_attachPoint attachedToItem:_boxImageView];
        
        [animator addBehavior:attach];
    }

    效果如下:

    其中的图片是_boxImageView。方块是_attachPoint。

    这里我们需要实现UICollisionBehaviorDelegate代理方法。上面有个UIDynamicItemBehavior类。可以暂时把它理解为行为限制类。一会再说:

    ---------------------------------------------------------------吸附行为结束---------------------------------------------------------------

    推行为:

    /*
     推行为可以让视图对象朝着某个方向运行,这个推力有瞬间和持续两种方式。
     设置推行为需要考虑方向和力的大小。
     */
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:YES];
        animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
        push = [[UIPushBehavior alloc] initWithItems:@[_box] mode:UIPushBehaviorModeContinuous];
        CGVector pushDirection = {0.5,0};
        [push setPushDirection:pushDirection];
        [push setMagnitude:5.0f];
        [animator addBehavior:push];
    }

    效果如下:

    这里说一下:推行为有瞬间和持续两种方式。

    瞬间行为:UIPushBehaviorModeInstantaneous:运动比较快。

    持续行为:UIPushBehaviorModeContinuous:由慢变快

    还有setMagnitude:方法是用来设置推的力度。

    ---------------------------------------------------------------推行为结束---------------------------------------------------------------

    甩行为:

    /*
     能够时物体朝着某个目标点抛出甩出。并且有瞬间加速度,由慢及快,再由快及慢,最后停止在目标点。
     */
    - (void)viewDidAppear:(BOOL)animated {
        CGPoint p = [[self view] center];
        animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
        snap = [[UISnapBehavior alloc] initWithItem:_testButton snapToPoint:p];
        [animator addBehavior:snap];
    }

    效果如下:

    这里没什么可说的,看一下代码就行了。大概甩的动作就是:

    能够时物体朝着某个目标点抛出甩出。并且有瞬间加速度,由慢及快,再由快及慢,最后停止在目标点。

    ---------------------------------------------------------------甩行为结束---------------------------------------------------------------

    UIDynamicItemBehavior:

    它是用来设置力学行为参数的。参数包括:弹性系数、摩擦系数、阻力和密度等物理属性

    density:密度:

    elasticity:弹力系数0-1.0表示没有反弹,1表示完全弹性碰撞

    friction:摩擦系数

    resistance:阻力,CGFLOAT_MAX表示最大阻力

    allowRotation:是否允许旋转。

    angularResistance:角阻力,物理旋转时候,旋转方向的阻力。

    ---------------------------------------------------------------力学结束---------------------------------------------------------------

    现在看一下:iOS7运动效果:(Motion Effects)

    运动效果主要提供的API是UIInterpolatingMotionEffect类。

    UIView可以调用addMotionEffect:方法来添加运动效果。看例子:

    - (void)viewDidLoad {
        [super viewDidLoad];
    //    [[UIApplication sharedApplication] setStatusBarHidden:YES];
        //设置图片的偏移量
        UIInterpolatingMotionEffect * imageEffe = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
        imageEffe.maximumRelativeValue = @50.0;
        imageEffe.minimumRelativeValue = @-50.0;
        [self.imageView addMotionEffect:imageEffe];
        
        
        UIInterpolatingMotionEffect *nameEffe = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
        nameEffe.maximumRelativeValue = @100.0;
        nameEffe.minimumRelativeValue = @-100.0;
        [self.nameButton addMotionEffect:nameEffe];
    }

    这个在模拟器无法查看,只能真机查看,当左右晃动设备的时候,里面的图片也在移动。

    ---------------------------------------------------------------------------不行了---------------------------------------------------------------------------

    Core Animation下一个博客在介绍吧。因为它很重要。很重要。很重要。

    添加个源码把:http://pan.baidu.com/s/1hq2HN4g

     

     

    1.水波纹效果示例

  • 相关阅读:
    网络爬虫基础练习
    词频统计预处理
    将博客搬至CSDN
    内核探测工具systemtap简介(转)
    常用汉字的Unicode码表
    随机生成登录时的验证码图片
    response中用outputstream输出中文问题
    ServletContext读取web应用中的资源文件
    ServletContext
    URL描述web资源访问流程
  • 原文地址:https://www.cnblogs.com/zhanggui/p/4744742.html
Copyright © 2011-2022 走看看