UIDynamicAnimator 结合 CollectionViewControllerLayout——方法 |
05 View ▸ day10 ▸ Demo1_CollectionView_Dynamic
1. UIDynamicAnimator 结合 CollectionViewControllerLayout
WWDC2013 Session
[Demo1]
UICollectionViewLayout 是抽象类, 继承此类需要在子类中做大量的工作(覆盖大量的方法)
UICollectionViewFlowLayout 是UICollectionViewLayout类的子类,是一个具体的实现类,提供流式的布局管理。如果继承此类,我们只需要覆盖掉我们自己需要的方法
2. 模糊效果
iOS7大量效果的设计
UIImage+ImageEffects类
3. MotionEffects效果
UIMotionEffect类是抽象类,是所有MotionEffect特效类的父类
UIInterpolatingMotionEffect 是他的一个常见的子类
UIMotionEffectGroup 也是他的一个子类,此类可以将多个特效对象合并成一个特效对象,然后加入到视图上
WWDC2013 Session
[Demo1]
UICollectionViewLayout 是抽象类, 继承此类需要在子类中做大量的工作(覆盖大量的方法)
UICollectionViewFlowLayout 是UICollectionViewLayout类的子类,是一个具体的实现类,提供流式的布局管理。如果继承此类,我们只需要覆盖掉我们自己需要的方法
2. 模糊效果
iOS7大量效果的设计
UIImage+ImageEffects类
3. MotionEffects效果
UIMotionEffect类是抽象类,是所有MotionEffect特效类的父类
UIInterpolatingMotionEffect 是他的一个常见的子类
UIMotionEffectGroup 也是他的一个子类,此类可以将多个特效对象合并成一个特效对象,然后加入到视图上
UIDynamicAnimator 结合 CollectionViewControllerLayout——使用Map |
纯代码:
1.在ViewDidLoad中
//
创建
collectionView 指定大小且自定义布局
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
2.new一个自定义类,TRCollectionViewSpringCellLayout继承自
UICollectionViewFlowLayout
3.在ViewDidLoad中
//
创建布局
TRCollectionViewSpringCellLayout *layout = [[TRCollectionViewSpringCellLayout alloc]init];
4.添加到view
[
self
.
view
addSubview
:collectionView];
5.设置数据源,遵守协议
<
UICollectionViewDataSource
>,回答问题
定义:static
NSString
*cellIdentifier =
@"MyCell"
;
在ViewDidLoad中
//
设置数据源
collectionView.dataSource = self;
//
注册cell
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];
//
遵守了协议,回答
3
个问题(分区,行,数据)
- ( NSInteger )collectionView:( UICollectionView *)collectionView numberOfItemsInSection:( NSInteger )section
{
return 50 ;
}
- ( UICollectionViewCell *)collectionView:( UICollectionView *)collectionView cellForItemAtIndexPath:( NSIndexPath *)indexPath
- ( NSInteger )collectionView:( UICollectionView *)collectionView numberOfItemsInSection:( NSInteger )section
{
return 50 ;
}
- ( UICollectionViewCell *)collectionView:( UICollectionView *)collectionView cellForItemAtIndexPath:( NSIndexPath *)indexPath
{
//
拿到
cell
UICollectionViewCell
*cell = [collectionView
dequeueReusableCellWithReuseIdentifier
:
cellIdentifier
forIndexPath
:indexPath];
//[UIColor randomColor] 随机颜色 因为没有这个方法,我们要创建一个RandomColor类继承自UIColor
cell.
backgroundColor
= [
UIColor
randomColor
];
return cell;
return cell;
}
6.给类加方法Objective-C category
[
--------实现随机有2种方式,一种:添加UIColor类方法(分类:可以给某一个类扩充一些方法),一种直接实现方法--------
方法一(xcode6)添加分类:
方法二:
]
声明(公有):
+ (
UIColor
*)randomColor;
实现:
+ (
UIColor
*)randomColor
{
{
CGFloat
red =
arc4random
() %
256
/
255.0
;
CGFloat green = arc4random () % 256 / 255.0 ;
CGFloat blue = arc4random () % 256 / 255.0 ;
CGFloat green = arc4random () % 256 / 255.0 ;
CGFloat blue = arc4random () % 256 / 255.0 ;
return [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
}
7.可以设置布局的属性
layout.
itemSize
=
CGSizeMake
(
300
,
40
);//宽度 高度
layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);
8.此时翻的时候有滚动条,我们可以把它关闭
//
关闭滚动条
collectionView. showsVerticalScrollIndicator = NO ;
collectionView. showsVerticalScrollIndicator = NO ;
collectionView.showsHorizontalScrollIndicator = NO;
接下来就要设置动画效果
9.定义私有的动画属性
@interface
TRCollectionViewSpringCellLayout
()
@property ( strong , nonatomic ) UIDynamicAnimator *animator;
@property ( strong , nonatomic ) UIDynamicAnimator *animator;
@end
10.实现(给每个cell添加一个
AttachmentBehavior[吸附行为]
)
//
布局前的准备,布局开始前自动调用
- ( void )prepareLayout
{
// 给每个一 Cell 创建 UIAttachmentBehavior( 吸附行为 )
if (! self . animator ){
//UIDynamicAnimator 专门针对 CollectionView 布局的方法
self . animator = [[ UIDynamicAnimator alloc ] initWithCollectionViewLayout : self ];
// 总共内容的大小(所有的 cell )
CGSize contentSize = [ self collectionViewContentSize ];
//[super layoutAttributesForElementsInRect : ..] 拿到一个 Rect 范围内的所有的 cell 的布局属性
NSArray *items = [ super layoutAttributesForElementsInRect : CGRectMake ( 0 , 0 , contentSize. width , contentSize. height )];
// 遍历
for ( UICollectionViewLayoutAttributes *attributes in items) {
// 创建吸附行为
UIAttachmentBehavior *spring = [[ UIAttachmentBehavior alloc ] initWithItem :attributes attachedToAnchor :attributes. center ];
spring. damping = 0.6 ; // 阻尼
spring. frequency = 0.8 ; // 频率
[ self . animator addBehavior :spring];
}
}
- ( void )prepareLayout
{
// 给每个一 Cell 创建 UIAttachmentBehavior( 吸附行为 )
if (! self . animator ){
//UIDynamicAnimator 专门针对 CollectionView 布局的方法
self . animator = [[ UIDynamicAnimator alloc ] initWithCollectionViewLayout : self ];
// 总共内容的大小(所有的 cell )
CGSize contentSize = [ self collectionViewContentSize ];
//[super layoutAttributesForElementsInRect : ..] 拿到一个 Rect 范围内的所有的 cell 的布局属性
NSArray *items = [ super layoutAttributesForElementsInRect : CGRectMake ( 0 , 0 , contentSize. width , contentSize. height )];
// 遍历
for ( UICollectionViewLayoutAttributes *attributes in items) {
// 创建吸附行为
UIAttachmentBehavior *spring = [[ UIAttachmentBehavior alloc ] initWithItem :attributes attachedToAnchor :attributes. center ];
spring. damping = 0.6 ; // 阻尼
spring. frequency = 0.8 ; // 频率
[ self . animator addBehavior :spring];
}
}
}
11.覆盖布局
//
返回在
rect
范围内的布局属性
- ( NSArray *)layoutAttributesForElementsInRect:( CGRect )rect
{
// 返回每个 Cell 的布局属性
return [ self . animator itemsInRect :rect];
}
// 专门针对 UICollectionViewLayout ,第几个区的第几个 item (每个 cell 的布局)
- ( UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:( NSIndexPath *)indexPath
{
return [ self . animator layoutAttributesForCellAtIndexPath :indexPath];
- ( NSArray *)layoutAttributesForElementsInRect:( CGRect )rect
{
// 返回每个 Cell 的布局属性
return [ self . animator itemsInRect :rect];
}
// 专门针对 UICollectionViewLayout ,第几个区的第几个 item (每个 cell 的布局)
- ( UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:( NSIndexPath *)indexPath
{
return [ self . animator layoutAttributesForCellAtIndexPath :indexPath];
}
12.达到弹簧效果
//
当
bounds
发生变化时
,
调用方法
,
为不同的
Cell
改变不同的锚点
- ( BOOL )shouldInvalidateLayoutForBoundsChange:( CGRect )newBounds
{
// 拿出 collectionView
UIScrollView *scrollView = self . collectionView ;
// 获取滚动的距离
CGFloat scrollDelta = newBounds. origin . y - scrollView. bounds . origin . y ;
// 手指所在的位置
CGPoint touchLocation = [scrollView. panGestureRecognizer locationInView :scrollView];
// 计算和改动每一个 Cell 的锚点
// 遍历所有的行为
for ( UIAttachmentBehavior *spring in self . animator . behaviors ) {
// 到 Attributes 里 Behavior 去拿绑定的 item
UICollectionViewLayoutAttributes *item = [spring. items firstObject ];
// 拿出中心点
CGPoint center = item. center ;
// 拿到 spring 的锚点
CGPoint anchorPoint = spring. anchorPoint ;
// 拿到距离 (用户点击的位置 - 锚点)
CGFloat distance = fabsf (touchLocation. y - anchorPoint. y );
// 阻力值
CGFloat scrollResistance = distance / 800 ;
// 滚动距离 >0?( 距离,距离 * 阻力值 当中取一个最小值 )
center. y += (scrollDelta> 0 )? MIN (scrollDelta, scrollDelta * scrollResistance): MAX (scrollDelta, scrollDelta * scrollResistance);
// 把中心点赋值回去
item. center = center;
// 当 item 处于动画中时 , 如果对象主动修改了位置信息, 需要更新动画
[ self . animator updateItemUsingCurrentState :item];
}
return NO ; // 要不要重新计算边界
- ( BOOL )shouldInvalidateLayoutForBoundsChange:( CGRect )newBounds
{
// 拿出 collectionView
UIScrollView *scrollView = self . collectionView ;
// 获取滚动的距离
CGFloat scrollDelta = newBounds. origin . y - scrollView. bounds . origin . y ;
// 手指所在的位置
CGPoint touchLocation = [scrollView. panGestureRecognizer locationInView :scrollView];
// 计算和改动每一个 Cell 的锚点
// 遍历所有的行为
for ( UIAttachmentBehavior *spring in self . animator . behaviors ) {
// 到 Attributes 里 Behavior 去拿绑定的 item
UICollectionViewLayoutAttributes *item = [spring. items firstObject ];
// 拿出中心点
CGPoint center = item. center ;
// 拿到 spring 的锚点
CGPoint anchorPoint = spring. anchorPoint ;
// 拿到距离 (用户点击的位置 - 锚点)
CGFloat distance = fabsf (touchLocation. y - anchorPoint. y );
// 阻力值
CGFloat scrollResistance = distance / 800 ;
// 滚动距离 >0?( 距离,距离 * 阻力值 当中取一个最小值 )
center. y += (scrollDelta> 0 )? MIN (scrollDelta, scrollDelta * scrollResistance): MAX (scrollDelta, scrollDelta * scrollResistance);
// 把中心点赋值回去
item. center = center;
// 当 item 处于动画中时 , 如果对象主动修改了位置信息, 需要更新动画
[ self . animator updateItemUsingCurrentState :item];
}
return NO ; // 要不要重新计算边界
}