iOS用UICollectionView实现自定义卡片布局原创
金蝶云社区-honey缘木鱼
honey缘木鱼
3人赞赏了该文章 2,335次浏览 未经作者许可,禁止转载编辑于2019年04月17日 10:25:14

最近写一个新项目时,UI设计了一种常规的卡片式的布局,来显示用户对电影的感悟,以前也写过这类布局,代码早已不知去向,每次遇到都是网上搜索,修改,每次都是这么重复,这次不如自己把这部分代码,功能整理出来,方便下次自己使用。

一.业务需求



二.实现思路


1.用UICollectionView来实现左右滑动的页面布局。
2.滑动最后一张时,提示用户暂无更多。(设计要求)
3.实现无限轮播。
4.时间间隔内自动播放。


三.关键代码


  1. 设置cell的缩放比例,实现中心卡片的位置。

- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {    
    NSArray *arr = [self getCopyOfAttributes:[super layoutAttributesForElementsInRect:rect]];    //屏幕中线
    CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.bounds.size.width/2.0f;    //刷新cell缩放
    for (UICollectionViewLayoutAttributes *attributes in arr) {  
          
        CGFloat distance = fabs(attributes.center.x - centerX);        
        //移动的距离和屏幕宽度的的比例
        CGFloat apartScale = distance/self.collectionView.bounds.size.width;   
             //把卡片移动范围固定到 -π/4到 +π/4这一个范围内
        CGFloat scale = fabs(cos(apartScale * M_PI/4));       
         //设置cell的缩放 按照余弦函数曲线 越居中越趋近于1
        attributes.transform = CGAffineTransformMakeScale(1.0, scale);
    }   
     return arr;
}
  1. 滑动最后一张时,提示用户暂无更多。

- (void)setModels:(NSArray *)models{    
    if (models.count == 0) {   
         return;
    }   
     NSMutableArray *modelsM = @[].mutableCopy;
    [modelsM addObjectsFromArray:models];
    ShowBannerModel *first = [[ShowBannerModel alloc]init];//添加一条新数据,设置空白页
     [modelsM addObject:first];
  }

3.实现无限轮播,实现无限轮播时就需要考虑多种情况,数据图片只有一张,两张,大于3张时的情况。

  - (void)setModels:(NSArray *)models{ 
     if (models.count == 0) { 
         return;
    }   
    //处理模型 实现无限滚动
    NSMutableArray *modelsM = @[].mutableCopy;
    [modelsM addObjectsFromArray:models]; 
    if (modelsM.count >= 3) {    
        if(_isRepeat){
            ShowBannerModel *first = modelsM.firstObject;
            ShowBannerModel *seconed = modelsM[1];
            ShowBannerModel *last = modelsM.lastObject;
            ShowBannerModel *lastTwo = modelsM[models.count - 2];
            
            [modelsM insertObject:last atIndex:0];
            [modelsM insertObject:lastTwo atIndex:0];
            
            [modelsM addObject:first];
            [modelsM addObject:seconed];
        } 
  }else if (modelsM.count == 2) {   
       if(_isRepeat){
                    ShowBannerModel *first = modelsM.firstObject;
                    ShowBannerModel *seconed = modelsM.lastObject;
                    ShowBannerModel *last = modelsM.lastObject;
                    ShowBannerModel *lastTwo = modelsM.firstObject;
            
                    [modelsM insertObject:last atIndex:0];
                    [modelsM insertObject:lastTwo atIndex:0];
            
                    [modelsM addObject:first];
                    [modelsM addObject:seconed];
        }
  } 
}else if (modelsM.count == 1) {
        _currentIndex = 0;      
          if(_isRepeat){
                   ShowBannerModel *first = [[ShowBannerModel alloc]init];
                    ShowBannerModel *seconed = modelsM.firstObject;
                    ShowBannerModel *last = modelsM.lastObject;
                    ShowBannerModel *lastTwo = models.lastObject;
                    [modelsM insertObject:last atIndex:0];
                    [modelsM insertObject:lastTwo atIndex:0];
                    [modelsM addObject:first];
                    [modelsM addObject:seconed];
        }
     }
  _models = modelsM; //设置初始位置
    if (models.count > 0) {
        [self.collection scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:_currentIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];        
        if (self.delegate &&
            [self.delegate respondsToSelector:@selector(ShowBannerView:scrollAt:)]) {
            [self.delegate ShowBannerView:self scrollAt:_currentIndex];
        }
        [self.collection reloadData];
   }

图片滑动中心显示时,也要考虑最后一张和第一张图片的情况

if(_isRepeat){            //如果是最后一张图
        if (_currentIndex == self.models.count - 1 ){ 
              _currentIndex = 2;
             [self.collection scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:_currentIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];                return;
            }            
            //第一张图
        else if (_currentIndex == 1) {
             _currentIndex = self.models.count - 3;
             [self.collection scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:_currentIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];        return;
        }
    }

4.设置时间间隔内自动播放。

#pragma mark 设置定时器时间
- (void)setTimeInterval:(NSTimeInterval)timeInterval {
    _timeInterval = timeInterval;   
     if(_isAutomatic){
        [self startTimer];
    }
    
}

- (void)startTimer {   
 //如果只有一张图片,则直接返回,不开启定时器
    if (_models.count <= 1)
     return;   
  //如果定时器已开启,先停止再重新开启
    if (self.timer){
        [self stopTimer];
    }   
     NSTimeInterval timeInterval = _timeInterval ? (_timeInterval >= 1 ?: 1) : DefaultTime;    self.timer = [NSTimer timerWithTimeInterval:timeInterval target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

- (void)stopTimer {
    [self.timer invalidate];  
     
     self.timer = nil;
}

以上实现的思路和关键代码,具体demo :https://github.com/dt8888/LeftAndRightScrollerView


四.如何引用demo的ShowBannerView


1.导入类 #import "ShowBannerView.h"
2.使用代码示例

 CGFloat width = self.view.bounds.size.width;
    _banner = [[ShowBannerView alloc] initWithFrame:CGRectMake(0, bgView.bottom+30, width, 520)];
    _banner.delegate = self;
    _banner.isRepeat = YES;//是否无限录播
    _banner.isAutomatic = YES;//是否定时自动显示
    [_scrollView addSubview:_banner];

3.设置代理 _banner.delegate = self; 遵守<ShowBannerViewDelegate>协议,并实现代理的方法

//滑动到某页面
- (void)ShowBannerView:(ShowBannerView *)bannerView scrollAt:(NSInteger)index{}
//点击某一个卡片的方法
- (void)ShowBannerView:(ShowBannerView *)bannerView didSelectedAt:(NSInteger)index{}

4.最终实现 的效果图





本篇独发金蝶云社区

赞 3