zoukankan      html  css  js  c++  java
  • ios开发——仿新版iBooks书本打开与关闭动画

    IOS新版iBooks吸引人的地方除了有干净整洁的界面、方便灵活的操作以及大容量的书籍容量以外。还有其优秀的用户交互,尤其是其动画的使用。打开一本书时书本缓慢放大并打开。关闭一本书后书本关闭并回到原位置。

    如今我们来实现这个简单的功能。


    效果图:



    用到的知识:

    1、CAKeyframeAnimation的应用

    2、怎样在代理中区分两个不同的动画

    3、坐标系转换


    思路:

    这个动画主要用到的是CAAnimation,而且是CAKeyframeAnimation。当用户点击书本时。设置一个UIImageView(为其加上tag方便以后取)并将其放在选中书本的位置上(使用坐标系转换)。接着通过动画将其放大到全屏,完毕后将其锚点设置为(0,0.5)并让其绕y轴选中π/2角度,将早已放在以下的textView(本app中是自己定义的readView)展示出来。

    动画完毕后将UIImageView的透明度设为0。这样就是书本的打开过程。

    关闭过程类似,依据tag取出UIImageView并将其旋转,然后设置frame到原来书本的位置(能够用私有变量记录该位置),最后removeFromSuperview就可以。


    代码:

    首先是“准备阶段”

        //BookReadView是展示textView和顶部底部附加view的自己定义view
        CYZBookItemView *itemView = [notification object];
        CYZBookReadView *readView = [[CYZBookReadView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, self.view.height) ItemView:itemView];
        //设置delegate是为了当用户从阅读界面返回时做出响应
        readView.delegate = self;
        //先将其alpha设为0防止用户刚点击书本动画还在进行中时就出现这一界面
        readView.alpha = 0.0f;
        [self.view addSubview:readView];
        
        //展示动画的UIImageView
        UIImageView *showView = [[UIImageView alloc] initWithImage:itemView.bookImage.currentBackgroundImage];
        //坐标系转换
        _itemPosition = [itemView.superview convertRect:itemView.frame toView:self.view];
        showView.frame = _itemPosition;
        //设置tag方便以后取出
        showView.tag = 1001;
        showView.backgroundColor = [UIColor clearColor];
        [self.view addSubview:showView];

    关于坐标系转换(以矩形为例。point类似):


    - (void)convertRect:toView:方法:

    格式[被转换者所在的View convertRect: 被转换者的frame或bounds toView:转换到的View];返回在目标View中的rect

    比如,将当前视图的子视图viewA中的一个imageView转换到当前视图。

    能够例如以下调用:

    [viewA convertRect:viewA.imageView.frame toRect:self.view];

    或者[imageView.superView convertRect:imageView.frame toRect:self.view];

    当中self指控制器。


    - (void)convertRect:fromView:方法:

    格式[要转换到的View convertRect: 被转换者的frame或bounds fromView:被转换者所在的View];返回在目标View中的rect。

    还是上一个样例,能够这样写:

    [self.view convertRect:viewA.imageView.frame fromView:viewA];

    或者[self.view convertRect:imageView.frame fromView:imageView.superView];

    当中self指控制器


    接着准备工作完毕了以后就能够開始动画了。

    一下是打开动画的部分

        [UIView animateWithDuration:0.5f animations:^{
            //将UIImageView放大为全屏
            showView.frame = self.view.bounds;
        } completion:^(BOOL finished) {
            if (finished) {
                //展示出readView
                readView.alpha = 1.0f;
                
                //设置锚点
                showView.layer.anchorPoint = CGPointMake(0, 0.5);
    #warning 不知道为什么,不加以下这句话showView会显示异常:即仅仅显示一半
                showView.frame = CGRectMake(0, 0, showView.width, showView.height);
    
                CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
                //设置其绕y轴旋转
                animation.keyPath = @"transform.rotation.y";
                //设置持续时间。能够定义一常量来表示
                animation.duration = 0.5f;
                animation.speed = 0.55f;
                animation.removedOnCompletion = NO;
                //旋转π/2度
                [animation setValues:[NSArray arrayWithObjects:@0.0f, @-M_PI_2, nil]];
                //设置代理便于回调
                animation.delegate = self;
                //这里必须设置上key,为了接下来区分不同动画
                [showView.layer addAnimation:animation forKey:@"rotateToOpenBook"];
            }
        }];

    代码中凝视已经解释得比較具体了,仅仅只是正如warning写得那样。本来我是用showView.layer.transform来实现动画的,这样会省非常多事。比方不用在代理中区分动画、不用记录position来在方法间传值等,只是不知道为什么showView总是仅仅显示一半。求解释╮(╯▽╰)╭


    回调中:

    [showView setAlpha:0.0f];

    将其临时隐藏。关上书时还要用它。


    关上书的动画大致类似

    #pragma mark - CYZBookViewDelegate
    
    - (void)readViewDidBackWithItem:(CYZBookItemView *)item
    {
        //取出showView
        UIImageView *showView = (UIImageView *)[self.view viewWithTag:1001];
        //将其显示出来
        showView.alpha = 1.0f;
        showView.layer.anchorPoint = CGPointMake(0, 0.5f);
        showView.frame = CGRectMake(0, 0, showView.width, showView.height);
        
        CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
        animation.keyPath = @"transform.rotation.y";
        animation.duration = 0.5f;
        animation.speed = 0.55f;
        animation.removedOnCompletion = NO;
        //反向旋转
        [animation setValues:[NSArray arrayWithObjects:@-M_PI_2, @0, nil]];
        animation.delegate = self;
        //设置不同的key为了区分动画用
        [showView.layer addAnimation:animation forKey:@"rotateToCloseBook"];
        
    }

    这里要用一个不同的key来表示这个动画。

    该动画的回调:

                [UIView animateWithDuration:0.5f animations:^{
                    showView.frame = _itemPosition;
                } completion:^(BOOL finished) {
                    [showView removeFromSuperview];
                }];

    _itemPosition是之前用来记录转换的坐标的私有变量,这几行代码的意思就是让showView回到书本的位置然后令其消失。

    这里的关键问题在于。两个动画都用到了回调,怎样区分呢?就用我们之前设置的key来区分:

    回调的完整代码:

    #pragma mark - AnimationDelegate
    
    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
    {
        UIImageView *showView = (UIImageView *)[self.view viewWithTag:1001];
        if (flag) {
            if (showView && [[showView.layer animationForKey:@"rotateToOpenBook"] isEqual:anim]) {
                [showView setAlpha:0.0f];
            } else if (showView && [anim isEqual:[showView.layer animationForKey:@"rotateToCloseBook"]]) {
                [UIView animateWithDuration:0.5f animations:^{
                    showView.frame = _itemPosition;
                } completion:^(BOOL finished) {
                    [showView removeFromSuperview];
                }];
            }
        }
    }
    通过showView所在层layer的方法 animationForKey:获得自己设置的动画,与代理中的anim做比較就可以区分。

    另外。在stackOverflow上还看到一种方法:用kvc的方法为animation设值,并在代理中通过kvc的方法依据这个键取出值并进行推断,应该也是能够的。


  • 相关阅读:
    sftp 使用笔记
    python-day001获取mac地址
    tomcat 修改端口
    mysql 封装与使用
    redis 封装使用
    centos7安装jenkins
    securecrt设置编码、字体、编码
    linux操作系统上路由管理维护
    ElasticSearch操作和使用指南
    sqlyog连接mysql错误码2058
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5360373.html
Copyright © 2011-2022 走看看