简介
效果:滚动到中间的时候最大,距离中间越远越小.
思路:实现这样的效果,我们首先要选对UI组件,这里我选择使用UICollectionView
,而它的布局主要是依靠其flowLayout,所以我决定自定义FlowLayout实现该效果.
步骤
自定义WYCollectionViewFlowLayout
继承自UICollectionViewFlowLayout
重写3个布局方法
@interface WYCollectionViewFlowLayout : UICollectionViewFlowLayout
@end
@implementation WYCollectionViewFlowLayout
// 这个方法返回所有的布局所需对象,瀑布流也可以重写这个方法实现.
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
// 1.获取cell对应的attributes对象
NSArray *arrayAttrs = [super layoutAttributesForElementsInRect:rect];
// 2.计算整体的中心点的x值
CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.bounds.size.width * 0.5;
// 3.修改一下attributes对象
for (UICollectionViewLayoutAttributes *attr in arrayAttrs) {
// 3.1 计算每个cell的中心点距离
CGFloat distance = ABS(attr.center.x - centerX);
// 3.2 距离越大,缩放比越小,距离越小,缩放比越大
CGFloat factor = 0.003;
CGFloat scale = 1 / (1 + distance * factor);
attr.transform = CGAffineTransformMakeScale(scale, scale);
}
return arrayAttrs;
}
// 当bounds发生改变的时候需要重新布局
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return true;
}
/// 滑动停止
///
/// @param proposedContentOffset 当手指滚动完毕后,自然情况下根据“惯性”,会停留的位置
/// @param velocity 速率,周率
///
/// @return 人为要让它停留的位置
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
// 1.计算中心点位置
CGFloat centerX = proposedContentOffset.x + self.collectionView.bounds.size.width * 0.5;
// 2.计算可视化区域
CGFloat visibleX = proposedContentOffset.x;
CGFloat visibleY = proposedContentOffset.y;
CGFloat visibleW = APP_WIDTH;
CGFloat visibleH = self.collectionView.bounds.size.height;
CGRect visibleRect = CGRectMake(visibleX, visibleY, visibleW, visibleH);
// 3.获取可视区域的cell的attribute对象
NSArray *attrs = [self layoutAttributesForElementsInRect:visibleRect];
// 4.比较出最小的偏移
int min_idx = 0;
UICollectionViewLayoutAttributes *min_attr = attrs[min_idx];
// 5.循环比较出最小的
for (int i = 1; i< attrs.count; i++){
// 5.1min_attr和中心点的距离
CGFloat distance1 = ABS(min_attr.center.x - centerX);
// 5.2当前循环的attr和中心点的距离
UICollectionViewLayoutAttributes *currentAttr = attrs[i];
CGFloat distance2 = ABS(currentAttr.center.x - centerX);
if (distance2 < distance1) {
min_idx = i;
min_attr = currentAttr;
}
}
// 6.计算出最小的偏移值
CGFloat offsetX = min_attr.center.x - centerX;
return CGPointMake(proposedContentOffset.x + offsetX, proposedContentOffset.y);
}
@end
然后在初始化UICollectionView
的时候,设置其流水布局collectionViewLayout
为我们自定义的WYCollectionViewFlowLayout
即可实现滚动的放大缩小了.