美文网首页
仿支付宝财富直通车通用组件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