分享

UICollectionView实现书本翻页布局

 昵称v8JFa 2016-05-13

效果图:


UICollectionView能够实现你想要的任何布局,Vincent Ngo在raywenderlich中,用Swift介绍了如何实现书本翻页布局,不得不佩服Vincent Ngo的想法,链接地址:http://www./94565/how-to-create-an-iOS-book-open-animation-part-1;

本文参考了这种思想,用OC编程实现了其中一部分效果,如上图所示;下面代码在每处都加上了详细解释,欢迎大家提供意见,

新建一个BookCell,继承自UIcollectionViewCell,在实现部分,重写applyLayoutAttributes方法,实现书本边缘圆角效果:

  1. #import "BookCell.h"  
  2.   
  3. @implementation BookCell  
  4.   
  5. {  
  6.     BOOL isRightPage;  
  7. }  
  8.   
  9. //初始化  
  10. - (instancetype)initWithFrame:(CGRect)frame {  
  11.     self = [super initWithFrame:frame];  
  12.     if (self) {  
  13.         //设置背景  
  14.         self.bgView = [[UIView alloc] initWithFrame:self.contentView.bounds];  
  15.         self.bgView.backgroundColor = [UIColor whiteColor];  
  16.         [self.contentView addSubview:self.bgView];  
  17.           
  18.         //添加图片  
  19.         self.imageView = [[UIImageView alloc] initWithFrame:self.bgView.bounds];  
  20.         [self.bgView addSubview:self.imageView];  
  21.           
  22.         //添加星座label  
  23.         self.textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 40)];  
  24.         self.textLabel.center = CGPointMake(self.bgView.bounds.size.width / 2 + 20, self.bgView.bounds.size.height - 20);  
  25.         [self.bgView addSubview:self.textLabel];  
  26.           
  27.         //开启反锯齿  
  28.         self.layer.allowsEdgeAntialiasing = YES;  
  29.           
  30.     }  
  31.     return self;  
  32. }  
  33.   
  34. //默认自定义布局,布局圆角 和 中心线  
  35. - (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {  
  36.     [super applyLayoutAttributes:layoutAttributes];  
  37.     //判断cell的奇数偶数  
  38.     if (layoutAttributes.indexPath.item % 2 == 0) {  
  39.         //如果偶数,则中心线在左边,页面右边有圆角,左边没有圆角  
  40.         isRightPage = YES;  
  41.         self.layer.anchorPoint = CGPointMake(0, 0.5);  
  42.     } else {  
  43.         isRightPage = NO;  
  44.         self.layer.anchorPoint = CGPointMake(1, 0.5);  
  45.     }  
  46.       
  47.     //圆角设置  
  48.     UIRectCorner corner = isRightPage ? UIRectCornerTopRight | UIRectCornerBottomRight : UIRectCornerTopLeft | UIRectCornerBottomLeft;  
  49.     UIBezierPath *bezier = [UIBezierPath bezierPathWithRoundedRect:self.bgView.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(16, 16)];  
  50.     //CAShapeLayer: 通过给定的贝塞尔曲线UIBezierPath,在空间中作图  
  51.     CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];  
  52.     maskLayer.frame = self.bgView.bounds;  
  53.     maskLayer.path = bezier.CGPath;  
  54.     self.bgView.layer.mask = maskLayer;  
  55.     self.bgView.clipsToBounds = YES;  
  56. }  
  57. @end  


新建一个BookLayout 布局类,继承自UICollectionViewLayout ,在这里我们将实现关键的3个必须实现的布局方法:

1. prepareLayout

2. collectionViewContentSize

3.  layoutAttributesForElementsInRect

关键思想,是在 layoutAttributesForItemAtIndexPath 方法中,实现空间布局,考虑到frame的变化,旋转角度和旋转比例的变化,以及cell的frame变化后,anchor点的重新设定等;

  1. #import "BookLayout.h"  
  2.   
  3. @implementation BookLayout  
  4.   
  5.   
  6. //定义cell的尺寸  
  7. static CGFloat pageWidth = 180;  
  8. static CGFloat pageHeight = 280;  
  9. static CGFloat numberOfPages = 0; //定义总的cell个数  
  10.   
  11.   
  12. - (void)prepareLayout {  
  13.     [super prepareLayout];  
  14.     //滚动结束时,翻动快些  
  15.     self.collectionView.decelerationRate = UIScrollViewDecelerationRateFast;  
  16.     numberOfPages = [self.collectionView numberOfItemsInSection:0];  
  17.     self.collectionView.pagingEnabled = YES;//滚动视图整页翻动  
  18. }  
  19.   
  20.   
  21. //布局实时更新  
  22. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {  
  23.     return YES;  
  24. }  
  25.   
  26.   
  27. //内容滚动区域设置  
  28. - (CGSize)collectionViewContentSize {  
  29.     //每个视图上显示两页  
  30.     CGFloat width = numberOfPages / 2 - 1;  
  31.     return CGSizeMake(width * self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);  
  32. }  
  33.   
  34.   
  35.   
  36. //每个cell的布局设置  
  37. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {  
  38.       
  39.     //获取cell的布局  
  40.     UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];  
  41.       
  42.       
  43.     //设置frame  
  44.     CGRect frame;  
  45.     frame.origin.x = self.collectionView.bounds.size.width / 2 - pageWidth / 2 + self.collectionView.contentOffset.x;  
  46.     frame.origin.y = (self.collectionViewContentSize.height - pageHeight) / 2;  
  47.     frame.size.width = pageWidth;  
  48.     frame.size.height = pageHeight;  
  49.     layoutAttributes.frame = frame;  
  50.       
  51.     //设置ratio  
  52.     CGFloat page = (indexPath.item - indexPath.item % 2) * 0.5; //结果 0,0,1,1,2,2 ...  
  53.     CGFloat ratio = - 0.5 + page - (self.collectionView.contentOffset.x / self.collectionView.bounds.size.width); //通过偏移量,获取比重  
  54.     //限制比重  
  55.     if (ratio > 0.5) {  
  56.         ratio = 0.5 + 0.1 * (ratio - 0.5);  
  57.     } else if (ratio < -0.5) {  
  58.         ratio = - 0.5 + 0.1 * (ratio + 0.5);  
  59.     }  
  60.       
  61.       
  62.     //  
  63.     if ((ratio > 0 && indexPath.item % 2 == 1) || (ratio < 0 && indexPath.item % 2 == 0)) {  
  64.         if (indexPath.row != 1) {  
  65.             return nil;  
  66.         }  
  67.     }  
  68.       
  69.       
  70.     //计算旋转角度angle,设定3D旋转  
  71.     CGFloat newRatio = MIN(MAX(ratio, -1), 1);  
  72.     //计算m34  
  73.     CATransform3D transform = CATransform3DIdentity;  
  74.     transform.m34 = 1.0 / - 2000;  
  75.       
  76.     CGFloat angle = 0.0f;  
  77.     if (indexPath.item % 2 == 0) {  
  78.         //中心线在左边  
  79.         angle = (1 - newRatio) * (-M_PI_2);  
  80.     } else if (indexPath.item % 2 == 1) {  
  81.         //中心线在右边  
  82.         angle = (1 + newRatio) * (M_PI_2);  
  83.     }  
  84.     angle += (indexPath.row % 2) / 1000;  
  85.       
  86.     transform = CATransform3DRotate(transform, angle, 0, 1, 0);  
  87.       
  88.     layoutAttributes.transform3D = transform;  
  89.     if (indexPath.row == 0) {  
  90.         layoutAttributes.zIndex = NSIntegerMax;  
  91.     }  
  92.     return layoutAttributes;  
  93. }  
  94.   
  95.   
  96. //所有cell布局数组  
  97. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {  
  98.     NSMutableArray *array = [NSMutableArray array];  
  99.     for (NSUInteger i = 0; i < numberOfPages; i++) {  
  100.         NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];  
  101.         UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:index];  
  102.         if (attributes != nil) {  
  103.             [array addObject:attributes];  
  104.         }  
  105.     }  
  106.     return array;  
  107. }  
  108. @end  

当布局完成后,我们就大功告成了,在UICollectionView 中,实现代理和数据源就OK了

  1. #import "BookView.h"  
  2. #import "BookCell.h"  
  3. #import "BookLayout.h"  
  4. @implementation BookView  
  5. {  
  6.     NSMutableArray *_array;  
  7.     NSMutableArray *_arrayStr;  
  8. }  
  9.   
  10. static NSString *const reuseIdentifier = @"cell";  
  11. - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {  
  12.     self = [super initWithFrame:frame collectionViewLayout:layout];  
  13.     if (self) {  
  14.         self.backgroundColor = [UIColor clearColor];  
  15.         self.dataSource = self;  
  16.         self.delegate =self;  
  17.         [self registerClass:[BookCell class] forCellWithReuseIdentifier:reuseIdentifier];  
  18.         self.showsHorizontalScrollIndicator = NO;  
  19.           
  20.         _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",@""];  
  21.         _arrayStr = (NSMutableArray *)@[@"",@"",@"白羊座",@"金牛座",@"双子座",@"巨蟹座",@"狮子座",@"处女座",@"天平座",@"天蝎座",@"射手座",@"魔蝎座",@"水瓶座",@"双鱼座",@"",@""];  
  22.     }  
  23.     return self;  
  24. }  
  25.   
  26.   
  27. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {  
  28.     return 16;  
  29. }  
  30.   
  31.   
  32. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {  
  33.     BookCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];  
  34.     cell.imageView.image = [UIImage imageNamed:_array[indexPath.row]];  
  35.     cell.textLabel.text = [NSString stringWithFormat:@"%@", _arrayStr[indexPath.row]];  
  36.     cell.textLabel.font = [UIFont systemFontOfSize:12];  
  37.     cell.textLabel.textColor = [UIColor colorWithRed:148 / 255.0f green:0.0f blue:211 / 255.0f alpha:1.0f];  
  38.     return cell;  
  39. }  
  40. @end  

  1. #import "ViewController.h"  
  2. #import "BookView.h"  
  3. #import "BookLayout.h"  
  4. #define kScreenWidth [UIScreen mainScreen].bounds.size.width  
  5. #define kScreenHeight [UIScreen mainScreen].bounds.size.height  
  6.   
  7. @interface ViewController ()  
  8.   
  9. @end  
  10.   
  11. @implementation ViewController  
  12.   
  13. - (void)viewDidLoad {  
  14.     [super viewDidLoad];  
  15.       
  16.       
  17.     BookLayout *layout = [[BookLayout alloc] init];  
  18.     BookView *book = [[BookView alloc] initWithFrame:CGRectMake(10, 100, 300, 500) collectionViewLayout:layout];  
  19.     [self.view addSubview:book];  
  20. }  
  21.   
  22. @end  

是不是感觉不可思议!

代码下载地址:

http://download.csdn.net/download/et295394330/9122319

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多