OCiOS开发:集合视图 UICollectionView

来源:互联网 发布:vb中的caption属性 编辑:程序博客网 时间:2024/06/09 13:41

简介

UICollectionView 和 UICollectionViewController 类是iOS6 新引进的API,用于展示集合视图,布局更加灵活,可实现多列布局,用法类似于UITableView 和 UITableViewController 类。

使用UICollectionView 必须实现UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout这三个协议。

UICollectionViewFlowLayout

UICollectionViewFlowLayout是苹果内置的一种流式的布局,其继承于UICollectionViewLayout,负责整个视图的布局,通过这个类,可以高度的定制每个item的位置,以及表头、脚注和装饰视图的位置,只需简单的配置几个属性就可以完成整个布局的搭建。

初始化方法

alloc + init

常用属性

  • itemSize:设置item尺寸

  • minimumLineSpacing:设置每行之间的间距

  • minimumInteritemSpacing:设置每行内部item之间的间距

  • headerReferenceSize:设置头部size

  • footerReferenceSize:设置脚注size

  • scrollDirection:设置滚动方向

  • sectionHeadersPinToVisibleBounds:设置是否当元素超出屏幕之后固定头部视图位置,默认NO

  • sectionFootersPinToVisibleBounds:设置是否当元素超出屏幕之后固定尾部视图位置,默认NO

属性配置UICollectionViewFlowLayout是在全局配置布局,想要单独定制每个item元素,需遵守UICollectionViewDelegate以及UICollectionViewDelegateFlowLayout协议,并根据需要实现如下方法即可:

// 1、单独定制item的尺寸- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;// 2、定义每个UICollectionView的margin(间距),对每一个section单独设置边界,即内部cell上下左右距离header和footer的边界(间距)- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;// 3、单独定制每行之间的间距- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;// 4、单独定制每行item之间的间距- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;// 5、单独定制头部视图size- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;// 6、单独定制脚注视图size- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;

UICollectionView

初始化

- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout; 

常用属性

  • delegate:设置代理

  • dataSource:设置数据源

  • allowsSelection:设置是否可以选中

  • allowsMultipleSelection:设置是否可以多选

注册

  • 注册Cell
- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
  • 注册头部或尾部视图
// @param elementKind// UICollectionElementKindSectionHeader:头部// UICollectionElementKindSectionFooter:尾部- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;

重用

// 1、Cell重用- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;// 2、supplementary View重用- (id)dequeueReusableSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;

操作

  • items操作
// 插入- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths;// 删除- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths;// 刷新- (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths;// 移动- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;
  • sections操作
// 插入- (void)insertSections:(NSIndexSet *)sections;// 删除- (void)deleteSections:(NSIndexSet *)sections;// 刷新- (void)reloadSections:(NSIndexSet *)sections;// 移动- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;

indexPath 获取方法

// 根据某一个点的位置获取item的indexPath- (nullable NSIndexPath *)indexPathForItemAtPoint:(CGPoint)point;// 根据cell获取item的indexPath- (nullable NSIndexPath *)indexPathForCell:(UICollectionViewCell *)cell;

reordering 重新排序

  • 一般重新排序步骤需经历如下周期,与手势搭配使用,根据手势的周期变化执行不同的方法:
// 1、设置是否允许移动item- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath;// 2、一般在手势开始时调用,与 indexPathForItemAtPoint 搭配使用,根据手势在视图上的位置获取item所在的indexPath, 开始在特定的索引路径上对cell(单元)进行Interactive Movement(交互式移动工作)- (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath;// 3、 在手势作用期间更新交互移动的目标位置。- (void)updateInteractiveMovementTargetPosition:(CGPoint)targetPosition;// 4、在完成手势动作后,结束交互式移动- (void)endInteractiveMovement;// 5、取消移动- (void)cancelInteractiveMovement;// 6、当移动结束后,如下方法将会被触发。- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath;

UIScrollViewDelegate

// 1、设置是否允许选中- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;// 2、设置是否允许取消选中- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath;// 3、选中- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;// 4、取消选中- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;

UICollectionViewDataSource

// 1、设置section组数- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;// 2、设置item个数- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;// 3、配置cell- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;// 4、自定义头部、脚注视图- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;

tips:配置Cell以及头部或者脚注视图需子类化UICollectionViewCellUICollectionReusableView,并重写initWithFrame方法,添加视图;

案例

效果展示

这里写图片描述

代码示例

自定义 cell 代码示例

#import <UIKit/UIKit.h>@interface CustomCollectionViewCell : UICollectionViewCell@property (nonatomic, strong) UILabel *displayLabel; /**< 展示视图 */@end
#import "CustomCollectionViewCell.h"@implementation CustomCollectionViewCell- (instancetype)initWithFrame:(CGRect)frame {    self = [super initWithFrame:frame];    if (self) {        self.layer.borderWidth   = 1.0f;        self.layer.borderColor   = [UIColor blackColor].CGColor;        self.layer.masksToBounds = YES;        [self.contentView addSubview:self.displayLabel];    }    return self;}#pragma mark *** Getters ***- (UILabel *)displayLabel {    if (!_displayLabel) {        _displayLabel = [[UILabel alloc] initWithFrame:self.bounds];        _displayLabel.textAlignment = NSTextAlignmentCenter;    }    return _displayLabel;}@end

自定义 ReusableView(头部、尾部) 代码示例

#import <UIKit/UIKit.h>// 自定义头部、尾部视图@interface CustomCollectionReusableView : UICollectionReusableView@property (nonatomic, strong) UILabel *displayLabel; /**< 展示标签 */@end
#import "CustomCollectionReusableView.h"@implementation CustomCollectionReusableView- (instancetype)initWithFrame:(CGRect)frame {    self = [super initWithFrame:frame];    if (self) {        [self addSubview:self.displayLabel];    }    return self;}#pragma mark *** Getters ***- (UILabel *)displayLabel {    if (!_displayLabel) {        _displayLabel = [[UILabel alloc] initWithFrame:self.bounds];        _displayLabel.backgroundColor = [UIColor redColor];        _displayLabel.textColor = [UIColor whiteColor];        _displayLabel.textAlignment = NSTextAlignmentCenter;    }    return _displayLabel;}@end

viewController 代码示例

#import <UIKit/UIKit.h>@interface ViewController : UIViewController@end
#import "ViewController.h"#import "CustomCollectionViewCell.h"#import "CustomCollectionReusableView.h"enum NSInteger {    InsertItemTag = 100,    DeleteItemTag};static NSString *const kTitle = @"CollectionView";static NSString *const kCollectionViewCellIdentifier = @"collectionViewCellIdentifier";static NSString *const kCollectionElementKindSectionHeaderIdentifier = @"headerIdentifier";@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout> {    BOOL _selected;    NSMutableArray *_dataSource; /**< 数据源 */    NSMutableArray *_selectedDataArr; /**< 选中数据源 */}@property (nonatomic, strong) UICollectionView *collectionView; /**< 集合视图 */@property (nonatomic, strong) UICollectionViewFlowLayout *collectionViewFlowLayout; /**< 流式布局 */- (void)initializeDataSource; /**< 初始化数据源 */- (void)initializeUserInterface; /**< 初始化用户界面 */@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    [self initializeDataSource];    [self initializeUserInterface];}#pragma mark *** Initialize ***- (void)initializeDataSource {    _selectedDataArr = [NSMutableArray array];    // 添加数据    _dataSource = [NSMutableArray array];    for (int i = 0; i < 20; i++) {        [_dataSource addObject:[NSString stringWithFormat:@"%d", i]];    }}- (void)initializeUserInterface {    self.title = kTitle;    self.automaticallyAdjustsScrollViewInsets = NO;    // 视图加载    [self.view addSubview:self.collectionView];    // 配置导航栏    // 插入    UIBarButtonItem *insertItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd                                                                                target:self                                                                                action:@selector(respondsToBarButtonItem:)];    insertItem.tag = InsertItemTag;    self.navigationItem.rightBarButtonItem = insertItem;    // 删除    UIBarButtonItem *deleteItem = [[UIBarButtonItem alloc] initWithTitle:@"删除"                                                                   style:UIBarButtonItemStylePlain                                                                  target:self                                                                  action:@selector(respondsToBarButtonItem:)];    deleteItem.tag = DeleteItemTag;    self.navigationItem.leftBarButtonItem = deleteItem;    // 添加长按手势,重排item    UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self                                                                                              action:@selector(respondsToGesture:)];    [self.collectionView addGestureRecognizer:longGesture];}#pragma mark *** Gestures ***- (void)respondsToGesture:(UIGestureRecognizer *)gesture {    NSLog(@"%@", NSStringFromSelector(_cmd));    // 监听手势状态    switch (gesture.state) {            // 1、手势开始        case UIGestureRecognizerStateBegan: {            // 获取手势长按位置            NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[gesture locationInView:self.collectionView]];            // 开始在特定的索引路径上对cell(单元)进行Interactive Movement(交互式移动工作)            [self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];        }            break;            // 2、手势变换        case UIGestureRecognizerStateChanged: {            // 在手势作用期间更新交互移动的目标位置。            [self.collectionView updateInteractiveMovementTargetPosition:[gesture locationInView:self.collectionView]];        }            break;            // 3、手势结束        case UIGestureRecognizerStateEnded: {            // 在完成手势动作后,结束交互式移动            [self.collectionView endInteractiveMovement];        }            break;        default: {            // 4、默认状态下,取消Interactive Movement。            [self.collectionView cancelInteractiveMovement];        }            break;    }}#pragma mark *** Events ***- (void)respondsToBarButtonItem:(UIBarButtonItem *)sender {    switch (sender.tag) {        case InsertItemTag: {            // 弹出框            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"请输入您要添加的数字:" preferredStyle:UIAlertControllerStyleAlert];            [alertController.view layoutIfNeeded];            // 添加文本输入框            [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {                textField.clearButtonMode = UITextFieldViewModeWhileEditing;                textField.textAlignment = NSTextAlignmentCenter;            }];            // 添加按钮            [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil]];            [alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {                // 获取文本输入框                UITextField *textField = alertController.textFields[0];                // 获取文本                NSString *context = textField.text;                // 异常处理                if (context.length == 0) {                    NSLog(@"请输入文本!");                    return ;                }                // 数据源插入                [_dataSource insertObject:context atIndex:0];                // 单元格插入                [_collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:0]]];            }]];            [self presentViewController:alertController animated:YES completion:nil];        }            break;        case DeleteItemTag: {            if ([self.navigationItem.leftBarButtonItem.title isEqualToString:@"点击删除"]) {                NSLog(@"执行删除逻辑!");                // 遍历删除数据源数据                for (NSString *data in _selectedDataArr) {                    [_dataSource removeObject:data];                }                // 刷新集合视图                [self.collectionView reloadData];                self.collectionView.allowsSelection = NO;            }            // 切换编辑状态            _selected = !_selected;            self.navigationItem.leftBarButtonItem.title = _selected ? @"选择删除项" : @"删除";           if ([self.navigationItem.leftBarButtonItem.title isEqualToString:@"选择删除项"]) {               self.collectionView.allowsSelection = YES;            }        }            break;        default:            break;    }}#pragma mark *** UICollectionViewDataSource ***// 设置组数- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {    return 1;}// 设置行数- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return _dataSource.count;}// 设置单元格- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    // item重用机制    CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCollectionViewCellIdentifier forIndexPath:indexPath];    cell.displayLabel.backgroundColor = [UIColor whiteColor];    cell.displayLabel.text = _dataSource[indexPath.row];    return cell;}// 设置自定义头部、尾部视图- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {    // UICollectionElementKindSectionHeader:头部视图    // UICollectionElementKindSectionFooter:尾部视图    // 如果同时自定义头部、尾部视图,可根据 kind 参数判断当前加载的是头部还是尾部视图,然后进行相应配置。    // 重用机制    CustomCollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kCollectionElementKindSectionHeaderIdentifier forIndexPath:indexPath];    headerView.displayLabel.text = @"[自定义头部视图]";    return headerView;}// 设置是否允许移动- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath {    return YES;}// 移动元素- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {    NSLog(@"%@", NSStringFromSelector(_cmd));}#pragma mark *** UICollectionViewDelegateFlowLayout ***// 通过UICollectionViewDelegateFlowLayout提供的方法可高度定制流式布局;- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {    return UIEdgeInsetsMake(0, 10, 0, 10);}#pragma mark *** UICollectionViewDelegate ***// 选中单元格- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {    self.navigationItem.leftBarButtonItem.title = @"点击删除";     _selected = YES;    CustomCollectionViewCell *cell = (CustomCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];    cell.displayLabel.backgroundColor = [UIColor greenColor];    [_selectedDataArr addObject:cell.displayLabel.text];}// 取消选中- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {    CustomCollectionViewCell *cell = (CustomCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];    cell.displayLabel.backgroundColor = [UIColor whiteColor];    [_selectedDataArr removeObject:cell.displayLabel.text];}#pragma mark *** Getters ***- (UICollectionViewFlowLayout *)collectionViewFlowLayout {    if (!_collectionViewFlowLayout) {        _collectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];        // 设置item估计值        _collectionViewFlowLayout.estimatedItemSize = CGSizeMake(100, 100);        // 全局配置item尺寸,单独定义调用协议方法[sizeForItemAtIndexPath]        _collectionViewFlowLayout.itemSize = CGSizeMake(100, 100);        // 全局配置每行之间的间距,单独定义可调用协议方法[minimumLineSpacingForSectionAtIndex]        _collectionViewFlowLayout.minimumLineSpacing = 10;        // 全局配置每行内部item的间距,单独定义可调用协议方法[minimumInteritemSpacingForSectionAtIndex]        _collectionViewFlowLayout.minimumInteritemSpacing = 10;        // 设置头部size        _collectionViewFlowLayout.headerReferenceSize = CGSizeMake(CGRectGetWidth(self.view.bounds), 44);        // 设置尾部size        _collectionViewFlowLayout.footerReferenceSize = CGSizeZero;        // 设置滚动方向        // UICollectionViewScrollDirectionVertical        // UICollectionViewScrollDirectionHorizontal        _collectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;        // 设置是否当元素超出屏幕之后固定头部视图位置,默认NO;        _collectionViewFlowLayout.sectionHeadersPinToVisibleBounds = YES;        // 设置是否当元素超出屏幕之后固定尾部视图位置,默认NO;        _collectionViewFlowLayout.sectionFootersPinToVisibleBounds = YES;    }    return _collectionViewFlowLayout;}- (UICollectionView *)collectionView {    if (!_collectionView) {        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 64, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - 64) collectionViewLayout:self.collectionViewFlowLayout];        _collectionView.backgroundColor = [UIColor brownColor];        // 设置是否允许滚动        _collectionView.scrollEnabled = YES;        // 设置是否允许选中,默认YES        _collectionView.allowsSelection = NO;        // 设置是否允许多选,默认NO        _collectionView.allowsMultipleSelection = YES;        // 设置代理        _collectionView.delegate = self;        // 设置数据源        _collectionView.dataSource = self;        // 注册Item        [_collectionView registerClass:[CustomCollectionViewCell class] forCellWithReuseIdentifier:kCollectionViewCellIdentifier];        // 注册头部视图        [_collectionView registerClass:[CustomCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kCollectionElementKindSectionHeaderIdentifier];    }    return _collectionView;}@end
4 0
原创粉丝点击