集合试图(UICollectionview)的灵活使用

1.相信大家都会很熟练使用UITableView了,但是今天给大家 介绍一个iOS6就已经引入的UICollectionView ,功能更加强大,更加灵活,学会使用它,会 帮你解决很多的问题的!它跟UITableView很相似,所以 熟练使用UICollectionView很简单!

2 。先列举一个简单的例子


效果图1.png

我们可以看到这个流式布局,我们可以自定义 布局,继承与UICollectionViewFlowLayout

我现在将 主要代码 贴出来 ,希望对正在使用UICollectionView的同学有所帮助

自定义 布局,继承与 UICollectionViewFlowLayout
CoustomFlowLayOut.m

  • (instancetype)init
    {
    if (self = [super init]) {
    }
    return self;
    }

/**

  • 当collectionView的显示范围发生改变的时候,是否需要重新刷新布局
  • 一旦重新刷新布局,就会重新调用下面的方法:
    1.prepareLayout
    2.layoutAttributesForElementsInRect:方法
    */
  • (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
    {
    return YES;
    }

/**

  • 用来做布局的初始化操作(不建议在init方法中进行布局的初始化操作)
    */
  • (void)prepareLayout
    {
    [super prepareLayout];

    // 水平滚动
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    // 设置内边距
    CGFloat inset = (self.collectionView.frame.size.width - self.itemSize.width) * 0.5;
    self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
    }

/**
UICollectionViewLayoutAttributes attrs;
1.一个cell对应一个UICollectionViewLayoutAttributes对象
2.UICollectionViewLayoutAttributes对象决定了cell的frame
/
/

  • 这个方法的返回值是一个数组(数组里面存放着rect范围内所有元素的布局属性)
  • 这个方法的返回值决定了rect范围内所有元素的排布(frame)
    */
  • (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
    // 获得super已经计算好的布局属性
    NSArray *array = [super layoutAttributesForElementsInRect:rect] ;

    // 计算collectionView最中心点的x值
    CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;

    // 在原有布局属性的基础上,进行微调
    for (UICollectionViewLayoutAttributes *attrs in array) {
    // cell的中心点x 和 collectionView最中心点的x值 的间距
    CGFloat delta = ABS(attrs.center.x - centerX);

      // 根据间距值 计算 cell的缩放比例
      CGFloat scale = 1 - delta / self.collectionView.frame.size.width;
      
      // 设置缩放比例
      attrs.transform = CGAffineTransformMakeScale(scale, scale);
    

    }
    return array;
    }

/**

  • 这个方法的返回值,就决定了collectionView停止滚动时的偏移量

*/

  • (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
    {
    // 计算出最终显示的矩形框
    CGRect rect;
    rect.origin.y = 0;
    rect.origin.x = proposedContentOffset.x;
    rect.size = self.collectionView.frame.size;

    // 获得super已经计算好的布局属性
    NSArray *array = [super layoutAttributesForElementsInRect:rect];

    // 计算collectionView最中心点的x值
    CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;

    // 存放最小的间距值
    CGFloat minDelta = MAXFLOAT;
    for (UICollectionViewLayoutAttributes *attrs in array) {
    if (ABS(minDelta) > ABS(attrs.center.x - centerX)) {
    minDelta = attrs.center.x - centerX;
    }
    }

    // 修改原有的偏移量
    proposedContentOffset.x += minDelta;
    return proposedContentOffset;
    }

自定义cell的话,就是只有一张图片,这里不再赘述,控制器里
mainViewController.m

  • (void)viewDidLoad {
    [super viewDidLoad];

    // 创建布局
    CoustomFlowLayOut *layout = [[CoustomFlowLayOut alloc] init];
    layout.itemSize = CGSizeMake(100, 100);

    // 创建CollectionView
    CGFloat collectionW = self.view.frame.size.width;
    CGFloat collectionH = 200;
    CGRect frame = CGRectMake(0, 150, collectionW, collectionH);
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout];
    collectionView.dataSource = self;
    collectionView.delegate = self;
    [self.view addSubview:collectionView];

    // 注册
    [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CYPhotoCell class]) bundle:nil] forCellWithReuseIdentifier:CYPhotoId];
    }

pragma mark - <UICollectionViewDataSource>

  • (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
    {
    return 20;
    }

  • (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
    CYPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CYPhotoId forIndexPath:indexPath];

    cell.imageName = [NSString stringWithFormat:@"%zd", indexPath.item + 1];

    return cell;
    }

pragma mark - <UICollectionViewDelegate>

  • (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
    {
    NSLog(@"------%zd", indexPath.item);
    }
    @end

上边就是 主要的代码,就可以很简单的实现 上边图片的功能

大家还可能 见过商城中的 商品中的布局 ,类似是这样的,


效果图.png

其实上边的这种效果也很容易实现,只要自己 自定义布局就行了,只是这个布局比 上边那种布局更复杂一点,但是整体的思路还是相同的,就是 自定义 布局,自定义cell,然后控制器 来利用使用它们,在这里 我将主要的代码贴出来,让大家参考,希望对大家 深入了解认识UICollectionView有好的帮助
同样的我先贴出 自定义layOut的 代码
.h中

import <UIKit/UIKit.h>

@class MKMasonryViewLayout;

@protocol MKMasonryViewLayoutDelegate <NSObject>
@required

  • (CGFloat) collectionView:(UICollectionView) collectionView
    layout:(MKMasonryViewLayout
    ) layout
    heightForItemAtIndexPath:(NSIndexPath*) indexPath;
    @end

@interface MKMasonryViewLayout : UICollectionViewLayout
@property (nonatomic, assign) NSUInteger numberOfColumns;
@property (nonatomic, assign) CGFloat interItemSpacing;
@property (weak, nonatomic) IBOutlet id<MKMasonryViewLayoutDelegate> delegate;
@end

.m中

import "MKMasonryViewLayout.h"

@interface MKMasonryViewLayout (/Private Methods/)
@property (nonatomic, strong) NSMutableDictionary *lastYValueForColumn;
@property (strong, nonatomic) NSMutableDictionary *layoutInfo;
@end

@implementation MKMasonryViewLayout

-(void) prepareLayout {

//集合试图 布局 前 会调用这个方法,在这里将 布局物件的边框都计算好 缓存到某个地方

self.numberOfColumns = 3;
self.interItemSpacing = 12.5;

CGFloat currentColumn = 0;
CGFloat fullWidth = self.collectionView.frame.size.width;
CGFloat availableSpaceExcludingPadding = fullWidth - (self.interItemSpacing * (self.numberOfColumns + 1));
CGFloat itemWidth = availableSpaceExcludingPadding / self.numberOfColumns;//每个物件的宽度

self.lastYValueForColumn = [NSMutableDictionary dictionary];

self.layoutInfo = [NSMutableDictionary dictionary];
NSIndexPath *indexPath;
NSInteger numSections = [self.collectionView numberOfSections];

for(NSInteger section = 0; section < numSections; section++) {
//collectionView 是 横着 排列的,而不是 竖着排列的
NSInteger numItems = [self.collectionView numberOfItemsInSection:section];
//每个 section 上含有几个 nuMItems
for(NSInteger item = 0; item < numItems; item++){
indexPath = [NSIndexPath indexPathForItem:item inSection:section];

  UICollectionViewLayoutAttributes *itemAttributes =
  [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
  
  CGFloat x = self.interItemSpacing + (self.interItemSpacing + itemWidth) * currentColumn;
  CGFloat y = [self.lastYValueForColumn[@(currentColumn)] doubleValue];
  
  CGFloat height = [((id<MKMasonryViewLayoutDelegate>)self.collectionView.delegate)
                    collectionView:self.collectionView
                    layout:self
                    heightForItemAtIndexPath:indexPath];
  
  itemAttributes.frame = CGRectMake(x, y, itemWidth, height);
  y+= height;
  y += self.interItemSpacing;
  
  self.lastYValueForColumn[@(currentColumn)] = @(y);
  
  currentColumn ++;
  if(currentColumn == self.numberOfColumns) currentColumn = 0;
  self.layoutInfo[indexPath] = itemAttributes;
}

}
}

  • (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {

    NSMutableArray *allAttributes = [NSMutableArray arrayWithCapacity:self.layoutInfo.count];

    [self.layoutInfo enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath,
    UICollectionViewLayoutAttributes *attributes,
    BOOL *stop) {

    if (CGRectIntersectsRect(rect, attributes.frame)) {
    [allAttributes addObject:attributes];
    }
    }];
    return allAttributes;
    }

-(CGSize) collectionViewContentSize {

NSUInteger currentColumn = 0;
CGFloat maxHeight = 0;
do {
CGFloat height = [self.lastYValueForColumn[@(currentColumn)] doubleValue];
if(height > maxHeight)
maxHeight = height;
currentColumn ++;
} while (currentColumn < self.numberOfColumns);

return CGSizeMake(self.collectionView.frame.size.width, maxHeight);
}

@end

上边就是 完整的把想要的布局 给 布置好了,同样自定义cell这里也不 多谢,现在把 控制器的代码贴出来!

import "SCTViewController.h"

@interface SCTViewController ()<UICollectionViewDataSource, UICollectionViewDelegate, MKMasonryViewLayoutDelegate, UICollectionViewDelegateFlowLayout>

@end

@implementation SCTViewController

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    }

  • (void)didReceiveMemoryWarning
    {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

  • (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {

    return 1;
    }

  • (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

    return 40;
    }

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

    static NSString *CellIdentifier = @"Cell";
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier
    forIndexPath:indexPath];
    cell.backgroundColor = [UIColor redColor];
    return cell;
    }

// this will be called if our layout is UICollectionViewFlowLayout

  • (CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    CGFloat randomHeight = 100 + (arc4random() % 140);
    return CGSizeMake(100, randomHeight); // 100 to 240 pixels tall
    }

// this will be called if our layout is MKMasonryViewLayout

  • (CGFloat) collectionView:(UICollectionView) collectionView
    layout:(MKMasonryViewLayout
    ) layout
    heightForItemAtIndexPath:(NSIndexPath*) indexPath {

    // we will use a random height from 100 - 400

    CGFloat randomHeight = 100 + (arc4random() % 140);
    return randomHeight;
    }

@end

上边的代码就可以实现上图中所要实现的功能,希望可以帮到个位!希望个位提出宝贵意见!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容