用 Core Animation 实现图片的碎片化

用 Core Animation 实现图片的碎片化

参考书籍:

 

效果如下:

原理其实非常简单哦:)。

1. 创建一个CALayer,使用其 contents 属性来装载一张图片(获取图片的CGImage)

2. 根据frame值裁剪图片,然后将裁剪的图片赋给你创建的更小的CALayer

3. 实现这些更小的CALayer的动画

4. 剩下的该干嘛干嘛,比如使用 Core Image 滤镜什么的,就靠你创造了:)

 

 

 

核心代码:

 

源码(书中提供,并非本人所写):

/***
 * Excerpted from "Core Animation for Mac OS X and the iPhone",
 * published by The Pragmatic Bookshelf.
 * Copyrights apply to this code. It may not be used to create training material,
 * courses, books, articles, and the like. Contact us if you are in doubt.
 * We make no guarantees that this code is fit for any purpose.
 * Visit http://www.pragmaticprogrammer.com/titles/bdcora for more book information.
***/
//
//  RootController.m
//  Confetti
//
//  Created by Bill Dudney on 5/21/08.
//  Copyright 2008 Gala Factory. All rights reserved.
//

#import "RootController.h"
#import <QuartzCore/QuartzCore.h>

// location of layer to start
static CGFloat kMaxWidth = 300.0f;
static CGFloat kMaxHeight = 380.0f;
static CGFloat kMinX = 10.0f;
static CGFloat kMinY = 20.0f;
static CGFloat kXSlices = 6.0f;
static CGFloat kYSlices = 8.0f;

@implementation RootController

@synthesize image;
@synthesize imageLayer;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
    self.title = @"Confetti";
    }
    return self;
}

- (void)loadView {
  [super loadView];

  self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Pop" style:UIBarButtonItemStyleBordered target:self action:@selector(pop:)] autorelease];
  self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(photo:)] autorelease];

  self.imageLayer = [CALayer layer];
  self.imageLayer.frame = CGRectMake(kMinX, kMinY, kMaxWidth, kMaxHeight);
  self.imageLayer.contentsGravity = kCAGravityResizeAspectFill;
  self.imageLayer.masksToBounds = YES;
  [self.view.layer addSublayer:self.imageLayer];
}

- (void)photo:(id)sender {
  if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
    UIImagePickerController* picker = [[UIImagePickerController alloc] init];
    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    picker.delegate = self;
    picker.allowsImageEditing = NO;
    // Picker is displayed asynchronously.
    [self presentModalViewController:picker animated:YES];
  } else {
    // pop up an alert
  }
}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
  imageLayer.contents = (id)drawnImage;
  // remove all sublayers from imageLayer
  NSArray *sublayers = [NSArray arrayWithArray:[imageLayer sublayers]];
  for(CALayer *layer in sublayers) {
    [layer removeFromSuperlayer];
  }
}

- (CGPoint)randomDestinationX:(CGFloat)x Y:(CGFloat)y imageSize:(CGSize)size {
  CGPoint destination;
  if((x <= (kXSlices / 2.0f)) && (y <= (kYSlices / 2.0f))) { // top left quadrant
    destination.x = -50.0f * ((CGFloat)(random() % 10000)) / 2000.0f;
    destination.y = -50.0f * ((CGFloat)(random() % 10000)) / 2000.0f;
  } else if((x > (kXSlices / 2.0f)) && (y <= (kYSlices / 2.0f))) { // top right quadrant
    destination.x = size.width + (50.0f * ((CGFloat)(random() % 10000)) / 2000.0f);
    destination.y = -50.0f * ((CGFloat)(random() % 10000)) / 2000.0f;
  } else if((x > (kXSlices / 2.0f)) && (y > (kYSlices / 2.0f))) { // bottom right quadrant
    destination.x = size.width + (50.0f * ((CGFloat)(random() % 10000)) / 2000.0f);
    destination.y = size.height + (50.0f * ((CGFloat)(random() % 10000)) / 2000.0f);
  } else if((x <= (kXSlices / 2.0f)) && (y > (kYSlices / 2.0f))) { // bottom right quadrant
    destination.x = -50.0f * ((CGFloat)(random() % 10000)) / 2000.0f;
    destination.y = size.height + (50.0f * ((CGFloat)(random() % 10000)) / 2000.0f);
  }
  return destination;
}

- (CAAnimation *)animationForX:(NSInteger)x Y:(NSInteger)y
                     imageSize:(CGSize)size {
  // return a group animation, one for opacity from 1 to zero and a keyframe
  // with a path appropriate for the x and y coords
  CAAnimationGroup *group = [CAAnimationGroup animation];
  group.delegate = self;
  group.duration = 2.0f;

  CABasicAnimation *opacity = [CABasicAnimation
                               animationWithKeyPath:@"opacity"];
  opacity.fromValue = [NSNumber numberWithDouble:1.0f];
  opacity.toValue = [NSNumber numberWithDouble:0.0f];

  CABasicAnimation *position = [CABasicAnimation
                                animationWithKeyPath:@"position"];
  position.timingFunction = [CAMediaTimingFunction
                             functionWithName:kCAMediaTimingFunctionEaseIn];
  CGPoint dest = [self randomDestinationX:x Y:y imageSize:size];
  position.toValue = [NSValue valueWithCGPoint:dest];

  group.animations = [NSArray arrayWithObjects:opacity, position, nil];
  return group;
}

- (void)pop:(id)sender {
  if(nil != imageLayer.contents) {
    CGSize imageSize = CGSizeMake(CGImageGetWidth(drawnImage),
                                  CGImageGetHeight(drawnImage));
    NSMutableArray *layers = [NSMutableArray array];
    for(int x = 0;x < kXSlices;x++) {
      for(int y = 0;y < kYSlices;y++) {
        CGRect frame = CGRectMake((imageSize.width / kXSlices) * x,
                                  (imageSize.height / kYSlices) * y,
                                  imageSize.width / kXSlices,
                                  imageSize.height / kYSlices);
        CALayer *layer = [CALayer layer];
        layer.frame = frame;
        layer.actions = [NSDictionary dictionaryWithObject:
                         [self animationForX:x Y:y imageSize:imageSize]
                                                    forKey:@"opacity"];
        CGImageRef subimage = CGImageCreateWithImageInRect(drawnImage, frame);
        layer.contents = (id)subimage;
        CFRelease(subimage);
        [layers addObject:layer];
      }
    }
    for(CALayer *layer in layers) {
      [imageLayer addSublayer:layer];
      layer.opacity = 0.0f;
    }
    imageLayer.contents = nil;
  }
}

- (CGImageRef)scaleAndCropImage:(UIImage *)fullImage {
  CGSize imageSize = fullImage.size;
  CGFloat scale = 1.0f;
  CGImageRef subimage = NULL;
  if(imageSize.width > imageSize.height) {
    // image height is smallest
    scale = kMaxHeight / imageSize.height;
    CGFloat offsetX = ((scale * imageSize.width - kMaxWidth) / 2.0f) / scale;
    CGRect subRect = CGRectMake(offsetX, 0.0f,
                                imageSize.width - (2.0f * offsetX),
                                imageSize.height);
    subimage = CGImageCreateWithImageInRect([fullImage CGImage], subRect);
  } else {
    // image width is smallest
    scale = kMaxWidth / imageSize.width;
    CGFloat offsetY = ((scale * imageSize.height - kMaxHeight) / 2.0f) / scale;
    CGRect subRect = CGRectMake(0.0f, offsetY, imageSize.width,
                                imageSize.height - (2.0f * offsetY));
    subimage = CGImageCreateWithImageInRect([fullImage CGImage], subRect);
  }
  // scale the image
  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  CGContextRef context = CGBitmapContextCreate(NULL, kMaxWidth,
                                               kMaxHeight, 8, 0, colorSpace,
                                               kCGImageAlphaPremultipliedFirst);
  CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
  CGRect rect = CGRectMake(0.0f, 0.0f, kMaxWidth, kMaxHeight);
  CGContextDrawImage(context, rect, subimage);
  CGContextFlush(context);
  // get the scaled image
  CGImageRef scaledImage = CGBitmapContextCreateImage(context);
  CGContextRelease (context);
  CGImageRelease(subimage);
  subimage = NULL;
  subimage = scaledImage;
  return subimage;
}

- (void)imagePickerController:(UIImagePickerController *)picker
        didFinishPickingImage:(UIImage *)newImage
                  editingInfo:(NSDictionary *)editingInfo {
  self.image = newImage;
  drawnImage = [self scaleAndCropImage:self.image];
  imageLayer.contents = (id)drawnImage;
  [[picker parentViewController] dismissModalViewControllerAnimated:YES];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
  [[picker parentViewController] dismissModalViewControllerAnimated:YES];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)dealloc {
    [super dealloc];
}

@end
时间: 2024-12-03 12:00:23

用 Core Animation 实现图片的碎片化的相关文章

图片碎片化mask动画

图片碎片化mask动画   效果   源码 https://github.com/YouXianMing/Animations // // TransformFadeViewController.m // Animations // // Created by YouXianMing on 15/11/17. // Copyright 2015年 YouXianMing. All rights reserved. // #import "TransformFadeViewController.h

Core Animation一些Demo总结 (动态切换图片、大转盘、图片折叠、进度条等动画效果)_Android

前一篇总结了Core Animation的一些基础知识,这一篇主要是Core Animation 的一些应用,涉及到CAShapeLayer.CAReplicatorLayer等图层的知识. 先看效果图: 1.切换图片: 2.彩票转盘 3.图片折叠 4.进度条旋转 5.粒子效果 一.切换图片 看起来很复杂的动画,通过少量的计算和编码就可以简单的实现.要做到这一步,必须是需要研究iOS开发中的Core Animation和Core Graphics框架的.日常工作中,对于很多东西不求甚解,只是拿过

iOS开发之核心动画(Core Animation)

1.概述 Core Animation是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍,使用它需要先添加QuartzCore.framework和引入对应的框架<QuartzCore/QuartzCore.h>. 特别注意的是核心动画的动画效果只是"假象",产生动画的那个view实际上并未发生任何变化. 开发步骤: 第一步:初始化一个动画对象(CAAnimation)并设置一些动画相关属性. 第二步:添加动画对象到层(CALayer)中,开

IOS开发UI篇--IOS动画(Core Animation)总结

一.简介 IOS 动画主要是指Core Animation框架.官方使用文档地址为:Core Animation Guide. Core Animation是IOS和OS X平台上负责图形渲染与动画的基础框架.Core Animation可以作用与动画视图或者其他可视元素,为你完成了动画所需的大部分绘帧工作.你只需要配置少量的动画参数(如开始点的位置和结束点的位置)即可使用Core Animation的动画效果.Core Animation将大部分实际的绘图任务交给了图形硬件来处理,图形硬件会加

IOS动画(Core Animation)总结

一.简介 IOS 动画主要是指Core Animation框架.官方使用文档地址为:Core Animation Guide. Core Animation是IOS和OS X平台上负责图形渲染与动画的基础框架.Core Animation可以作用与动画视图或者其他可视元素,为你完成了动画所需的大部分绘帧工作.你只需要配置少量的动画参数(如开始点的位置和结束点的位置)即可使用Core Animation的动画效果.Core Animation将大部分实际的绘图任务交给了图形硬件来处理,图形硬件会加

和菜头:在碎片化的轰炸中喘息

博客.微博.微信,我们在数字化时代迎来了信息的大爆炸,也迎来了信息的碎片化.一条信息被140个字的微博翻新.重组.恶搞,最终就被"翻译"成一条又一条的段子. @和菜头 就为此宣布"准备停止微博一段时间",并撰文戏称"碎片化阅读对我的大脑有所损伤". 碎片化生存 --和菜头在其博文中提到"现在这世界基本上已经是一个由信息碎片所构成的大型显示屏,完整的信息已经非常少见." 微博带来的是什么 微博要求一个人迅速在各种信息之间跳转,不

如何在信息碎片化下生存

随着科技的进步以及时代的快速发展,数字化时代迎来了信息的大爆炸,博客.微博.微信都是当前最热门的信息聚集地.不过与此同时,也迎来了信息的碎片化.一条信息被140个字的微博翻新.重组.恶搞,之后就被"翻译"成为一条又一条的段子. 碎片化生存 现在这世界基本上已经是一个由信息碎片所构成的大型显示屏,完整的信息已经不多了." 微博要求一个人迅速在各种信息之间跳转,不要在任意一条信息上停留过多时间.又要求一个人尽可能快地消费一条信息,迅速咬住它,吸干其中的汁液,然后一口吐掉.最后,对

旅行碎片化的再组织

随着各类垂直社交如雨后春笋般涌现,旅游类社交网站也呈现出了蓬勃发展的势头.而SNS为这个传统行业注入了新的活力,从传统的论坛模式转型成为新型的旅游社区.和以往更多地是被动放接受旅游机构形形色色的宣传信息比起来,社交网络为人们提供了获取更加真实的旅游信息的方式,而通过网友们真实地晒自己在旅途中的见闻,从而让网友们更真实的了解到当地的风土人情,更加的真切可信.而来自亲朋好友的评价肯定比陌生人的更具有说服力,所以一条来自好友的好评胜过别人的千言万语. 而旅游,其实与"移动"密切相关,移动互联

IOS实现碎片化动画详解_IOS

碎片化效果图 遮罩视图 在UIView中有一个maskView属性,这个属性是我们今天实现动画的最重要的变量.这个属性在iOS8之后开始使用,用来表示视图的遮罩.什么是遮罩呢?我想了很久都没有找到合适的比喻来介绍这个.简单来说,一个UIView的对象,可以通过设置alpha来改变这个视图的透明度,遮罩的实现效果也是一样的.唯一的差别在于前者是通过修改0~1之间的值来改变透明效果,作为遮罩的视图对象的backgroundColor.alpha.transform等等属性都会影响到被遮盖的视图的透明