闲来没事,做了个 UICollectionView 的圆形布局,效果图如下
控制器代码如下
//
// ViewController.m
// CollectionViewTest
//
// Created by 黄瑞 on 2017/5/24.
// Copyright © 2017年 CoderHuang. All rights reserved.
//
#import "ViewController.h"
#import "MyLayout.h"
#import "MyCollectionView.h"
@interface ViewController () <UICollectionViewDelegate, UICollectionViewDataSource>
{
NSInteger count;
}
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
// 方块个数
@property (weak, nonatomic) IBOutlet UISlider *countSlider;
// 起始位置
@property (weak, nonatomic) IBOutlet UISlider *originSlider;
// 方块个数Label
@property (weak, nonatomic) IBOutlet UILabel *countLabel;
// 颜色数组
@property (nonatomic, strong) NSArray <UIColor *> *colors;
@end
@implementation ViewController
#pragma mark - View did load
- (void)viewDidLoad {
[super viewDidLoad];
count = (NSInteger)self.countSlider.value;
self.countLabel.text = [NSString stringWithFormat:@"%ld", (long)count];
self.colors = @[
[UIColor redColor],
[UIColor orangeColor],
[UIColor yellowColor],
[UIColor greenColor],
[UIColor blueColor],
[UIColor magentaColor],
[UIColor purpleColor],
];
}
#pragma mark - Slider click
- (IBAction)valueChange:(UISlider *)sender {
if (sender == self.countSlider) {
NSInteger nCount = (NSInteger)self.countSlider.value;
if (nCount != count) {
count = nCount;
self.countLabel.text = [NSString stringWithFormat:@"%ld", (long)count];
[self.collectionView reloadData];
}
} else {
MyLayout *layout = (MyLayout *)self.collectionView.collectionViewLayout;
layout.origin = sender.value;
[self.collectionView reloadData];
}
}
// 和 UITableView 类似,UICollectionView也是有 Section 和 Row 的
#pragma mark - Delegate
#pragma mark - Collection view delegate
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return count;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// 已经在 StoryBoard 中设置了ReuseIdentifier
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
cell.backgroundColor = self.colors[indexPath.row % self.colors.count];
return cell;
}
@end
StoryBoard
如图
注意,要将 CollectionView 的 Layout 改为 Custom 然后选择自定义类 MyLayout,它必须继承自 UICollectionViewLayout 类。
MyLayout.h
//
// MyLayout.h
// CollectionViewTest
//
// Created by 黄瑞 on 2017/5/24.
// Copyright © 2017年 CoderHuang. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface MyLayout : UICollectionViewLayout
// 起始的角度
@property (nonatomic, assign) CGFloat origin;
@end
MyLayout.m
//
// MyLayout.m
// CollectionViewTest
//
// Created by 黄瑞 on 2017/5/24.
// Copyright © 2017年 CoderHuang. All rights reserved.
//
#import "MyLayout.h"
@interface MyLayout ()
{
// item的数量
NSInteger count;
// 圆形布局的中心
CGPoint center;
// 圆形布局的半径
CGFloat radius;
}
@end
@implementation MyLayout
// 重写父类的四个方法
- (void)prepareLayout {
count = [self.collectionView numberOfItemsInSection:0];
center = CGPointMake(self.collectionView.frame.size.width / 2, self.collectionView.frame.size.height / 2);
radius = 150;
}
// 返回 ContentSize
- (CGSize)collectionViewContentSize {
return self.collectionView.frame.size;
}
// 对于每一个 Item 都有一个 UICollectionViewLayoutAttributes 对象与它对应,这个对象仅仅包含了Item的布局信息。
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray *arr = [NSMutableArray array];
for (NSInteger i = 0; i < count; i++) {
[arr addObject:[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]]];
}
return arr;
}
// 根据 indexPath 来创建 Item 的布局属性对象
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __func__);
UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGFloat angle = 2 * M_PI / count * indexPath.row + M_PI_2 * self.origin;
CGFloat x = center.x + cos(angle) * radius;
CGFloat y = center.y - sin(angle) * radius;
attr.center = CGPointMake(x, y);
attr.size = CGSizeMake(30, 30);
return attr;
}
@end