Collectionview自定义布局
来源:互联网 发布:微信 java版 编辑:程序博客网 时间:2024/06/05 17:43
我们平时经常见到一些很酷的滚动效果,卡片式的堆叠效果、瀑布流、单元格移动等,这些炫酷的效果我们可以通过collectionview自定义布局来实现。
继承UICollectionViewLayout
我们自定义layout,需要继承UICollectionViewLayout,有一些核心方法需要我们来实现,这些核心方法可以帮助我们来完成布局任务。
prepareLayout
方法,为布局计算做一些准备工作;collectionViewContentSize
方法,返回内容区域的size;layoutAttributesForElementsInRect:
方法,返回矩形区域内cells或者views的属性;
说明图片:
示例代码
创建自定义布局类
collectionViewLayout.h 文件
interface collectionViewLayout : UICollectionViewLayoutproperty (nonatomic) CGSize itemSize;@property (nonatomic) NSInteger visibleCount;@property (nonatomic) UICollectionViewScrollDirection scrollDirection;@end
collectionViewLayout.m 文件
#import "collectionViewLayout.h"#define INTERSPACEPARAM 0.65@interface collectionViewLayout (){ CGFloat _viewHeight; CGFloat _itemHeight;}@end
//为自定义布局做准备工作,确定滚动区域大小-(void)prepareLayout { [super prepareLayout]; if (self.visibleCount < 1) { self.visibleCount = 5; } _viewHeight = CGRectGetWidth(self.collectionView.frame); _itemHeight = self.itemSize.width; self.collectionView.contentInset = UIEdgeInsetsMake(0, (_viewHeight - _itemHeight) / 2, 0, (_viewHeight - _itemHeight) / 2); self.collectionView.showsHorizontalScrollIndicator = NO; self.collectionView.showsVerticalScrollIndicator = NO;}
//处理现实区域布局属性-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { NSInteger cellCount = [self.collectionView numberOfItemsInSection:0]; CGFloat centerY = self.collectionView.contentOffset.x + _viewHeight / 2; NSInteger index = centerY / _itemHeight; NSInteger count = (self.visibleCount - 1) / 2; NSInteger minIndex = MAX(0, (index - count)); NSInteger maxIndex = MIN((cellCount - 1), (index + count)); NSMutableArray *array = [NSMutableArray array]; for (NSInteger i = minIndex; i <= maxIndex; i++) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath]; [array addObject:attributes]; } return array;}
//此方法可以立即获取某一布局属性- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attributes.size = self.itemSize; CGFloat cY = self.collectionView.contentOffset.x + _viewHeight / 2; CGFloat attributesY = _itemHeight * indexPath.row + _itemHeight / 2; attributes.zIndex = -ABS(attributesY - cY); CGFloat delta = cY - attributesY; CGFloat ratio = - delta / (_itemHeight * 2); CGFloat scale = 1 - ABS(delta) / (_itemHeight * 6.0) * cos(ratio * M_PI_4); attributes.transform = CGAffineTransformMakeScale(scale, scale); CGFloat centerY = attributesY; centerY = cY + sin(ratio * M_PI_2) * _itemHeight * INTERSPACEPARAM; attributes.center = CGPointMake(centerY, CGRectGetHeight(self.collectionView.frame) / 2); return attributes;}
//这个方法的返回值,就决定了collectionView停止滚动时的偏移量- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { CGFloat index = roundf((proposedContentOffset.x + _viewHeight / 2 - _itemHeight / 2) / _itemHeight); proposedContentOffset.x = _itemHeight * index + _itemHeight / 2 - _viewHeight / 2; return proposedContentOffset;}
//这个方法的返回值,决定了当collectionview的显示范围发生改变的时候,是否需要刷新布局- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return !CGRectEqualToRect(newBounds, self.collectionView.bounds);}
使用自定义布局
ViewController.m
#import "CollectionCell.h"#import "collectionViewLayout.h"@interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate>@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;@property (strong, nonatomic) NSArray * imageArray;@end
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. _imageArray = @[@"p4.jpg",@"p0.jpg",@"p1.jpg",@"p2.jpg",@"p3.jpg",@"p4.jpg",@"p0.jpg",@"p1.jpg"]; collectionViewLayout * layout = [[collectionViewLayout alloc] init]; layout.itemSize = CGSizeMake(250, 160); layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; _collectionView.frame = CGRectMake(0, 100, self.view.frame.size.width, layout.itemSize.height); _collectionView.backgroundColor = [UIColor grayColor]; [self.collectionView setCollectionViewLayout:layout animated:YES]; _collectionView.delegate = self; _collectionView.dataSource = self;}-(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; //使collectionview默认滑动到第二张图片位置 _collectionView.contentOffset = CGPointMake(250, 0);}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return _imageArray.count;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionCell" forIndexPath:indexPath]; cell.imageView.image = [UIImage imageNamed:_imageArray[indexPath.row]]; return cell;}- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath { NSIndexPath *curIndexPath = [self curIndexPath]; if (indexPath.row == curIndexPath.row) { return YES; } NSLog(@"current row %ld",(long)indexPath.row); [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES]; return NO;}//获取当前点击的IndexPath- (NSIndexPath *)curIndexPath { NSArray *indexPaths = [self.collectionView indexPathsForVisibleItems]; NSIndexPath *curIndexPath = nil; NSInteger curzIndex = 0; for (NSIndexPath *path in indexPaths.objectEnumerator) { UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:path]; if (!curIndexPath) { curIndexPath = path; curzIndex = attributes.zIndex; continue; } if (attributes.zIndex > curzIndex) { curIndexPath = path; curzIndex = attributes.zIndex; } } return curIndexPath;}
//实现无限循环滚动-(void)scrollViewDidScroll:(UIScrollView *)scrollView{ if (scrollView.contentOffset.x<=250) { scrollView.contentOffset = CGPointMake(5*250+scrollView.contentOffset.x, 0); } if (scrollView.contentOffset.x > (_imageArray.count - 2)*250) { scrollView.contentOffset = CGPointMake(250+scrollView.contentOffset.x-(_imageArray.count - 2)*250, 0); }}
效果如下:
本示例还存在一个问题,就是点击非焦点cell时不能使其很好的滚动到中间位置,望大神们指点一下。
1 0
- CollectionView自定义布局
- Collectionview自定义布局
- CollectionView自定义布局
- 整理 collectionView 水平自定义布局
- 一个简单的collectionView自定义布局
- 一分钟学会collectionView自定义layout(二、圆形布局)
- iOS-CollectionView流水布局
- IOS CollectionView 线性布局
- 自定义重排的CollectionView
- swift 自定义collectionView
- 整理 collectionView 瀑布流 布局
- 手写CollectionView并调整布局
- 自定义TableViewCell里嵌套CollectionView
- swift CollectionView写一个多section布局
- collectionview 集合视图流式布局
- collectionView布局原理及瀑布流布…
- CollectionView
- collectionView
- 实战X86寄存器
- Delphi 停靠技术的应用3(两个窗体停靠成PageControl样式, 分页停靠)
- swift基础之UIAnimation 动画(手势操作)
- 开源 java CMS - FreeCMS2.4 信息管理
- iii
- Collectionview自定义布局
- 13.3节练习
- 第9周课后实践1-②
- Delphi 停靠技术的应用2(窗体之间的相互停靠,引入宿主窗体)
- 数据库中候选键的确定
- Delphi 停靠技术的应用1(在一个窗体中停靠另一个窗体)
- Isomorphic Strings - Javacript
- Java异常的另类用法(一)
- [6.15] 心态 信念