UICollectionView自定义布局(二)
这是UICollectionView
自定义布局的第二篇,实现类似UltravisualApp的视差效果,同样这篇文章的教程来自Ray家的Swift Expanding Cells in iOS Collection Views这篇文章。
自定义布局
将该动画分解,首先实现如下图所示的效果。
随着CollectionView的滑动,itermCell
的frame
的变化如下图所示:
itermCell
分为三种类型:- FeaturedCell : 突出显示的cell,高度为
featuredHeight
。 - StandardCell : 标准状态下的cell,高度为
standardHeight
。 - ChangedCell : 高度随着
contentOffSet
改变而改变的cell,高度的变化范围在standardHeight和featuredHeight之间。(FeaturedCell下面的那个cell)
1.获取FeaturedCell的索引
- (int)featuredItemIndex{ int index = (int)(self.collectionView.contentOffset.y / self.dragOffset); return MAX(0, index); }
self.dragOffset
是拖拽距离(当偏移量大于这个值时,featuredItemIndex的索引会变为下一个)。由当前FeaturedCell
的索引index可以获得ChangedCell
的索引为index+1,进而得到其他的索引位置就是StandardCell
。
2.重写prepareLayout方法
随着collectionView的滑动,standardCell 变化为 featuredCell,变化范围为[0 ,1]。
- (CGFloat)nextItemPercentageOffset{ CGFloat percent = (self.collectionView.contentOffset.y / self.dragOffset) - [self featuredItemIndex]; return percent; }
attribute.zIndex
的值随着iterm的增加逐渐增大,形成上图所示的覆盖效果。ChangedCell
的高度随着偏移距离,由standardHeight
变化为featuredHeight
。- 从视觉上看由
StandardCell
变为FeaturedCell
只移动了standardHeight
的距离,但是实际上contentOffSet.y
移动的距离大于这个值,实际上移动了self.dragOffset
才能完成这个变换。 - 详细的代码如下所示。
- (void)prepareLayout{ [super prepareLayout]; [self.attributesArray removeAllObjects]; CGRect frame = CGRectZero; CGFloat y = 0; NSInteger numberOfIterm = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i < numberOfIterm; i++) { NSIndexPath *path = [NSIndexPath indexPathForItem:i inSection:0]; UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path]; /*下一个cell都在之前的cell之上*/ attribute.zIndex = path.item; /*初始化时设置cell的高度都为标准高度*/ CGFloat height = standardHeight; if (path.item == [self featuredItemIndex]) { /*featured Cell*/ CGFloat yOffSet = standardHeight * [self nextItemPercentageOffset]; y = self.collectionView.contentOffset.y - yOffSet; height = featuredHeight; }else if (path.item == [self featuredItemIndex] + 1 && path.item != numberOfIterm){ /*在featuredCell之下,随着用户滚动逐渐变大*/ CGFloat maxY = y + standardHeight; height = standardHeight + MAX((featuredHeight - standardHeight) * [self nextItemPercentageOffset], 0); y = maxY - height; } frame = CGRectMake(0, y, CGRectGetWidth(self.collectionView.bounds), height); attribute.frame = frame; [self.attributesArray addObject:attribute]; /*获取下一个cell的初始的Y值*/ y = CGRectGetMaxY(frame); } //重新刷新collectionView,不然数据会错乱 [self.collectionView reloadData]; }
3.改变滚动停止时的位置
当itermCell
滚动的时候,将其停在固定的点。使其滚动停止时,屏幕显示的第一个cell永远是FeaturedCell
。
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{ NSInteger currentFeaturedIndex = round(proposedContentOffset.y / self.dragOffset); CGFloat yOffSet = currentFeaturedIndex * self.dragOffset; return CGPointMake(0, yOffSet); }
添加图片背景和详情内容
图片和文本的创建代码比较简单就不列出了,需要注意的是:
UIImageView
的contentMode
设置为UIViewContentModeScaleAspectFill
。并且设置layer.masksToBounds = YES
。- 一定要使用自动布局否则会显示不正常。
重写applyLayoutAttributes
- 根据偏移量改变黑色
CoverView
的背景色,突出显示FeaturedCell
。 - 根据偏移量对
titleLabel
进行仿射变换。 - 根据偏移量对
detailLabel
进行透明度变化,只有当前cell是FeaturedCell
的时候才显示。
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes{ [super applyLayoutAttributes:layoutAttributes]; CGFloat standardHeight = 100.0; CGFloat featuredHeight = 280.0; /*根据移动距离改变CoverView透明度*/ CGFloat factor = 1 - (featuredHeight - CGRectGetHeight(layoutAttributes.frame))/(featuredHeight - standardHeight); CGFloat minAlpha = 0.2; CGFloat maxAlpha = 0.75; CGFloat currentAlpha = maxAlpha - (maxAlpha - minAlpha) * factor; self.coverView.alpha = currentAlpha; /*改变字体大小*/ CGFloat titleScale = MAX(0.5, factor); self.titleLabel.transform = CGAffineTransformMakeScale(titleScale, titleScale); /*设置detailLabel的透明度*/ self.timeAndRoomLabel.alpha = factor; self.speakerLabel.alpha = factor; }
至此,自定义布局就全部完成了,Demo链接可以到GitHub下载。
相关推荐
lijiexiaoge 2019-06-29
binglechen 2016-06-07
fanxiaoxuan 2014-04-08
稀土 2018-01-31
郎启旭的写字本 2017-12-28
元宝酱拯救地球 2017-11-29
软件设计 2017-03-25
手机开发 2017-03-10