效果图:
UICollectionView能够实现你想要的任何布局,Vincent Ngo在raywenderlich中,用Swift介绍了如何实现书本翻页布局,不得不佩服Vincent
Ngo的想法,链接地址:http://www./94565/how-to-create-an-iOS-book-open-animation-part-1;
本文参考了这种思想,用OC编程实现了其中一部分效果,如上图所示;下面代码在每处都加上了详细解释,欢迎大家提供意见,
新建一个BookCell,继承自UIcollectionViewCell,在实现部分,重写applyLayoutAttributes方法,实现书本边缘圆角效果:
- #import "BookCell.h"
-
- @implementation BookCell
-
- {
- BOOL isRightPage;
- }
-
- //初始化
- - (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- //设置背景
- self.bgView = [[UIView alloc] initWithFrame:self.contentView.bounds];
- self.bgView.backgroundColor = [UIColor whiteColor];
- [self.contentView addSubview:self.bgView];
-
- //添加图片
- self.imageView = [[UIImageView alloc] initWithFrame:self.bgView.bounds];
- [self.bgView addSubview:self.imageView];
-
- //添加星座label
- self.textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 40)];
- self.textLabel.center = CGPointMake(self.bgView.bounds.size.width / 2 + 20, self.bgView.bounds.size.height - 20);
- [self.bgView addSubview:self.textLabel];
-
- //开启反锯齿
- self.layer.allowsEdgeAntialiasing = YES;
-
- }
- return self;
- }
-
- //默认自定义布局,布局圆角 和 中心线
- - (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
- [super applyLayoutAttributes:layoutAttributes];
- //判断cell的奇数偶数
- if (layoutAttributes.indexPath.item % 2 == 0) {
- //如果偶数,则中心线在左边,页面右边有圆角,左边没有圆角
- isRightPage = YES;
- self.layer.anchorPoint = CGPointMake(0, 0.5);
- } else {
- isRightPage = NO;
- self.layer.anchorPoint = CGPointMake(1, 0.5);
- }
-
- //圆角设置
- UIRectCorner corner = isRightPage ? UIRectCornerTopRight | UIRectCornerBottomRight : UIRectCornerTopLeft | UIRectCornerBottomLeft;
- UIBezierPath *bezier = [UIBezierPath bezierPathWithRoundedRect:self.bgView.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(16, 16)];
- //CAShapeLayer: 通过给定的贝塞尔曲线UIBezierPath,在空间中作图
- CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
- maskLayer.frame = self.bgView.bounds;
- maskLayer.path = bezier.CGPath;
- self.bgView.layer.mask = maskLayer;
- self.bgView.clipsToBounds = YES;
- }
- @end
新建一个BookLayout 布局类,继承自UICollectionViewLayout ,在这里我们将实现关键的3个必须实现的布局方法:
1. prepareLayout
2. collectionViewContentSize
3. layoutAttributesForElementsInRect
关键思想,是在 layoutAttributesForItemAtIndexPath 方法中,实现空间布局,考虑到frame的变化,旋转角度和旋转比例的变化,以及cell的frame变化后,anchor点的重新设定等;
- #import "BookLayout.h"
-
- @implementation BookLayout
-
-
- //定义cell的尺寸
- static CGFloat pageWidth = 180;
- static CGFloat pageHeight = 280;
- static CGFloat numberOfPages = 0; //定义总的cell个数
-
-
- - (void)prepareLayout {
- [super prepareLayout];
- //滚动结束时,翻动快些
- self.collectionView.decelerationRate = UIScrollViewDecelerationRateFast;
- numberOfPages = [self.collectionView numberOfItemsInSection:0];
- self.collectionView.pagingEnabled = YES;//滚动视图整页翻动
- }
-
-
- //布局实时更新
- - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
- return YES;
- }
-
-
- //内容滚动区域设置
- - (CGSize)collectionViewContentSize {
- //每个视图上显示两页
- CGFloat width = numberOfPages / 2 - 1;
- return CGSizeMake(width * self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
- }
-
-
-
- //每个cell的布局设置
- - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
-
- //获取cell的布局
- UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
-
-
- //设置frame
- CGRect frame;
- frame.origin.x = self.collectionView.bounds.size.width / 2 - pageWidth / 2 + self.collectionView.contentOffset.x;
- frame.origin.y = (self.collectionViewContentSize.height - pageHeight) / 2;
- frame.size.width = pageWidth;
- frame.size.height = pageHeight;
- layoutAttributes.frame = frame;
-
- //设置ratio
- CGFloat page = (indexPath.item - indexPath.item % 2) * 0.5; //结果 0,0,1,1,2,2 ...
- CGFloat ratio = - 0.5 + page - (self.collectionView.contentOffset.x / self.collectionView.bounds.size.width); //通过偏移量,获取比重
- //限制比重
- if (ratio > 0.5) {
- ratio = 0.5 + 0.1 * (ratio - 0.5);
- } else if (ratio < -0.5) {
- ratio = - 0.5 + 0.1 * (ratio + 0.5);
- }
-
-
- //
- if ((ratio > 0 && indexPath.item % 2 == 1) || (ratio < 0 && indexPath.item % 2 == 0)) {
- if (indexPath.row != 1) {
- return nil;
- }
- }
-
-
- //计算旋转角度angle,设定3D旋转
- CGFloat newRatio = MIN(MAX(ratio, -1), 1);
- //计算m34
- CATransform3D transform = CATransform3DIdentity;
- transform.m34 = 1.0 / - 2000;
-
- CGFloat angle = 0.0f;
- if (indexPath.item % 2 == 0) {
- //中心线在左边
- angle = (1 - newRatio) * (-M_PI_2);
- } else if (indexPath.item % 2 == 1) {
- //中心线在右边
- angle = (1 + newRatio) * (M_PI_2);
- }
- angle += (indexPath.row % 2) / 1000;
-
- transform = CATransform3DRotate(transform, angle, 0, 1, 0);
-
- layoutAttributes.transform3D = transform;
- if (indexPath.row == 0) {
- layoutAttributes.zIndex = NSIntegerMax;
- }
- return layoutAttributes;
- }
-
-
- //所有cell布局数组
- - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
- NSMutableArray *array = [NSMutableArray array];
- for (NSUInteger i = 0; i < numberOfPages; i++) {
- NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
- UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:index];
- if (attributes != nil) {
- [array addObject:attributes];
- }
- }
- return array;
- }
- @end
当布局完成后,我们就大功告成了,在UICollectionView 中,实现代理和数据源就OK了
- #import "BookView.h"
- #import "BookCell.h"
- #import "BookLayout.h"
- @implementation BookView
- {
- NSMutableArray *_array;
- NSMutableArray *_arrayStr;
- }
-
- static NSString *const reuseIdentifier = @"cell";
- - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
- self = [super initWithFrame:frame collectionViewLayout:layout];
- if (self) {
- self.backgroundColor = [UIColor clearColor];
- self.dataSource = self;
- self.delegate =self;
- [self registerClass:[BookCell class] forCellWithReuseIdentifier:reuseIdentifier];
- self.showsHorizontalScrollIndicator = NO;
-
- _array = (NSMutableArray *)@[@"",@"封面.jpg",@"白羊座1.jpg",@"金牛座2.jpg",@"双子座3.jpg",@"巨蟹座4.jpg",@"狮子座5.jpg",@"处女座6.jpg",@"天平座7.jpg",@"天蝎座8.jpg",@"射手座9.jpg",@"魔蝎座10.jpg",@"水瓶座11.jpg",@"双鱼座12.jpg",@"封底.jpg",@""];
- _arrayStr = (NSMutableArray *)@[@"",@"",@"白羊座",@"金牛座",@"双子座",@"巨蟹座",@"狮子座",@"处女座",@"天平座",@"天蝎座",@"射手座",@"魔蝎座",@"水瓶座",@"双鱼座",@"",@""];
- }
- return self;
- }
-
-
- - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
- return 16;
- }
-
-
- - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
- BookCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
- cell.imageView.image = [UIImage imageNamed:_array[indexPath.row]];
- cell.textLabel.text = [NSString stringWithFormat:@"%@", _arrayStr[indexPath.row]];
- cell.textLabel.font = [UIFont systemFontOfSize:12];
- cell.textLabel.textColor = [UIColor colorWithRed:148 / 255.0f green:0.0f blue:211 / 255.0f alpha:1.0f];
- return cell;
- }
- @end
- #import "ViewController.h"
- #import "BookView.h"
- #import "BookLayout.h"
- #define kScreenWidth [UIScreen mainScreen].bounds.size.width
- #define kScreenHeight [UIScreen mainScreen].bounds.size.height
-
- @interface ViewController ()
-
- @end
-
- @implementation ViewController
-
- - (void)viewDidLoad {
- [super viewDidLoad];
-
-
- BookLayout *layout = [[BookLayout alloc] init];
- BookView *book = [[BookView alloc] initWithFrame:CGRectMake(10, 100, 300, 500) collectionViewLayout:layout];
- [self.view addSubview:book];
- }
-
- @end
是不是感觉不可思议!
代码下载地址:
http://download.csdn.net/download/et295394330/9122319
|