---恢复内容开始---html
闲篇 最近升级了下百度音乐,惟一的感受就是动画效果很炫丽。我不是个对产品很敏感的人,可是这段时间观察一些大厂的产品发现如今的APP愈来愈重视动画效果了。你们可能没有注意过,连支付宝的一个很边缘很边缘的小角落(“财富 ->芝麻信用分 ->信用猜猜”)动画也是很炫的。随着手机硬件的加强以及广大苦逼程序员的不懈努力与钻研,APP的会愈来愈强调交互性,物理效果(UIDynamic)和动画效果(CoreAnimation)会愈来愈受欢迎。程序员
准备 好吧,闲话不说了,首先跟你们坦白一下,今天的内容会涉及到图形学知识,可是个人图形学知识都彻底还给老师了,因此!你懂得~ 关于矩阵的知识我可能说的不清楚。你们能够到网上找一下相关的博客,不少人写的仍是很好的。 数组
开始 首先为了能让你们更好的了解整个项目,先给你们先简单介绍一下各个类。具体的代码会在下文介绍。我图简便用的是故事板(storyboard)拖的一个collectionView控制器,并将整个控制器的类指定为CollectionViewController。又创建一个自定义布局类继承自UICollectionViewFlowLayout类。dom
#import "CollectionViewController.h" @implementation CollectionViewController static NSString * const reuseIdentifier = @"Cell"; - (void)viewDidLoad { [super viewDidLoad]; //补充一下:与tableView 不一样,collectionView和view不适同一个对象。tableView 和view是同一个对象 self.collectionView.backgroundColor=[UIColor whiteColor]; [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier]; } #pragma mark <UICollectionViewDataSource> - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 1; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 100; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; //把cell 设置为稍微有点圆角,能好看一点 cell.layer.cornerRadius=4; cell.layer.masksToBounds=YES; //随机颜色 cell.backgroundColor=[UIColor colorWithRed:(arc4random()%255)/(1.0*255) green:(arc4random()%255)/(1.0*255) blue:(arc4random()%255)/(1.0*255) alpha:1]; return cell; }
下面主要来看一下布局类,以及布局类的打印信息。经过打印信息咱们能够知道各个方法的调用顺序,了解调用顺序对开发相当重要。咱们先来看一下打印信息:布局
2015-05-19 00:32:07.460 翻页效果[13957:392865] prepareLayoutpost
2015-05-19 00:32:07.461 翻页效果[13957:392865] layoutAttributesForElementsInRect动画
2015-05-19 00:32:08.530 翻页效果[13957:392865] shouldInvalidateLayoutForBoundsChangespa
2015-05-19 00:32:08.531 翻页效果[13957:392865] prepareLayoutcode
2015-05-19 00:32:08.531 翻页效果[13957:392865] layoutAttributesForElementsInRectorm
2015-05-19 00:32:08.553 翻页效果[13957:392865] shouldInvalidateLayoutForBoundsChange
而后咱们再来看一下layout 方法,layout方法我加了详细的注释,方便你们阅读。
//并非一会儿所有都返回出来 而是逐渐的提供 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSLog(@"layoutAttributesForElementsInRect"); //首先将系统的特征数组取出 NSArray *attrs=[super layoutAttributesForElementsInRect:rect]; //这两个数据下面会用到,用到再解释 CGFloat halfW=self.collectionView.bounds.size.width/2; CGFloat orx=self.collectionView.contentOffset.x; //将此次提供的特征数组 一个一个的将特征取出来进行社会主义大改造 for (UICollectionViewLayoutAttributes *attr in attrs) { //计算attr中心的距离可视中心的距离 CGFloat distance=(orx+halfW)-CGRectGetMidX(attr.frame); //这里就是用到了上面定义个数据,计算出一个比例,好供咱们再下面进行计算,离屏幕中心越远越大 CGFloat scale=distance/halfW; //也就是说这个 item 的身体至少一半在屏幕内时咱们才去改变它的布局特征 if (scale<=1) { //计算各个attr 的M34 什么事m34? 它是transform3D的一个属性 // m11 (X 缩放) m12 (Y 切变) m13 ( ) m14 ( ) // m21 (X 切变) m22(Y 缩放) m23 ( ) m24 ( ) // m33 ( ) m32 ( ) m33 ( ) m34 (最重要的M34 具备一种倾斜效果,有正负之分方向不一样) // m41 (X 平移) m42 (Y 平移) m43 (Z 平移) m44 ( ) //建立一个单位矩阵 CATransform3D rotationTrans=CATransform3DIdentity; //单位矩阵的M34 改成-0.004 数字你们以为合适便可 rotationTrans.m34=-0.004; //计算各个attr 的y轴旋转角度 根据比例来计算,离屏幕中心越远旋转角度越大 这里表示绕Y轴旋转 rotationTrans=CATransform3DRotate(rotationTrans, M_PI_4*(scale), 0.0, 1, 0.0); // 计算各个attr的缩放 CGFloat factor =0.3; CGFloat zoom=1+factor-ABS(scale)*factor;//控制再1~1.2倍 CATransform3D zoomTrans=CATransform3DMakeScale(zoom, zoom, 1.0); //拟合各个trans attr.transform3D=CATransform3DConcat(rotationTrans, zoomTrans); //计算各个attr 的透明度 CGFloat alp=1+0.1-ABS(scale); alp>1?(attr.alpha=1):(attr.alpha=alp); } else { attr.alpha=0; } } return attrs; }