ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo
    实现上我选择了使用UICollectionView ;用UICollectionViewFlowLayout来定制样式;下面看看具体实现

    效果

    实现上我选择了使用UICollectionView ;用UICollectionViewFlowLayout来定制样式;下面看看具体实现

    具体实现

    1、ViViewController.m 代码实现

    
    #import "ViewController.h"
    #import "CollModel.h"
    #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
    #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
    #define SCREEN_RATE ([UIScreen mainScreen].bounds.size.width/375.0)
    #import "imageCell.h"
    #import "LHHorizontalPageFlowlayout.h"
    static NSString * const imageC = @"imageCell";
    static NSString * const moreImageC = @"imageCell";
    static const NSInteger kItemCountPerRow = 5; //每行显示5个
    static const NSInteger kRowCount = 3; //每页显示行数
    static float imageHeight = 80;//cell 高度
    @interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>
    @property (nonatomic, strong) UICollectionView * collectionView;
    @property (nonatomic, strong) NSMutableArray * modelArray;
    @property (nonatomic, strong) UICollectionView * moreCollectionView;
    @end
    @implementation ViewController
    - (void)viewDidLoad {
     [super viewDidLoad];
     NSArray *appArray = [[self getDict] objectForKey:@"dictInfo"];
     for (int i = 0; i < appArray.count; i++) {
      NSDictionary * appDic = appArray[i];
      CollModel * model = [[CollModel alloc]init];
      model.title = [appDic objectForKey:@"title"];
      model.url = [appDic objectForKey:@"url"];
      [self.modelArray addObject:model];
     }
     [self createCollectionView];
     [self createRightCollectionView];
    }
    
    - (NSDictionary *)getDict {
     NSString * string = @"{\"dictInfo\":[{\"title\":\"你好啊\",\"url\":\"1.jpeg\"},{\"title\":\"你好啊\",\"url\":\"2.jpeg\"},{\"title\":\"你好啊\",\"url\":\"3.jpeg\"},{\"title\":\"你好啊\",\"url\":\"4.jpeg\"},{\"title\":\"你好啊\",\"url\":\"5.jpeg\"},{\"title\":\"你好啊\",\"url\":\"6.jpeg\"},{\"title\":\"是很好\",\"url\":\"7.jpeg\"},{\"title\":\"你好啊\",\"url\":\"1.jpeg\"},{\"title\":\"你好啊\",\"url\":\"2.jpeg\"},{\"title\":\"你好啊\",\"url\":\"3.jpeg\"},{\"title\":\"你好啊\",\"url\":\"4.jpeg\"},{\"title\":\"你好啊\",\"url\":\"5.jpeg\"},{\"title\":\"你好啊\",\"url\":\"6.jpeg\"},{\"title\":\"是很好\",\"url\":\"7.jpeg\"},{\"title\":\"你好啊\",\"url\":\"1.jpeg\"},{\"title\":\"你好啊\",\"url\":\"2.jpeg\"},{\"title\":\"你好啊\",\"url\":\"3.jpeg\"},{\"title\":\"你好啊\",\"url\":\"4.jpeg\"},{\"title\":\"你好啊\",\"url\":\"5.jpeg\"},{\"title\":\"你好啊\",\"url\":\"6.jpeg\"},{\"title\":\"是很好\",\"url\":\"7.jpeg\"}]}";
     NSDictionary *infoDic = [self dictionaryWithJsonString:string];
     return infoDic;
    }
    
    
    -(NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
     if (jsonString == nil) {
      return nil;
     }
     NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
     NSError *err;
     NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
     if(err)
     {
      NSLog(@"json解析失败:%@",err);
      return nil;
     }
     return dic;
    }
    
    - (NSMutableArray *)modelArray {
     if (!_modelArray) {
      _modelArray = [NSMutableArray array];
     }
     return _modelArray;
    }
    
    - (void)createCollectionView{
     UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init];
     layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
     layout.minimumLineSpacing = 0;
     layout.minimumInteritemSpacing = 0;
     _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, imageHeight * SCREEN_RATE) collectionViewLayout:layout];
     _collectionView.tag = 11;
     _collectionView.backgroundColor = [UIColor colorWithRed:186 / 255.0 green:186 / 255.0 blue:186 / 255.0 alpha:0.9];
     _collectionView.dataSource = self;
     _collectionView.delegate = self;
     _collectionView.bounces = NO;
     _collectionView.alwaysBounceHorizontal = YES;
     _collectionView.alwaysBounceVertical = NO;
     _collectionView.showsHorizontalScrollIndicator = NO;
     _collectionView.showsVerticalScrollIndicator = NO;
     [self.view addSubview:_collectionView];
     [_collectionView registerClass:[imageCell class] forCellWithReuseIdentifier:imageC];
    }
    
    - (void)createRightCollectionView{
     
     LHHorizontalPageFlowlayout * layout = [[LHHorizontalPageFlowlayout alloc] initWithRowCount:kRowCount itemCountPerRow:kItemCountPerRow];
     [layout setColumnSpacing:0 rowSpacing:0 edgeInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
     layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
     // UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
     // layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
     layout.minimumLineSpacing = 0;
     layout.minimumInteritemSpacing = 0;
     _moreCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 300, [UIScreen mainScreen].bounds.size.width, imageHeight * SCREEN_RATE * kRowCount) collectionViewLayout:layout];
     _moreCollectionView.backgroundColor = [UIColor clearColor];
     _moreCollectionView.tag = 22;
     _moreCollectionView.dataSource = self;
     _moreCollectionView.delegate = self;
     _moreCollectionView.bounces = NO;
     _moreCollectionView.alwaysBounceHorizontal = YES;
     _moreCollectionView.alwaysBounceVertical = NO;
     _moreCollectionView.backgroundColor = [UIColor colorWithRed:186 / 255.0 green:186 / 255.0 blue:186 / 255.0 alpha:0.9];
     _moreCollectionView.showsHorizontalScrollIndicator = NO;
     _moreCollectionView.showsVerticalScrollIndicator = NO;
     [self.view addSubview:_moreCollectionView];
     [_moreCollectionView registerClass:[imageCell class] forCellWithReuseIdentifier:moreImageC];
    }
    
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
     return self.modelArray.count;
    }
    
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
     CollModel * model = self.modelArray[indexPath.row];
     imageCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:imageC forIndexPath:indexPath];
     cell.itemModel = model;
     return cell;
    }
    
    // 返回每个item的大小
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
     CGFloat CWidth = imageHeight * SCREEN_RATE;
     CGFloat CHeight = imageHeight * SCREEN_RATE;
     return CGSizeMake(CWidth, CHeight);
    }
    
    #pragma mark - UICollectionViewDelegate点击事件
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
     CollModel * model = self.modelArray[indexPath.row];
     NSLog(@"self.appModelArray----%@",model.title);
    }
    
    
    - (void)didReceiveMemoryWarning {
     [super didReceiveMemoryWarning];
     // Dispose of any resources that can be recreated.
    }
    
    @end

    2、自定义UICollectionViewFlowLayout

    LHHorizontalPageFlowlayout.h 实现

    
    #import <UIKit/UIKit.h>
    @interface LHHorizontalPageFlowlayout : UICollectionViewFlowLayout
    /** 列间距 */
    @property (nonatomic, assign) CGFloat columnSpacing;
    /** 行间距 */
    @property (nonatomic, assign) CGFloat rowSpacing;
    /** collectionView的内边距 */
    @property (nonatomic, assign) UIEdgeInsets edgeInsets;
    
    /** 多少行 */
    @property (nonatomic, assign) NSInteger rowCount;
    /** 每行展示多少个item */
    @property (nonatomic, assign) NSInteger itemCountPerRow;
    
    //固定宽度
    @property (nonatomic, assign) CGFloat itemWidth; //设置完这个,就会自动计算列间距
    //固定高度
    @property (nonatomic, assign) CGFloat itemHight;//设置完这个,就会自动计算行间距
    
    /** 所有item的属性数组 */
    @property (nonatomic, strong) NSMutableArray *attributesArrayM;
    
    /** 设置行列间距及collectionView的内边距 */
    - (void)setColumnSpacing:(CGFloat)columnSpacing rowSpacing:(CGFloat)rowSpacing edgeInsets:(UIEdgeInsets)edgeInsets;
    /** 设置多少行及每行展示的item个数 */
    - (void)setRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow;
    
    #pragma mark - 构造方法
    /** 设置多少行及每行展示的item个数 */
    + (instancetype)horizontalPageFlowlayoutWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow;
    /** 设置多少行及每行展示的item个数 */
    - (instancetype)initWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow;
    
    @end

    LHHorizontalPageFlowlayout.m 实现

    
    #import "LHHorizontalPageFlowlayout.h"
    
    @implementation LHHorizontalPageFlowlayout
    
    #pragma mark - Public
    - (void)setColumnSpacing:(CGFloat)columnSpacing rowSpacing:(CGFloat)rowSpacing edgeInsets:(UIEdgeInsets)edgeInsets
    {
     self.columnSpacing = columnSpacing;
     self.rowSpacing = rowSpacing;
     self.edgeInsets = edgeInsets;
    }
    
    - (void)setRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow
    {
     self.rowCount = rowCount;
     self.itemCountPerRow = itemCountPerRow;
    }
    
    #pragma mark - 构造方法
    + (instancetype)horizontalPageFlowlayoutWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow
    {
     return [[self alloc] initWithRowCount:rowCount itemCountPerRow:itemCountPerRow];
    }
    
    - (instancetype)initWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow
    {
     self = [super init];
     if (self) {
      self.rowCount = rowCount;
      self.itemCountPerRow = itemCountPerRow;
     }
     return self;
    }
    
    
    #pragma mark - 重写父类方法
    - (instancetype)init
    {
     self = [super init];
     if (self) {
      [self setColumnSpacing:0 rowSpacing:0 edgeInsets:UIEdgeInsetsZero];
     }
     return self;
    }
    
    /** 布局前做一些准备工作 */
    - (void)prepareLayout
    {
     [super prepareLayout];
     if (self.attributesArrayM && self.attributesArrayM.count > 0) {
      [self.attributesArrayM removeAllObjects];
     }
     
     // 从collectionView中获取到有多少个item
     NSInteger itemTotalCount = [self.collectionView numberOfItemsInSection:0];
     
     // 遍历出item的attributes,把它添加到管理它的属性数组中去
     for (int i = 0; i < itemTotalCount; i++) {
      NSIndexPath *indexpath = [NSIndexPath indexPathForItem:i inSection:0];
      UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexpath];
      [self.attributesArrayM addObject:attributes];
     }
    }
    
    /** 计算collectionView的滚动范围 */
    - (CGSize)collectionViewContentSize
    {
     // 计算出item的宽度
     CGFloat itemWidth = (self.collectionView.frame.size.width - self.edgeInsets.left - self.itemCountPerRow * self.columnSpacing) / self.itemCountPerRow;
     // 从collectionView中获取到有多少个item
     NSInteger itemTotalCount = [self.collectionView numberOfItemsInSection:0];
     
     // 理论上每页展示的item数目
     NSInteger itemCount = self.rowCount * self.itemCountPerRow;
     // 余数(用于确定最后一页展示的item个数)
     NSInteger remainder = itemTotalCount % itemCount;
     // 除数(用于判断页数)
     NSInteger pageNumber = itemTotalCount / itemCount;
     // 总个数小于self.rowCount * self.itemCountPerRow
     if (itemTotalCount <= itemCount) {
      pageNumber = 1;
     }else {
      if (remainder == 0) {
       pageNumber = pageNumber;
      }else {
       // 余数不为0,除数加1
       pageNumber = pageNumber + 1;
      }
     }
     
     CGFloat width = 0;
     // 考虑特殊情况(当item的总个数不是self.rowCount * self.itemCountPerRow的整数倍,并且余数小于每行展示的个数的时候)
     if (pageNumber > 1 && remainder != 0 && remainder < self.itemCountPerRow) {
      width = self.edgeInsets.left + (pageNumber - 1) * self.itemCountPerRow * (itemWidth + self.columnSpacing) + remainder * itemWidth + (remainder - 1)*self.columnSpacing + self.edgeInsets.right;
     }else {
      width = self.edgeInsets.left + pageNumber * self.itemCountPerRow * (itemWidth + self.columnSpacing) - self.columnSpacing + self.edgeInsets.right;
     }
     
     // 只支持水平方向上的滚动
     return CGSizeMake(width, 150);
    }
    
    /** 设置每个item的属性(主要是frame) */
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
    {
     // item的宽高由行列间距和collectionView的内边距决定
     CGFloat itemWidth = (self.collectionView.frame.size.width) / self.itemCountPerRow;
     CGFloat itemHeight = (self.collectionView.frame.size.height) / self.rowCount;
     
     NSInteger item = indexPath.item;
     // 当前item所在的页
     NSInteger pageNumber = item / (self.rowCount * self.itemCountPerRow);
     NSInteger x = item % self.itemCountPerRow + pageNumber * self.itemCountPerRow;
     NSInteger y = item / self.itemCountPerRow - pageNumber * self.rowCount;
     
     // 计算出item的坐标
     CGFloat itemX = itemWidth * x;
     CGFloat itemY = itemHeight * y;
     
     UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
     // 每个item的frame
     attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);
     
     return attributes;
    }
    
    /** 返回collectionView视图中所有视图的属性数组 */
    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
    {
     return self.attributesArrayM;
    }
    
    
    #pragma mark - Lazy
    - (NSMutableArray *)attributesArrayM
    {
     if (!_attributesArrayM) {
      _attributesArrayM = [NSMutableArray array];
     }
     return _attributesArrayM;
    }
    @end

    4、自定义cell 和model

    model

    
    #import <Foundation/Foundation.h>
    
    @interface CollModel : NSObject
    @property (nonatomic,strong)NSString *imgUrl;
    @property (nonatomic,strong)NSString *title;
    @property (nonatomic,strong)NSString *url;
    @end

    cell 自定义

    
    #import "imageCell.h"
    // 屏幕比例
    #define SCREEN_RATE  ([UIScreen mainScreen].bounds.size.width/375.0)
    
    @interface imageCell()
    @property (nonatomic, strong) UIImageView *itemIcon;
    @end
    
    @implementation imageCell
    
    @synthesize itemModel = _itemModel;
    
    - (instancetype)initWithFrame:(CGRect)frame{
     if (self = [super initWithFrame:frame]) {
      self.contentView.backgroundColor = [UIColor clearColor];
      [self initView];
     }
     return self;
    }
    
    - (void)initView{
     _itemIcon = [[UIImageView alloc] init];
     [self.contentView addSubview:_itemIcon];
     _itemIcon.backgroundColor = [UIColor clearColor];
     CGFloat iconWidth = 80 * SCREEN_RATE;
     _itemIcon.frame = CGRectMake(0, 0, iconWidth, iconWidth);
     _itemIcon.center = self.contentView.center;
    }
    
    - (CollModel *)itemModel{
     return _itemModel;
    }
    
    - (void)setItemModel:(CollModel *)itemModel
    {
     if (!itemModel) {
      return;
     }
     _itemModel = itemModel;
     
     [self setCellWithModel:_itemModel];
    }
    
    - (void)setCellWithModel:(CollModel *)itemModel{
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
      _itemIcon.image = [UIImage imageNamed:itemModel.url];
     }];
    }

    下载:ios uicollectionview横向滚动

    GitHub下载

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持lingkb。