美文网首页
仿支付宝财富直通车通用组件GLFreePagingLayout

仿支付宝财富直通车通用组件GLFreePagingLayout

作者: 格雷s | 来源:发表于2019-05-08 18:25 被阅读0次

由于在项目开发过程中,经常会遇到app仿'支付宝的财富直通车'效果,本项目是直通车的升级版本,支持自定义滑动speed居中对齐最大允许惯性滑动page数自定义分页宽度

1.直通车控件特性

  • cell宽度 < collectionView的Width
  • 滑块在最左边或者最右边时,不用居中
  • 滑动到其他位置,选择居中对齐

2.实现思路

自定义UICollectionViewFlowLayout,通过重写targetContentOffsetForProposedContentOffset:withScrollingVelocity:方法,该方法的返回值为最终scrollview的contentOffset,如果不通过collectionView实现,同样可以补货scrollView的代理方法scrollViewWillEndDragging:withVelocity:targetContentOffset:,下面我们看看自定义layout:
GLFreePagingLayout.h

@protocol GLFreePagingLayoutDelegate <NSObject>
- (void)targetCenterIndexPathForProposedIndexPath:(NSIndexPath *)indexpath;
@end

@interface GLFreePagingLayout : UICollectionViewFlowLayout
@property (nonatomic, weak) id<GLFreePagingLayoutDelegate> delegate;
/** speed 0~1.f,惯性大小,默认为1 */
@property (nonatomic, assign) CGFloat speed;
/** 居中对其 */
@property (nonatomic, assign) BOOL centerOn;
/** 开启居中对齐,在惯性作用下,松手后最大允许滑动的page数,可同时和speed作用,默认maxInertialCount为MAX */
@property (nonatomic, assign) NSInteger maxInertialCount;
/**
 分页的宽度pageWidth,
 1.在居中对齐情况下,如果依赖惯性滑动的距离>pageWidth * 0.5,那么就选择下一个cell对齐
 2.默认pageWidth为collectionView的Width
 */
@property (nonatomic, assign) CGFloat pageWidth;
@end

GLFreePagingLayout.m

@implementation GLFreePagingLayout

- (instancetype)init {
    self = [super init];
    if (self) {
        self.speed = 1.f;
        self.maxInertialCount = NSIntegerMax;
    }
    return self;
}

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
    // 保证滚动结束后视图的显示效果
    if (self.collectionView.contentOffset.x < 0) {
        [self scrollCenterToIndex:[NSIndexPath indexPathForRow:0 inSection:0]];
        return proposedContentOffset;
    }
    
    if (self.collectionView.contentOffset.x > [super collectionViewContentSize].width - self.collectionView.frame.size.width) {
        if (self.delegate && [self.delegate respondsToSelector:@selector(targetCenterIndexPathForProposedIndexPath:)]) {
            NSInteger count = [self.collectionView numberOfItemsInSection:0];
            [self scrollCenterToIndex:[NSIndexPath indexPathForRow:count - 1 inSection:0]];
        }
        return proposedContentOffset;
    }
    //在speed作用下的proposedContentOffset
    CGFloat tmp = proposedContentOffset.x - self.collectionView.contentOffset.x;
    tmp = tmp * self.speed;
    proposedContentOffset.x = self.collectionView.contentOffset.x + tmp;
    //如果没有开启居中对齐
    if (!self.centerOn) {
        return proposedContentOffset;
    }
    
    // 计算出最终显示的矩形框
    CGRect rect;
    rect.origin.y = 0;
    rect.origin.x = proposedContentOffset.x;
    rect.size = self.collectionView.frame.size;
    
    if (self.pageWidth == 0) {
        self.pageWidth = self.collectionView.frame.size.width;
    }
    CGFloat autoOffset = (self.maxInertialCount - 0.5) * self.pageWidth;
    if (ABS(tmp) > autoOffset) {
        rect = CGRectMake(self.collectionView.contentOffset.x + autoOffset * (tmp > 0 ? 1 : -1), proposedContentOffset.y, self.collectionView.frame.size.width, self.collectionView.frame.size.height);
    }
    
    // 获得 super 已经计算好的布局的属性
    NSArray *arr = [super layoutAttributesForElementsInRect:rect];
    
    // 计算 collectionView 最中心点的 x 值
    CGFloat centerX = rect.origin.x + self.collectionView.frame.size.width * 0.5;
    
    CGFloat minDelta = MAXFLOAT;
    NSIndexPath *indexPath = nil;
    for (UICollectionViewLayoutAttributes *attrs in arr) {
        //cell视图
        if (attrs.representedElementCategory == UICollectionElementCategoryCell && ABS(minDelta) > ABS(attrs.center.x - centerX)) {
            minDelta = attrs.center.x - centerX;
            indexPath = attrs.indexPath;
        }
    }
    [self scrollCenterToIndex:indexPath];
    
    return CGPointMake(rect.origin.x + minDelta, rect.origin.y);
}
//添加滚动动画
- (void)scrollCenterToIndex:(NSIndexPath *)indexPath {
    if (self.delegate && [self.delegate respondsToSelector:@selector(targetCenterIndexPathForProposedIndexPath:)]) {
        [self.delegate performSelector:@selector(targetCenterIndexPathForProposedIndexPath:) withObject:indexPath];
    }
}

@end

3.Demo展示

        GLFreePagingLayout *layout = [[GLFreePagingLayout alloc] init];
        //开启居中对齐
        layout.centerOn = YES;
        //松手后惯性系数
        layout.speed = 0.3;
        //松手后最大滚动cell个数
        layout.maxInertialCount = 2;
        //分页宽度
        layout.pageWidth = 300;
        layout.delegate = self;
        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 400, self.view.frame.size.width, 200) collectionViewLayout:layout];
        [_collectionView registerClass:UICollectionViewCell.class forCellWithReuseIdentifier:NSStringFromClass(UICollectionViewCell.class)];
        _collectionView.backgroundColor = [UIColor redColor];
        _collectionView.delegate = self;
        _collectionView.dataSource = self;
image.png image.png

4.项目地址

相关文章

网友评论

      本文标题:仿支付宝财富直通车通用组件GLFreePagingLayout

      本文链接:https://www.haomeiwen.com/subject/novvoqtx.html