会说话的汤姆猫这个APP层级风靡一时,其UI部分就是利用了序列动画的技术, 接下来

我们用汤姆猫来演示怎么制作序列动画。

  [要求]:

    1、学会使用序列动画的方法

    2、学会分析动画播放中内存占用高的问题,并解决

  [实现]

    1、搭建UI界面

      1.1.设置模拟器的屏幕尺寸3.7,添加素材

        我们的素材文件是是按照3.7Inch的大小,设置屏幕大小为3.7Inch,添

      加动画的素材到工程。

      2.2.添加控件

        2.2.1.添加背景图片

          我们用ImageView控件来实现动画,首先添加一个UIViewImage控

        件到View,设置ImageView的Image属性为amgry_00.jpg,当然也可

        以选择图库里的其他图片。

        2.2.2.添加按钮

          添加一个UIButton到View,设置尺寸为60X60,因为我们的Butto

        的图片尺寸就是60X60的,然后设置Background的相应的图片,删除

        Title的文字,然后相同的方式创建其他按钮。我们要点击头部已经脚,同

        样的方法在头部和左右脚添加透明的按钮。完成后如下图所示

         

         2.2.3.建立连线,监听按钮点击事件

          下面为创建的6个图片按钮以及头部和脚的透明按钮建立连线用于监

        听按钮的点击。至此UI搭建的部分全部完成,接下来处理按钮点击后的动

        画播放。

                     

    2、实现序列动画的播放

      2.1.[动画原理]

        所谓的动画无非是把一些连续动作进行拆分成许多副图片,然后把这些图

      片快速连续的播放出来,快到人眼觉察不出这不是一副一副单独的图片的播放,

      而是一个连续的视频,其实最根本的是利用人眼的视觉暂留,人眼看到一个物体

      或者一副画会在至少会在人的意识中停留0.34秒,这样如果播放图片的时间间

      隔小于这个视觉暂留的时间的话会给人造成一种流畅的视觉变化的效果。

        知道了这个原理我们就可以实现利用序列的图片进行动画的演示了,把事

      先做好的动画图片按照顺序依次等时间间隔的加载的屏幕上显示就可以了。

 

      2.2.[代码实现]

        2.2.1.加载图片

          制作动画首先需要把响应的图片加载到内存中,我们创建一个动态数

        组,然后把图片数据一张一张的添加到图片数组中,下面以drink为例

        NSMutable *animationData = [[NSMutableArray alloc]init];

        for(index = 0; index < 80; index++) {

                NSString *picName = [NSString stringWithFormat:@"drink_02d.jpg",index];
                UIImage *imagePic = [UIImage imageNamed:picName];
        
                [animatinData addObject: imagePic];

        }

          //2.2.2、设置动画的持续时间
          self.tom.animationDuration = animatinData.count * 0.03;
    
          //2.2.3、设置动画的重复次数
          self.tom.animationRepeatCount = 1;
 
          //2.2.4、设置动画的图片内容
          self.tom.animationImages = animatinData;
    
           //2.2.5、启动动画播放
          [self.tom startAnimating];

          这样我们就完成了整个动画播放的代码流程当点击到播放按钮后可以实现

       固定动画的播放,然后按照这个流程依次实现所有的动画,这样就完成了。

- (IBAction)drink
{
    //1、加载图片数据到NSArry
    NSMutableArray *animatinData = [[NSMutableArray alloc]init];
    for (int index = 0; index < 80; index++) {
        NSString *picName = [NSString stringWithFormat:@"drink_02d.jpg",index];
        UIImage *imagePic = [UIImage imageNamed:picName];
        
        [animatinData addObject: imagePic];
        
    }

    //2、设置动画的持续时间
    self.tom.animationDuration = animatinData.count * 0.03;
    
    //3、设置动画的重复次数
    self.tom.animationRepeatCount = 1;
 
    //4、设置动画的图片内容
    self.tom.animationImages = animatinData;
    
    //5、启动动画播放
    [self.tom startAnimating];
}

 

     2.3.[代码优化] 

        2.2.1、代码复用   

            我们发现这个drink按钮点击事件处理的方法实现了动画的功能,但是和

        其他所有的按钮点击事件处理的代码几乎一样,只不过不同的是选择的素材不

        同,素材的张数不同,那么我们把这些相同的部分封装成方法,不同的部分作

        为参数传入以实现代码的复用,于是大大减少冗余的代码。

- (void)runAnimationWithCount: (int)count name:(NSString *)name
{
//1、加载图片数据到NSArry
    NSMutableArray *animatinData = [[NSMutableArray alloc]init];
    for (int index = 0; index < count; index++) {
        NSString *picName = [NSString stringWithFormat:@"%@_%02d.jpg",name,index];
        UIImage *imagePic = [UIImage imageNamed:picName];
        
        [animatinData addObject: imagePic];
        
    }

    //2、设置动画的持续时间
    self.tom.animationDuration = animatinData.count * 0.03;
    
    //3、设置动画的重复次数
    self.tom.animationRepeatCount = 1;
 
    //4、设置动画的图片内容
    self.tom.animationImages = animatinData;
    
    //5、启动动画播放
    [self.tom startAnimating];
}

 

- (IBAction)knock {
    [self runAnimationWithCount: 81 name: @"knockout"];
}

- (IBAction)footLeft {
    [self runAnimationWithCount: 30 name: @"footLeft"];
}

- (IBAction)footRight {
    [self runAnimationWithCount: 30 name: @"footRight"];
}

- (IBAction)eat {
    [self runAnimationWithCount: 40 name: @"eat"];
}

- (IBAction)pie {
    [self runAnimationWithCount: 24 name: @"pie"];
}

- (IBAction)scratch {
    [self runAnimationWithCount: 56 name: @"scratch"];
}

- (IBAction)fart {
    [self runAnimationWithCount: 28 name: @"fart"];
}

- (IBAction)cymbal {
    [self runAnimationWithCount: 13 name: @"cymbal"];
}

 

      2.2.2 排查动画覆盖

        有没有发现当前动画还没有播放完成的时候如果点击另一个播放按钮,当

      前播放的动画会被覆盖区执行另一个动画播放,那么接近这个问题很简单,只

      需要在按钮点击后检查有没有动画正在播放就可以了,一行代码搞定

       if(self.tom.isAnimating) return ;

  3、解决内存爆表

    下面我们启动模拟器开观察一下tom在运行过程中的内存使用情况。

    3.1 启动模拟器后观察

             

    3.2 点击drink按钮

             

    3.3 再次点击drink按钮

     

    3.4 点击knock

             

      3.5 点击其他

             

             

             

    3.6 内存分析

      3.6.1、模拟器启动后tom内存只有11.5M,点击drink后内存一路飙升100多M

        并且稍微有卡顿的感觉(我的是虚拟机)那么点击后加载动画内容到内存,

        播放完毕后动画内容并没有释放。

      3.6.2、再次点击drink,动画播放,没有卡顿的感觉,内存无变化。那么说明第

        二次点击drink实际并没有再次读取动画内容到内存,而是使用的第一次加载

        的动画内存数据。没有卡顿说明,和占用内存没有增加证明了这一点。

        结论:动画应该是加载到缓存。以后相同的数据都使用这块内存区域。缓存

          不会自动释放。

       从上图的数据来看播放几个动画后内存飙升到800M,非常严重的问题。那么接

      下来我们需要解决这个问题。

    3.7 内存问题解决

        从上面的分析中我们加载了动画数据到内存后并不释放,我们需要做的就是

      在动画播放完毕后来释放这块内存。

        在加载图片的部分我们用的是imageName这个方法来读取的图片,这个方法

      会把图片加载到缓存,其实还有一个方法 imageWithContentsOfFile 来代替。

      这个方法不会创建缓存并且会释放。

      

        改进后代码:

      

        测试:

        1、启动后内存占用情况

           

        2、点击不同播放按钮后内存使用情况

            

                         

                         

                         

        3、分析

           通过上面的图可以看出改进后的代码对内存的占用情况有了很大的改

         善。多次播放动画后内存没有想要的叠加,取代的是更新,点击播放时

           会会先释放覆盖上一次的动画内存,然后加载当前的动画数据到内存。

         我们所看到的内存占用情况是最后一次动画播放完成后所占用的内存。

           虽然有很大的改观,单是仍然有问题,问题是最后一次动画加载到内存

        后播放完成后内存不释放,直到下一次点击按钮。那么我们应该在动画播放

        完成后来手动释放占用的内存区域。

        4、手动释放内存

                       

                                                                              

                                                            【全文完】

 

 

 posted on 2015-08-13 12:26  ~疯子~  阅读(590)  评论(0编辑  收藏  举报