当前位置: 首页 > article >正文

UICollectionView 实现整页翻动(每页3个cell)

提示:页面架构是通过UICollectionView做的分页,分页点PageControl使用的是<SDCycleScrollView/TAPageControl.h> ,布局架构使用的是Masonry


前言

为了实现UICollectionView无限翻动,连续滑动,主要是利用pagingEnabled属性,配合 UIScrollViewDelegate的代理方法来实现的。


一、准备列表数据和计算思路

1.数据源的创建(9个元素,作为数据源),目的是让翻页效果是3页。

最终达到效果:

2. 思路:通过设置轮播倍数目的是通过建立多个section来实现轮播联动在最后一次循环从头开始排序达到循环播放。

二、使用步骤

1.初始化尺寸数据准备

代码如下(示例):

static CGFloat const Cell_Height = 174;
static CGFloat const PageDot_Height = 30;

// 轮播倍数Num
static const int kLoopMaxMultiple = 4;
-(void)setArr_data:(NSMutableArray *)arr_data{
    _arr_data = arr_data;
    self.pageControl.numberOfPages = arr_data.count%3==0?arr_data.count/3:(arr_data.count/3+1);
    self.pageControl.currentPage = 0;
    [self.mainCV reloadData];
}

2.绘画view

代码如下(示例):

- (void)drawView {
    self.backgroundColor = [UIColor clearColor];
    CGFloat img_w = (SCREEN_WIDTH - 15 * 4) / 3.0;

    [self addSubview:self.bkgView];
    self.bkgView.backgroundColor = [UIColor clearColor];
    [self.bkgView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.top.right.mas_equalTo(self);
        make.height.mas_equalTo(Cell_Height+PageDot_Height);
    }];

    //collectionview
    [self.bkgView addSubview:self.mainCV];
    self.mainCV.delegate = self;
    self.mainCV.dataSource = self;
    [self.mainCV mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.bkgView.mas_top);
        make.left.mas_equalTo(self.bkgView.mas_left).mas_offset(15);
        make.right.mas_equalTo(self.bkgView.mas_right).mas_offset(-0);
        make.height.mas_equalTo(Cell_Height);
    }];

    [self.mainCV registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
    [self.mainCV registerClass:[TZUploadNewPriceGoodsColCell class] forCellWithReuseIdentifier:@"TZUploadNewPriceGoodsColCell"];

    //pagecontrol
    [self.bkgView addSubview:self.pageControl];
    self.pageControl.frame = CGRectMake(0, Cell_Height, SCREEN_WIDTH, 30);
}


- (UIImage *)zd_imageWithColor:(UIColor *)color
                          size:(CGSize)size
                          text:(NSString *)text
                textAttributes:(NSDictionary *)textAttributes
                      circular:(BOOL)isCircular {
    if (!color || size.width <= 0 || size.height <= 0) return nil;
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    // circular
    if (isCircular) {
        CGPathRef path = CGPathCreateWithEllipseInRect(rect, NULL);
        CGContextAddPath(context, path);
        CGContextClip(context);
        CGPathRelease(path);
    }
    // color
    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, rect);
    //    // text
    //    CGSize textSize = [text sizeWithAttributes:textAttributes];
    //    [text drawInRect:CGRectMake((size.width - textSize.width) / 2, (size.height - textSize.height) / 2, textSize.width, textSize.height) withAttributes:textAttributes];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

#pragma mark - get -
-(UIView *)bkgView{
    if(!_bkgView){
        _bkgView = [[UIView alloc]init];
        _bkgView.backgroundColor = [UIColor clearColor];
        _bkgView.userInteractionEnabled = YES;
    }
    return _bkgView;
}

-(UICollectionView *)mainCV{
    if(!_mainCV){
        CGFloat img_w = (SCREEN_WIDTH - 15 * 4) / 3.0;
        UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
        flowLayout.itemSize = CGSizeMake(img_w, img_w*2);

        //管上下缝隙 minimumLineSpacing
        flowLayout.minimumLineSpacing = 15;
        //管左右缝隙 minimumInteritemSpacing
        flowLayout.minimumInteritemSpacing = 15;
        flowLayout.sectionInset = UIEdgeInsetsMake(0, 15, 0, 0);
        flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        _mainCV = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
        _mainCV.bounces = YES;
        _mainCV.pagingEnabled = YES;
        _mainCV.backgroundColor = [UIColor clearColor];
        _mainCV.showsHorizontalScrollIndicator = NO;
        _mainCV.showsVerticalScrollIndicator = NO;
    }
    return _mainCV;
}

- (TAPageControl *)pageControl {
    if (_pageControl == nil) {
        _pageControl = [[TAPageControl alloc] init];
        _pageControl.currentDotImage = [self zd_imageWithColor:[UIColor colorWithHexString:@"#C32136"] size:CGSizeMake(5, 5) text:@"" textAttributes:@{} circular:YES];
        _pageControl.dotImage = [self zd_imageWithColor:[UIColor colorWithHexString:@"#DEDEDE" alpha:1.0] size:CGSizeMake(5, 5) text:@"" textAttributes:@{} circular:YES];
        _pageControl.shouldResizeFromCenter = YES;
    }
    return _pageControl;
}

3.关键步骤和思路

1.获取显示页面cell的index目的是为了计算页面的页数

/**
 获取scrollView的index
 
 @param scrollView scrollView
 @return index
 */
- (NSIndexPath* )indexWithScrollView:(UIScrollView * _Nonnull)scrollView {

    UICollectionView *cv = scrollView;
    NSArray* visibleCellIndex = cv.indexPathsForVisibleItems;
     NSArray *sortedIndexPaths = [visibleCellIndex sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
            NSIndexPath *path1 = (NSIndexPath *)obj1;
            NSIndexPath *path2 = (NSIndexPath *)obj2;
            return [path1 compare:path2];
        }];

    NSIndexPath* indexPath = [sortedIndexPaths firstObject];
    return indexPath;
}

2.滚动到相应的页数collectionview和Pagecontrol联动

/**
 滚动到指定索引

 @param scrollView scrollView
 */
- (void)scrollToIndex:(UIScrollView *)scrollView {
    NSIndexPath* index = [self indexWithScrollView:scrollView];

    NSInteger item_section = index.section;
    if (index.section == kLoopMaxMultiple - 1) {
        item_section = 0;
    }
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem: index.row inSection:item_section];
    [self.mainCV scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
    
    self.pageControl.currentPage = index.row/3;

}

3.UICollectionView代理方法(将分格空间做在cell 里面,不然整页翻动会有偏移偏移的量为分隔空间的倍数),将数据赋值多份通过多个section来实现第一次最后一帧能够与第一帧接上

#pragma mark-- 数据 --

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return kLoopMaxMultiple;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

    return self.arr_data.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    TZUploadNewPriceGoodsColCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZUploadNewPriceGoodsColCell" forIndexPath:indexPath];
    
    cell.titL.text = [NSString stringWithFormat:@"题目:第%ld页 -- row:%ld  -- section:%ld",indexPath.row/3+1,indexPath.row,indexPath.section];
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat img_w = (SCREEN_WIDTH - 15 * 4) / 3.0;

    return CGSizeMake(floor(img_w)+15, Cell_Height);
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 0, 0, 0);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 0.000001;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 0.000001;
}

// 设置区头尺寸高度
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
    CGSize size = CGSizeMake(0.00001, 0.00001);
    return size;
}

// 设置区尾尺寸高度
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
    return CGSizeMake(0.00001, 0.00001);
}

 4.UIScrollViewDelegate代理方法

  1. scrollViewDidEndScrollingAnimation 不是人为滚动的方法

  2. scrollViewDidEndDecelerating 是人为滑动的方法

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSIndexPath *indexP = [self indexWithScrollView:scrollView];
    NSInteger index = indexP.row/3;
    self.pageControl.currentPage = index;
}

//不是人为滚动
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    [self scrollToIndex:scrollView];
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    
}
//是人为滚动
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self scrollToIndex:scrollView];
}


总结

  1. 通过UICollectionView的属性@property (nonatomic, readonly) NSArray<NSIndexPath *> *indexPathsForVisibleItems;来获取当前页面上显示的cell再排序(**排序很重要)

  2. 当当前cell的index.section == kLoopMaxMultiple - 1 是最后一个分区的时候一定要去滚动到第一个分区从新开始     [self.mainCV scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO]; (动画要关了)

  3. UIScrollViewDelegate的代理一定要区分停止滚动的类型(人为拖拽scrollViewDidEndDecelerating、和代码自动滚动scrollViewDidEndScrollingAnimation


http://www.kler.cn/a/18157.html

相关文章:

  • 2-UML概念模型测试
  • 项目模块详细说明
  • 【智谱开放平台-注册/登录安全分析报告】
  • 第 4 章 - Go 语言变量与常量
  • 开源数据库 - mysql - xtrabackup工具进行备份
  • OpenGL 进阶系列07 - 阴影贴图(shadowmap )
  • Android 9.0 Camera2 拍照功能默认选前摄像头
  • 【论文阅读】A Comparative Study on Camera-Radar Calibration Methods
  • 如何提高执行力
  • 图数据库游记
  • 代码随想录算法训练营day28 | 93.复原IP地址,78.子集,90.子集II
  • 回文数:探索数字世界中的对称美学
  • spark练习例子——单词计数——pyspark
  • Java基础--->基础部分(2)【Java值传递】
  • 项目搭建—常用的插件
  • 基于R语言APSIM模型
  • 国民技术N32G430开发笔记(19)- IAP 升级 I2C1 从机收发数据
  • 本地字体库的引入方法
  • 程序设计的三种结构-C中实现其的6条语句
  • 数据导向下制造业的生产效率、交易效率提升办法
  • 【ESD专题】案例:TVS管钳位电压能不能通过TLP测试数据表征?
  • 【CMIP6月、日数据】【ERA5-LAND陆面再分析数据】【全球VIPPHEN物候数据】
  • javaScript---设计模式-设计模式概论
  • TypeScript基础
  • Chapter 7:XDC Precedence (ug903)
  • TreeMap源码分析,Collections工具类的使用