美文网首页视图控件
iOS 使用UICollectionView封装实现卡片式Vie

iOS 使用UICollectionView封装实现卡片式Vie

作者: 翻滚着的牛宝宝 | 来源:发表于2016-06-07 21:51 被阅读4247次

    目前APP中卡片布局方式非常常见,例如:淘宝、支付宝、百度地图等均有使用。


    淘宝截图

    作为一名苦逼程序猿,不知大家写过了多少卡片布局。写的多了,自然就想如何封装一下,以方便之后更好的复用。考虑到复用,我们必须能够做到以下几点:

    1. 具有足够的灵活性,每个卡片内部一定是可定制的,so,我们的封装应该是不care内容的;
    2. 需要考虑性能,卡片一般会放在tableview中,因此在tableview滑动过程中,有部分卡片会出现、隐藏,考虑到性能问题,我们最好支持卡片每项的复用;
    3. 卡片的每行列数应该支持外部设置,同事根据卡片总数量调整整体View的布局。

    基于以上几点,我考虑使用UICollectionView来封装。可能很多人面对这样的需求会考虑使用for循环,add每一个卡片,这样固然简单,但这样就没办法复用,如果整个页面多出出现这样的布局,对性能消耗也是不小的。话不多说,上代码:
    #import <UIKit/UIKit.h>

    @class GNColGridView;
    
    //用collectionView实现
    
    @protocol GNColGridViewDelegagte <NSObject>
    
    @required
    //每行的高度
    - (CGFloat)heightForRowInGridView:(GNColGridView *)gridView;
    //gridView列的数量
    - (NSInteger)numberOfColumsInGridView:(GNColGridView *)gridView;
    //gridView中item总量
    - (NSInteger)totolNumberOfGridView:(GNColGridView *)gridView;
    //返回每个item
    - (GNButton *)gridView:(GNColGridView *)gridView gridAtIndex:(NSInteger)index;
      @optional
      //item点击事件
    - (void)gridView:(GNColGridView *)gridView onItemClick:(NSInteger)index;
    
    @end
    
    
    @interface GNColGridView : UIView
    
    @property (nonatomic, weak) id<GNColGridViewDelegagte> delegate;
    
    - (void)reLoadData;
    
    @end
    

    上面是对外暴露的接口,接口封装还是比较清晰的。【注:GNButton是我Demo工程中对UIButton的封装,读者把他当成UIButton就行】


    下面是具体的实现:
    #import "GNColGridView.h"

    #define kGNCOLGRIDVIEWID @"GNCOLGRIDVIEWID"
    
    @protocol GNColGridViewLayoutDelegate <NSObject>
    
    - (NSInteger)numberOfColums;
    - (NSInteger)totolNumber;
    - (CGFloat)height;
    
    @end
    
    @interface GNColGridViewLayout : UICollectionViewFlowLayout
    
    @property (nonatomic, weak) id<GNColGridViewLayoutDelegate> delegate;
    @property (nonatomic, assign) NSInteger col;
    @property (nonatomic, assign) NSInteger sum;
    @property (nonatomic, assign) CGFloat height; //每行高度
    
    @end
    
    @implementation GNColGridViewLayout
    
    - (NSInteger)col {
        if (_delegate && [_delegate respondsToSelector:@selector(numberOfColums)]) {
            return [_delegate numberOfColums];
    }
        return 0;
    }
    
    - (NSInteger)sum {
        if (_delegate && [_delegate respondsToSelector:@selector(totolNumber)]) {
            return [_delegate totolNumber];
        }
    return 0;
    }
    
    - (CGFloat)height {
        if (_delegate && [_delegate respondsToSelector:@selector(height)]) {
            return [_delegate height];
        }
        return 0;
    }
    
    - (CGSize)collectionViewContentSize {
        if (self.col <= 0) {
            return CGSizeZero;
        }
    
        NSInteger row = self.sum / self.col + ((self.sum % self.col) > 0 ? 1: 0);
        CGFloat width = SCREEN_WIDTH;
        CGFloat height = self.height * row;
        return CGSizeMake(width, height);
    }
    
    - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
        return YES;
    }
    - (void)prepareLayout
    {
        [super prepareLayout];
    }
    
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
        UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
        if (self.col <= 0) {
            return attributes;
        }
        CGFloat itemWidth = SCREEN_WIDTH / self.col;
        attributes.center =  CGPointMake((indexPath.row % self.col + 0.5) * itemWidth, self.height * (indexPath.row / self.col + 0.5));
        attributes.size = CGSizeMake(itemWidth, self.height);
        attributes.indexPath = indexPath;
        return attributes;
    }
    
    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
        NSArray *array = [super layoutAttributesForElementsInRect:rect];
        NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:5];
        for (int i = 0; i < [array count]; i ++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
            [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
        }
    return attributes;
    }
    
    @end
    
    
    @interface GNColGridView () <UICollectionViewDataSource, UICollectionViewDelegate, GNColGridViewLayoutDelegate>
    
    @property (nonatomic, strong) UICollectionView *collectionView;
    
    @end
    
    @implementation GNColGridView
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self initUI];
        }
        return self;
    }
    
    - (void)layoutSubviews {
        [super layoutSubviews];
    }
    
    - (void)initUI {
        GNColGridViewLayout *layout = [[GNColGridViewLayout alloc] init];
        [layout setDelegate:self];
        self.collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:layout];
        _collectionView.dataSource = self;
        _collectionView.delegate = self;
        [_collectionView setBackgroundColor:[UIColor clearColor]];
        [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kGNCOLGRIDVIEWID];
        [self addSubview:_collectionView];
    }
    
    #pragma mark - UICollectionViewDataSource
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
        NSInteger sum = 0;
        if (_delegate && [_delegate respondsToSelector:@selector(totolNumberOfGridView:)]) {
            sum = [_delegate totolNumberOfGridView:self];
        }
        return sum;
    }
    
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath   {
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kGNCOLGRIDVIEWID forIndexPath:indexPath];
        if (_delegate && [_delegate respondsToSelector:@selector(gridView:gridAtIndex:)]) {
            for (UIView *subView in cell.contentView.subviews) {
                if (subView.subviews) {
                    [subView removeFromSuperview];
                }
            }
            GNButton *view = [GNButton new];
            view = [_delegate gridView:self gridAtIndex:indexPath.row];
            view.tag = indexPath.row;
            [view addTarget:self action:@selector(onItemClick:) forControlEvents:UIControlEventTouchUpInside];
            view.centerX = cell.width / 2;
            view.centerY = cell.height / 2;
            [cell.contentView addSubview:view];
        }
        return cell;
    }
    
    #pragma mark - GNColGridViewLayoutDelegate
    - (NSInteger)numberOfColums {
        if (_delegate && [_delegate respondsToSelector:@selector(numberOfColumsInGridView:)]) {
            return [_delegate numberOfColumsInGridView:self];
        }
        return 0;
    }
    
    - (NSInteger)totolNumber {
        if (_delegate && [_delegate respondsToSelector:@selector(totolNumberOfGridView:)]) {
            return [_delegate totolNumberOfGridView:self];
        }
        return 0;
    }
    
    - (CGFloat)height {
        if (_delegate && [_delegate respondsToSelector:@selector(heightForRowInGridView:)]) {
            return [_delegate heightForRowInGridView:self];
        }
        return 0.0;
    }
    
    #pragma mark - action
    - (void)onItemClick:(GNButton*) button{
        if (_delegate && [_delegate respondsToSelector:@selector(gridView:onItemClick:)]) {
            [_delegate gridView:self onItemClick:button.tag];
        }
    }
    
    #pragma mark - public
    - (void)reLoadData {
        NSInteger row = [self totolNumber] / [self numberOfColums] + (([self totolNumber] % [self numberOfColums]) > 0 ? 1: 0);
        CGFloat width = SCREEN_WIDTH;
        CGFloat height = self.height * row;
        _collectionView.height = height;
        [_collectionView reloadData];
    }
    
    @end
    

    代码地址:
    https://git.oschina.net/youxibar/youxibar_iOS.git

    相关文章

      网友评论

        本文标题:iOS 使用UICollectionView封装实现卡片式Vie

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