IOS 6 集合视图

IOS 6中开放了集合视图API——UICollectionView,方便了网格视图的开发。集合视图有4个重要组成部分:

1、单元格,它是集合视图中的一个单元格。

2、,它是集合视图中的一个行数据,由多个单元格组成。

3、补充视图,它是节的头和脚。

4、装饰视图,集合视图中的背景视图。


UICollectionView继承自UIScrollView。与选择器类似,集合视图也有两个协议:UICollectionViewDelegate委托协议和UICollectionViewDataSource数据源协议。UICollectionViewCell是单元格类。集合视图的布局由UICollectionViewLayout类定义,它是一个抽象类。UICollectionViewFlowLayout是UICollectionViewLayout的子类。对于复杂的布局,可以自定义UICollectionViewLayout类。UICollectionView对应的控制器是UICollectionViewController类(具体如下图所示)。



下面是一个简单的sample。

//  ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UICollectionViewController

@property (strong, nonatomic) NSArray * events;

@end

这里ViewController的父类是UICollectionViewController(需要实现集合视图的数据源和代理协议,这里我们直接在storyboard里操作),events是一个数组,用于存放数据。数据保存在plist文件中,组织方式如下所示,



我们在viewDidLoad方法中读取数据:

- (void)viewDidLoad
{
    [super viewDidLoad];
  
	NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"events"ofType:@"plist"];
    //获取文件中的数据
	self.events = [[NSArray alloc] initWithContentsOfFile:plistPath];
    
}


接下来我们需要定义集合视图的单元格,我们可以在storyboard中设计也可以通过代码来设计。单元格是一个视图,可以在它的内部放置其它视图或控件。

首先我们定义一个单元格类,注意它的父类必须是UICollectionViewCell。因为数据单元中定义了key分别为image和name的两个键值对,所以在单元格类中显示数据就需要两个属性与之对应。这里我们定义一个UIImageView和一个UILabel属性(并定义成输出口)。

//  Cell.h

#import <UIKit/UIKit.h>

@interface Cell : UICollectionViewCell

@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@property (strong, nonatomic) IBOutlet UILabel *label;

@end

Cell.m代码如下:

#import "Cell.h"

@implementation Cell

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

@end

因为我们的单元格视图在Interface Builder设计,所以 在这个文件中我们不需要做任何事情(上述代码是自动生成的)。如果我们通过代码实现单元格视图,就需要在initWithFrame:函数中实现UIImageView和UILabel两个控件的初始化代码。


接下来打开ViewController的storyboard文件,将界面的View Controller下的View换成Collection View(如下图)。



这里我们把结合视图的背景改成白色,选择Collection View并修改其背景色。然后选择Collection View Cell,打开其标识检查器,将Custom Class改成Cell(如下左图);打开其属性检查器,在Collection Reusable View的Identifier中输入Cell(如下右图),这是可重用单元格标识。

                      


上面提到的“可重用单元格”是为了节约内存开销而设计的,当屏幕在翻动时,旧的单元格退出屏幕,新的单元格进入屏幕,如果每次都实例化单元格,必然增加内心开销,可重用单元格就是不去实例化新的单元格,而是先使用可重用单元格标识到视图中去找,找到了就使用,没有则创建。IOS 6对可重用单元格进行优化,不在需要做nil判断了。之前代码

Cell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    if(!cell){
        ...
    }
改成如下形式

Cell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];


说了这么多,我们的单元格视图还没设计呢。接下来从对象库中分别拖拽一个UIImageView和UILabel到单元格中。由于要往里面动态填数据,所以我们要将这两个控件与Cell类中的两个输出口连线。具体操作方法是:选中Cell,然后按住control将鼠标拖拽到UIImageView控件上,这时会弹出一个菜单,选择Image View。用同样的方法将Label控件与label属性连接起来。


下面直接看ViewController.m中实现的集合数据源和代理协议方法:

#pragma mark - UICollectionViewDataSource

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return [self.events count] / 2;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 2;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    Cell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    NSDictionary *event = [self.events objectAtIndex:(indexPath.section*2 + indexPath.row)];
    cell.label.text = [event objectForKey:@"name"];
    cell.imageView.image = [UIImage imageNamed:[event objectForKey:@"image"]];
    return cell;
}

#pragma mark - UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *event = [self.events objectAtIndex:(indexPath.section*2 + indexPath.row)];
    NSLog(@"select event name : %@", [event objectForKey:@"name"]);

}


UICollectionViewDataSource协议的定义如下:

@protocol UICollectionViewDataSource <NSObject>
@required

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;

// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;

@optional

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;

// The view that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;

@end

这里的collectionView:numberOfItemsInsection:方法是定义节中的单元格数(列数),collectionView:cellForItemAtIndexPath:方法是定义单元格中的显示数据,这两个方法是必须要实现的。另两个方法,numberOfSectionsInCollectionView:方法是定义集合视图中节的数目,collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法是定义某个节的补充视图显示数据的。


UICollectionViewDelegate协议定义如下:

@protocol UICollectionViewDelegate <UIScrollViewDelegate>
@optional

// Methods for notification of selection/deselection and highlight/unhighlight events.
// The sequence of calls leading to selection from a user touch is:
//
// (when the touch begins)
// 1. -collectionView:shouldHighlightItemAtIndexPath:
// 2. -collectionView:didHighlightItemAtIndexPath:
//
// (when the touch lifts)
// 3. -collectionView:shouldSelectItemAtIndexPath: or -collectionView:shouldDeselectItemAtIndexPath:
// 4. -collectionView:didSelectItemAtIndexPath: or -collectionView:didDeselectItemAtIndexPath:
// 5. -collectionView:didUnhighlightItemAtIndexPath:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath; // called when the user taps on an already-selected item in multi-select mode
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;

// These methods provide support for copy/paste actions on cells.
// All three should be implemented if any are.
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;

@end

这里提供的方法比较多,使用方便,都是可选实现的。我们代码中只实现了collectionView:didSelectItemAtIndexPath:方法,它在选择单元格之后触发。其他的代理方法文档上都有很清楚的描述,不一一赘述。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值