iOS6新特征:UICollectionView高级使用示例之CircleLayout

时间:2024-11-07 15:38:12
AppDelegate介绍
在AppDelegate的方法didFinishLaunchingWithOptions中,创建一个ViewController,注意:此处的ViewController是继承自UICollectionViewController,在此需要给ViewController传递一个Layout,此处传递了CircleLayout的一个对象实例。这是layout对象是与collection view相关的,layout控制了collection view如何显示它里面的cells和supplementary views。如下面这行关键的代码
1	     = [[ViewController alloc] initWithCollectionViewLayout:[[CircleLayout alloc] init]];




01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import <UIKit/>
10	
11	@class ViewController;
12	
13	@interface AppDelegate : UIResponder <UIApplicationDelegate>
14	
15	@property (strong, nonatomic) UIWindow *window;
16	
17	@property (strong, nonatomic) ViewController *viewController;
18	
19	@end




01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import ""
10	
11	#import ""
12	#import ""
13	
14	@implementation AppDelegate
15	
16	- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17	{
18	     = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
19	     
20	     = [[ViewController alloc] initWithCollectionViewLayout:[[CircleLayout alloc] init]];
21	     
22	     = ;
23	    [ makeKeyAndVisible];
24	    return YES;
25	}
26	
27	@end

ViewController介绍

ViewController是继承自UICollectionViewController,它负责显示Collection View的所有内容。通常在这里实现Collection View的dataSource和delegate。下面的代码实现了如下两个方法:
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section;
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;


并且给collectionView添加了Tap手势识别功能,以便用户在Tap的时候,对item进行相应的添加和删除功能。

01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import <UIKit/>
10	
11	@interface ViewController : UICollectionViewController
12	
13	@property (nonatomic, assign) NSInteger cellCount;
14	
15	@end



01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import ""
10	#import ""
11	
12	@implementation ViewController
13	
14	-(void)viewDidLoad
15	{
16	     = 20;
17	    UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
18	    [ addGestureRecognizer:tapRecognizer];
19	    [ registerClass:[Cell class] forCellWithReuseIdentifier:@"MY_CELL"];
20	    [ reloadData];
21	     = [UIColor scrollViewTexturedBackgroundColor];
22	
23	    UIImageView* imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@""]];
24	     = ;
25	    [ addSubview:imageView];
26	}
27	
28	- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section;
29	{
30	    return ;
31	}
32	
33	- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
34	{
35	    Cell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"MY_CELL" forIndexPath:indexPath];
36	    return cell;
37	}
38	
39	- (void)handleTapGesture:(UITapGestureRecognizer *)sender {
40	     
41	    if ( == UIGestureRecognizerStateEnded)
42	    {
43	        CGPoint initialPinchPoint = [sender locationInView:];
44	        NSIndexPath* tappedCellPath = [ indexPathForItemAtPoint:initialPinchPoint];
45	        if (tappedCellPath!=nil)
46	        {
47	             =  - 1;
48	            [ performBatchUpdates:^{
49	                [ deleteItemsAtIndexPaths:[NSArray arrayWithObject:tappedCellPath]];
50	                 
51	            } completion:nil];
52	        }
53	        else
54	        {
55	             =  + 1;
56	            [ performBatchUpdates:^{
57	                [ insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:0 inSection:0]]];
58	            } completion:nil];
59	        }
60	    }
61	}
62	
63	@end



Cell介绍

在此自定义了一个简单的cell:继承自UICollectionViewCell。

当item在collection view的可视范围内时,UICollectionViewCell负责显示单个item数据的内容,你可以通过as-is关系来使用它,当然,也可以继承(subclass)自它,以添加一些额外的属性和方法。cell的layout和显示是有collection view管理的,并且cell与layout对象相互对应。

在这里,我使用继承(subclass)机制,来给cell添加了一个UIImageView,用来显示一副图片。代码很简单,看下面的具体时间即可。在.m文件里面对UIImageView进行了圆角处理。

01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import <UIKit/>
10	
11	@interface Cell : UICollectionViewCell
12	
13	@property (strong, nonatomic) UIImageView* imageView;
14	
15	@end




01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import ""
10	
11	@implementation Cell
12	
13	- (id)initWithFrame:(CGRect)frame
14	{
15	    self = [super initWithFrame:frame];
16	    if (self) {
17	         = 10.0;
18	        [ setFrame:CGRectMake(0, 0, 75, 75)];
19	         = 1.0f;
20	         = [UIColor whiteColor].CGColor;
21	         = [UIColor underPageBackgroundColor];
22	         
23	         = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"98_avatar_big.jpg"]];
24	         
25	         = YES;  
26	         = 10.0;
27	        [ setFrame:];
28	        [ addSubview:];
29	    }
30	    return self;
31	}
32	
33	@end

CircleLayout介绍【在UICollectionView中,Layout非常重要】

CircleLayout继承自UICollectionViewLayout,在这里先简单介绍一下UICollectionViewLayout
UICollectionViewLayout类是一个抽象基类,通过继承它以生成collection view的layout信息。layout对象的职责就是决定collection view中cells,supplementary views和decoration views的位置,当collection view请求这些信息时,layout对象会提供给collection view。collection view就使用laout对象提供的信息把相关的view显示在屏幕上。
注意:要使用UICollectionViewLayout必须先子类化它

子类化时需要注意的事项:
layout对象不负责创建views,它只提供layout(布局),view的创建是在collection view的data source中。layout对象定义了view的位置和size等布局属性。

collection view有三种可视元素需要layout:
Cells:cells是layout管理的主要元素。每一个cell代表了collection view中的单个数据item。一个collection view可以把cell放到一个section中,也可以把cell分为多个section。layout的主要职责就是组织collection view的cells。

Supplementary views:supplementary view也显示数据,但是与cells不同。并不像cell,supplementary view不可以被用户选择。相反,可以使用supplementary view来给一个section实现类似页眉和页脚,当然不仅仅是section,也可以是整个collection view。supplementary view是可选的,并且他们的使用和位置是由layout对象定义的。

Decoration views:decoration view是用于装饰的,不可以被用户选择,并且它的相关数据没有与collection view绑定。decoration view是另外一种supplementary view。类似supplementary view,decoration view也是可选的,,并且他们的使用和位置是由layout对象定义的。

collection view会在许多不同时间里面,请求这些元素的layout对象以获得相关 layout信息。每一个出现在屏幕中的cell和view的位置是有layout对象提供的。类似的,每次从collection view中插入或者删除item,相应的layout也会被添加或者移除。当然,collection view总是会限制layout对象数目:即只针对屏幕的可视范围。

需要重载的方法
每个layout对象都需要实现下面的方法:
  • collectionViewContentSize
  • shouldInvalidateLayoutForBoundsChange:
  • layoutAttributesForElementsInRect:
  • layoutAttributesForItemAtIndexPath:
  • layoutAttributesForSupplementaryViewOfKind:atIndexPath: (如果layout 支持 supplementary views)
  • layoutAttributesForDecorationViewWithReuseIdentifier:atIndexPath: (如果layout 支持 decoration views)

这些方法具体作用,可以查阅相关的sdk即可知晓。
当collection view中的数据发生了改变,如插入或删除item,那么collection view会请求这些item的layout对象,以更新layout信息。特别是,任意的item被移动,添加或者删除了,必须要有它相关的layout信息来更新相关的新位置。对于移动一个items,collection view会使用标准的方法来检索item的layout属性。对于item的插入和删除,collection view会调用一些不同的方法,你应该重载这些方法,以提供相关的layout信息:
  • initialLayoutAttributesForInsertedItemAtIndexPath:
  • initialLayoutAttributesForInsertedSupplementaryElementOfKind:atIndexPath:
  • finalLayoutAttributesForDeletedItemAtIndexPath:
  • finalLayoutAttributesForDeletedSupplementaryElementOfKind:atIndexPath:

下面的代码中就是使用到了item的插入和删除。所以重载了下面两个方法:
  • initialLayoutAttributesForInsertedItemAtIndexPath:
  • finalLayoutAttributesForDeletedItemAtIndexPath:


对于layout在collection view中的作用非常重大,你的画面显示什么效果就看你如何定义layout了。更多相关信息还请阅读相关sdk中的内容。在此不再进行详细的讲解。


01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import <UIKit/>
10	
11	@interface CircleLayout : UICollectionViewLayout
12	
13	@property (nonatomic, assign) CGPoint center;
14	@property (nonatomic, assign) CGFloat radius;
15	@property (nonatomic, assign) NSInteger cellCount;
16	
17	@end





01	//
02	//  
03	//  DevDiv_CollectionView_CircleLayout_Demo
04	//
05	//  Created by BeyondVincent on 12-7-3.
06	//  Copyright (c) 2012年 DevDiv. All rights reserved.
07	//
08	
09	#import ""
10	
11	#define ITEM_SIZE 70
12	
13	@implementation CircleLayout
14	
15	-(void)prepareLayout
16	{
17	    [super prepareLayout];
18	     
19	    CGSize size = ;
20	    _cellCount = [[self collectionView] numberOfItemsInSection:0];
21	    _center = CGPointMake( / 2.0,  / 2.0);
22	    _radius = MIN(, ) / 2.5;
23	}
24	
25	-(CGSize)collectionViewContentSize
26	{
27	    return [self collectionView].;
28	}
29	
30	- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
31	{
32	    UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
33	     = CGSizeMake(ITEM_SIZE, ITEM_SIZE);
34	     = CGPointMake(_center.x + _radius * cosf(2 *  * M_PI / _cellCount),
35	                                    _center.y + _radius * sinf(2 *  * M_PI / _cellCount));
36	    return attributes;
37	}
38	
39	-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
40	{
41	    NSMutableArray* attributes = [NSMutableArray array];
42	    for (NSInteger i=0 ; i < ; i++) {
43	        NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];
44	        [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
45	    }   
46	    return attributes;
47	}
48	
49	- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedItemAtIndexPath:(NSIndexPath *)itemIndexPath
50	{
51	    UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
52	     = 0.0;
53	     = CGPointMake(_center.x, _center.y);
54	    return attributes;
55	}
56	
57	- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedItemAtIndexPath:(NSIndexPath *)itemIndexPath
58	{
59	    UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
60	     = 0.0;
61	     = CGPointMake(_center.x, _center.y);
62	    attributes.transform3D = CATransform3DMakeScale(0.1, 0.1, 1.0);
63	    return attributes;
64	}
65	
66	@end