首页  »   移动开发

UICollectionView详解3:UICollectionViewLayout

网友分享于:2015-05-21  浏览:0次
UICollectionView详解三:UICollectionViewLayout

上一节中,我介绍了UICollectionViewFlowLayout的使用,它主要是使用在流式布局中的,但对于某些复杂的布局,UICollectionViewFlowLayout就不起作用了。这个时候,我们可以考虑使用UICollectionViewLayout。 UICollectionViewFlowLayout是继承自UICollectionViewLayout,并且拥有自己的流式特性。对于一些复杂的效果,我们完全可以自定义UICollectionViewLayout来实现。

这一节,我就介绍使用UICollectionViewLayout来实现不同布局的来回切换。最终效果图如下:

样式1:



样式2:



我们可以通过点击屏幕的空白区域来回的切换上面两种效果,并且切换过程中,动画效果非常的流畅。

主界面的代码和以前一样,设置数据源;初始化UICollectionView;注册UICollectionViewCell;代码如下:

@interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate>
@property (nonatomic,strong) NSMutableArray *images;
@property (nonatomic,weak) UICollectionView *collectionView;
@end

static NSString *const identifer = @"ImageCell";

@implementation ViewController

-(NSMutableArray *)images {
    if (!_images) {
        _images = [NSMutableArray array];
        for (int i=1;i<=8;i++) {
            [_images addObject:[NSString stringWithFormat:@"%d.jpg",i]];
        }
    }
    return _images;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    CGRect rect = CGRectMake(0, 150, self.view.frame.size.width,400);
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:[[LFStackLayout alloc] init]];
    collectionView.dataSource = self;
    collectionView.delegate = self;
    
    // 注册collectionView(因为是从xib中加载cell的,所以registerNib)
    [collectionView registerNib:[UINib nibWithNibName:@"ImageCell" bundle:nil] forCellWithReuseIdentifier:identifer];
    
    [self.view addSubview:collectionView];
    
    self.collectionView = collectionView;
}

#pragma mark - 点击屏幕空白处,切换布局模式
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([self.collectionView.collectionViewLayout isKindOfClass:[LFStackLayout class]]) {
        [self.collectionView setCollectionViewLayout:[[LFCircleLayout alloc] init] animated:YES];
    } else {
        [self.collectionView setCollectionViewLayout:[[LFStackLayout alloc] init] animated:YES];
    }
}

#pragma mark - delegate
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return  self.images.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    ImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifer forIndexPath:indexPath];
    
    cell.iconName = self.images[indexPath.item];
    
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    // 1. 删除模型数据
    [self.images removeObjectAtIndex:indexPath.item];
    
    // 2. 删除UI元素
    [collectionView deleteItemsAtIndexPaths:@[indexPath]];
}

关键代码就是这一段,用来实现“堆叠布局”和“圆形布局”的自由切换。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([self.collectionView.collectionViewLayout isKindOfClass:[LFStackLayout class]]) {
        [self.collectionView setCollectionViewLayout:[[LFCircleLayout alloc] init] animated:YES];
    } else {
        [self.collectionView setCollectionViewLayout:[[LFStackLayout alloc] init] animated:YES];
    }
}

这里,我就“圆形布局”进行说明,自定义LFCircleLayout, 并且继承自UICollectionViewLayout

@interface LFCircleLayout : UICollectionViewLayout

@end

UICollectionViewFlowLayout是可以直接获取到所有Item的FlowLayout,然后对各自的layout进行调整;而UICollectionViewLayout完全需要自定义,来满足自己的需求。主要是下面的代码,重写父类的 layoutAttributesForElementsInRect方法,返回的数组对象就是自定义layout的集合。当获取到这个集合后,UICollectionView就会对每一个Item进行自动调节。
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
     ...
}

自定义LFCircleLayout中实现的layoutAttributesForElementsInRect方法如下:

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray *array = [NSMutableArray array];
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    
    for (int i=0; i<count; i++) {
        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        [array addObject:attrs];
    }
    
    return array;
}

代码中定义了一个方法:layoutAttributesForItemAtIndexPath, 专门用来设置每个Item的layout,完成“圆形布局”。代码如下:

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    attrs.size = CGSizeMake(60, 60);
    
    // 第几个Item
    NSInteger index = indexPath.item;
    
    // 半径100
    CGFloat radius = 100;
    
    // 圆心
    CGFloat circleX = self.collectionView.frame.size.width * 0.5;
    CGFloat circleY = self.collectionView.frame.size.height * 0.5;
    
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    CGFloat singleItemAngle = 360.0 / count;
    
    // 计算各个环绕的图片center
    attrs.center = CGPointMake(circleX + radius * cosf(kCalcAngle(singleItemAngle * index)), circleY - radius * sinf(kCalcAngle(singleItemAngle * index)));
    
    return attrs;
}

代码中关于计算弧度的方法,我定义了一个宏来处理。

#define kCalcAngle(x) x * M_PI / 180.0

“堆叠布局”我就不做介绍了,基本类似,主要代码如下:

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    attrs.size = CGSizeMake(150, 150);
    attrs.center = CGPointMake(self.collectionView.frame.size.width * 0.5, self.collectionView.frame.size.height * 0.5);
    
    NSInteger index = indexPath.item;
    CGFloat angles[] ={0,15,30,45,60};
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    
    if (index >= 5) {
        attrs.hidden = YES;
    } else {
        attrs.transform = CGAffineTransformMakeRotation(kCalcAngle(angles[index]));
        attrs.zIndex = count - index;
    }
    
    return attrs;
}

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray *array = [NSMutableArray array];
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    
    for (int i=0; i<count; i++) {
        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        [array addObject:attrs];
    }
    
    return array;
}


相关解决方案

最新解决方案