用 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() % )) / 2000.0f;
destination.y = -50.0f * ((CGFloat)(random() % )) / 2000.0f;
} else if((x > (kXSlices / 2.0f)) && (y <= (kYSlices / 2.0f))) { // top right quadrant
destination.x = size.width + (50.0f * ((CGFloat)(random() % )) / 2000.0f);
destination.y = -50.0f * ((CGFloat)(random() % )) / 2000.0f;
} else if((x > (kXSlices / 2.0f)) && (y > (kYSlices / 2.0f))) { // bottom right quadrant
destination.x = size.width + (50.0f * ((CGFloat)(random() % )) / 2000.0f);
destination.y = size.height + (50.0f * ((CGFloat)(random() % )) / 2000.0f);
} else if((x <= (kXSlices / 2.0f)) && (y > (kYSlices / 2.0f))) { // bottom right quadrant
destination.x = -50.0f * ((CGFloat)(random() % )) / 2000.0f;
destination.y = size.height + (50.0f * ((CGFloat)(random() % )) / 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 = ;x < kXSlices;x++) {
for(int y = ;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, , , 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

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

  1. Core Animation编程指南

    本文是<Core Animation Programming Guide>2013-01-28更新版本的译文.本文略去了原文中关于OS X平台上Core Animation相关内容.因为原 ...

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

    前一篇总结了Core Animation的一些基础知识,这一篇主要是Core Animation 的一些应用,涉及到CAShapeLayer.CAReplicatorLayer等图层的知识. 先看效果 ...

  3. 图片碎片化mask动画

    图片碎片化mask动画 效果 源码 https://github.com/YouXianMing/Animations // // TransformFadeViewController.m // A ...

  4. iOS——Core Animation 知识摘抄(四)

    原文地址http://www.cocoachina.com/ios/20150106/10840.html 延迟解压 一旦图片文件被加载就必须要进行解码,解码过程是一个相当复杂的任务,需要消耗非常长的 ...

  5. iOS Instruments之Core Animation动画性能调优(工具复选框选项介绍)

    Core Animation工具用来监测Core Animation性能.它给我们提供了周期性的FPS,并且考虑到了发生在程序之外的动画(见图12.4) Core Animation工具提供了一系列复 ...

  6. instrument 之 core animation

    1.Color Blended Layers 图层混合 需要消耗一定的GPU资源,避免设置alpha小于1,省去不必要的运算 2.Color Hits Green and Misses Red 光栅化 ...

  7. Core Animation学习总结

    文件夹: The Layer Beneath The Layer Tree(图层树) The Backing Image(寄宿层) Layer Geometry(图层几何学) Visual Effec ...

  8. Instruments学习之Core Animation学习

    当App发展到一定的规模,性能优化就成为必不可少的一点.但是很多人,又对性能优化很陌生,毕竟平常大多时间都在写业务逻辑,很少关注这个.最近在优化自己的项目,也收集了很多资料,这里先浅谈一下使用Inst ...

  9. 一、Instrument之Core Animation工具

    一.Instrument 三个方法: (1).按下Command + I打开Instrument; (2).Xcode->product->profile; (3).Xcode->O ...

随机推荐

  1. 剑指offer62:二插搜索树的第k个节点

    题目描述: 给定一颗二叉搜索树,请找出其中的第k大的结点.例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4. 中序遍历 /* struct TreeNo ...

  2. mysql中难以理解的sql

    工作中遇到这样的例子, CASE type WHEN 1 THEN '普通红包' WHEN 2 THEN '普通礼包加油卡' WHEN 3 THEN '优 惠码兑换加油卡' WHEN 4 THEN ' ...

  3. OOAD之单例模式Singleton的6种写法

    1  主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 一 :第一种 饿汉式(预加载) public class Singleton { private Singleton(){ ...

  4. form表单select的选项值选择

    html: <form action=""> <p>选择城市</p> <p> <select name="" ...

  5. vuex中怎么把‘库’中的状态对象赋值给内部对象(三种方法)

    一.通过computed的计算属性直接赋值 import store from '@/store/store' export default{ name: 'count', data(){ retur ...

  6. MySQL常用命令操作

    1. 命令行登录使用默认3306端口的MySQL: mysql -u root -p 2. 通过TCP连接管理不同端口的多个MySQL(注意:MySQL4.1以上版本才有此项功能): mysql -u ...

  7. c#调用webservices

    有两种方式,静态调用(添加web服务的暂且这样定义)和动态调用: 静态调用: 使用添加web服务的方式支持各种参数,由于vs2010会自动转换,会生成一个特定的Reference.cs类文件   动态 ...

  8. MVC初级知识之——Routing路由

    实例产品基于asp.net mvc 5.0框架,源码下载地址:http://www.jinhusns.com/Products/Download 我们注意到地址栏的URL是Home/Index 路由可 ...

  9. emberjs 按年月分组

    一个集合,里面有年和月的属性,按照年和月进行分组显示数据 + item.TopicMonth }).map(function (value, key) { return { time: { year: ...

  10. 不用中间变量,交换a、b值

    如果要交换a.b之间的值,一般的做法是: tmp=a;a=b;b=tmp;这种方法不得不使用一个临时变量. 从网上学来一个方法,可以不用使用临时变量: a^=b^=a^=b; 这样计算之后,就可以交换 ...