新浦京81707con > 首页 > 用UICollectionView实现瀑布流详解,瀑布流封装

原标题:用UICollectionView实现瀑布流详解,瀑布流封装

浏览次数:195 时间:2020-04-27

  • 用法:注意根据WSLWaterFlowLayoutDelegate商谈,代理方法和TableView、collectionView的代理方法用法相近。上边是WSLWaterFlowLayout.h中的属性方法和代理方法,含义注释的还算清晰:

分明供给

由地点的要求暗意图可以预知模块的蝇头单位是长方形,边长是显示器宽除去边距间距后的四等份,而各样模块的体制有小正方形、大纺锤形、横长方形、纵纺锤形,动态的依据服务器下发模块样式绘制结构,能够横向滑动,限制为两行的惊人。注意:上边包车型地铁表示宽高比是约等于,忽略了区间,计算的时候千万别忘了。

  • 相同点:
    • 皆以三翻五次自UIScrollView,援助滚动。
    • 都援救数据单元格的选定机制。
    • 都以经过代理方法和数据源方法来落到实处调节和出示。
  • 不同点:
    • UICollectionView的section里面包车型地铁多少单元叫做item,UITableView的名称叫cell
    • UICollectionView的布局使用UICollectionViewLayou依然其子类UICollectionViewFlowLayout和易于达成自定义构造。
typedef enum { WSLWaterFlowVerticalEqualWidth = 0, /** 竖向瀑布流 item等宽不等高 */ WSLWaterFlowHorizontalEqualHeight = 1, /** 水平瀑布流 item等高不等宽 不支持头脚视图*/ WSLWaterFlowVerticalEqualHeight = 2, /** 竖向瀑布流 item等高不等宽 */ WSLWaterFlowHorizontalGrid = 3, /** 特为国务院客户端原创栏目滑块样式定制-水平栅格布局 仅供学习交流*/ WSLLineWaterFlow = 4 /** 线性布局 待完成,敬请期待 */} WSLFlowLayoutStyle; //样式@class WSLWaterFlowLayout;@protocol WSLWaterFlowLayoutDelegate <NSObject>/** 返回item的大小 注意:根据当前的瀑布流样式需知的事项: 当样式为WSLWaterFlowVerticalEqualWidth 传入的size.width无效 ,所以可以是任意值,因为内部会根据样式自己计算布局 WSLWaterFlowHorizontalEqualHeight 传入的size.height无效 ,所以可以是任意值 ,因为内部会根据样式自己计算布局 WSLWaterFlowHorizontalGrid 传入的size宽高都有效, 此时返回列数、行数的代理方法无效, WSLWaterFlowVerticalEqualHeight 传入的size宽高都有效, 此时返回列数、行数的代理方法无效 */- waterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;/** 头视图Size */-waterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout sizeForHeaderViewInSection:(NSInteger)section;/** 脚视图Size */-waterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout sizeForFooterViewInSection:(NSInteger)section;@optional //以下都有默认值/** 列数*/-columnCountInWaterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout;/** 行数*/-rowCountInWaterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout;/** 列间距*/-columnMarginInWaterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout;/** 行间距*/-rowMarginInWaterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout;/** 边缘之间的间距*/-(UIEdgeInsets)edgeInsetInWaterFlowLayout:(WSLWaterFlowLayout *)waterFlowLayout;@end@interface WSLWaterFlowLayout : UICollectionViewLayout/** delegate*/@property (nonatomic, weak) id<WSLWaterFlowLayoutDelegate> delegate;/** 瀑布流样式*/@property (nonatomic, assign) WSLFlowLayoutStyle flowLayoutStyle;@end

图片 1金镶玉裹福禄双全的栅格结构功效暗指图图片 2需求暗中提示图

UICollectionViewDelegate

雷同的UICollectionView也许有代理方法,在实今世理合同之后经过代理方法来兑现和客户的相互操作。具体来讲主要承受一之下八分专门的学业:

  • cell的高亮效果展现
- collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;- collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;- collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;
  • cell的入选状态
- collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath; // called when the user taps on an already-selected item in multi-select mode- collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;- collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;
  • 接济长按后的菜单
- collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath;- collectionView:(UICollectionView *)collectionView canPerformAction:action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;- collectionView:(UICollectionView *)collectionView performAction:action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;

UICollectionView的精髓即是UICollectionViewLayout,那也是UICollectionView和UITableView最大的两样。UICollectionViewLayout决定了UICollectionView是怎么体现在分界面上的。在显示之间,日常必要扭转合适的UICollectionViewLayout的子类对象,并将其赋值到UICollectionView的布局属性上。UICollectionViewFlowLayout是UICollectionViewLayout的子类。这么些布局是最简便最常用的。它实现了直线对其的构造排布情势,Gird View正是用UICollectionViewFlowLayout结构方式。

落到实处思路

由上急需深入分析可以预知,大家得以让后台各种模块下发width和height五个字段,字段的值是1或2就能够了,然后大家就能够依照宽高字段来规定模块的宽高了。现在宽高有了,大家怎么来绘制模块呢?答案当然是用UICollectionView了,然后自定义流水构造UICollectionViewLayout,主要代码如下:计算记录每多少个cell对应的布局属性。这些样式的栅格构造作者已打包集成在WSLWaterFlowLayout 中,实际情况可以前往Github下载demo,也能够看前边的 iOS 瀑布流封装 那篇随笔明白越来越多。

/** 返回indexPath位置cell对应的布局属性*/- itemFrameOfHorizontalGridWaterFlow:(NSIndexPath *)indexPath{ //collectionView的高度 CGFloat collectionH = self.collectionView.frame.size.height; //设置布局属性item的frame CGFloat h = [self.delegate waterFlowLayout:self sizeForItemAtIndexPath:indexPath].height; CGFloat w = [self.delegate waterFlowLayout:self sizeForItemAtIndexPath:indexPath].width; CGFloat x = 0; CGFloat y = 0; //找出宽度最短的那一行 NSInteger destRow = 0; CGFloat minRowWidth = [self.rowWidths[destRow] doubleValue]; for (NSInteger i = 1; i < self.rowWidths.count; i  ) { //取出第i行 CGFloat rowWidth = [self.rowWidths[i] doubleValue]; if (minRowWidth > rowWidth) { minRowWidth = rowWidth; destRow = i; } } y = destRow == 0 ? self.edgeInsets.top : self.edgeInsets.top   h   self.rowMargin; x = [self.rowWidths[destRow] doubleValue] == self.edgeInsets.left ? self.edgeInsets.left : [self.rowWidths[destRow] doubleValue]   self.columnMargin; //更新最短那行的宽度 if (h >= collectionH - self.edgeInsets.bottom - self.edgeInsets.top) { x = [self.rowWidths[destRow] doubleValue] == self.edgeInsets.left ? self.edgeInsets.left : self.maxRowWidth   self.columnMargin; for (NSInteger i = 0; i < 2; i  ) { self.rowWidths[i] = @; } }else{ self.rowWidths[destRow] = @; } //记录最大宽度 if (self.maxRowWidth < x   w) { self.maxRowWidth = x   w ; } return CGRectMake(x, y, w, h);}

图片 3后台下发字段格式暗示图

职能描述:WSLWaterFlowLayout 是在世袭于UICollectionViewLayout的底工上包裹的为首脚视图的瀑布流控件。近年来支撑竖向瀑布流(item等宽不等高、扶持头脚视图卡塔尔、水平瀑布流(item等高不等宽 不协理头脚视图卡塔尔、竖向瀑布流( item等高不等宽、协助头脚视图State of Qatar、栅格结构瀑布流 4种样式的瀑布流布局。

图片 4WSLWaterFlowLayout

引入阅读:iOS 瀑布流封装WKWebView的利用UIScrollView视觉差动漫iOS 传感器集锦iOS 封装原生二维码扫描和生成iOS 音乐播放器之锁屏歌词 歌词拆解深入分析 锁屏效果UIActivityViewController系统原生疏享-仿简书分享iOS 自定义转场动漫iOS UITableView获取一确定工作岗位位的cell

UICollectionViewLayout布局的求实思路:

  • 设置itemSzie性子,它定义了每一种item的大小。在三个演示中经过安装layout的itemSize属性全局的设置了cell的尺码。假使想要对有些cell定制尺寸,能够使用- collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath方法实现
  • 安装间隔间隔能够钦定item之间的间距和每一行之间的间距。间隔和itemSzie同一,既有大局属性,也足以对每八个item设定:
@property (nonatomic) CGFloat minimumLineSpacing;@property (nonatomic) CGFloat minimumInteritemSpacing;- collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;- collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
  • 设定滚动方向
typedef NS_ENUM(NSInteger, UICollectionViewScrollDirection) { UICollectionViewScrollDirectionVertical, UICollectionViewScrollDirectionHorizontal};
  • 安装Header和Footer的尺码设置Header和Footer的尺寸也分为全局和局地。在那间须求小心滚动的取向,滚动方向分化,header和footer的大幅和冲天独有二个会起成效。垂直滚动时section间宽度为尺寸的高。
@property (nonatomic) CGSize headerReferenceSize;@property (nonatomic) CGSize footerReferenceSize;- collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;- collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;
  • 安装内边距
@property (nonatomic) UIEdgeInsets sectionInset;- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;

瀑布流很常用,越发是在电商类app中用来彰显商品消息,比如某宝:

图片 5

落到实处瀑布流的主意有两种,可是比较轻松的是经过UICollectionView,因为collectionView本人会落实cell的大循环使用,所以本人不用完成循环使用的体制。瀑布就最根本的就是布局,要筛选最短的那一列来排布,保障每一列之间的间距不会太大。

 WSLWaterFlowLayout * _flow = [[WSLWaterFlowLayout alloc] init]; _flow.delegate = self; _flow.flowLayoutStyle = WSLVerticalWaterFlow;

金玉锦绣步骤

  • 自定义世襲自UICollectionViewLayout的子类来开展落到实处结构
    • 调用- prepareLayout扩充初叶化
    • 重载- collectionViewContentSize归来内容的轻重
    • 重载- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:rect措施再次来到rect中具有因素的布局属性,再次回到的是一个数组
    • 重载- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath办法再次回到对应的indexPath的岗位的cell的结构属性。
    • 重载- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;艺术再次来到对应indexPath之处的扩展视图的布局属性,若无就毫无重载
    • 重载- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath *)indexPath;措施再次来到对应indexPath的岗位的装潢视图的构造属性,如果未有也无需重载
    • 重载- shouldInvalidateLayoutForBoundsChange:newBounds;当边界产生变动时,是不是相应刷新。

用代理来落实对item的布局属性的调节.h文件

#import <UIKit/UIKit.h>@class LMHWaterFallLayout;@protocol LMHWaterFallLayoutDeleaget<NSObject>@required/** * 每个item的高度 */- waterFallLayout:(LMHWaterFallLayout *)waterFallLayout heightForItemAtIndexPath:(NSUInteger)indexPath itemWidth:itemWidth;@optional/** * 有多少列 */- (NSUInteger)columnCountInWaterFallLayout:(LMHWaterFallLayout *)waterFallLayout;/** * 每列之间的间距 */- columnMarginInWaterFallLayout:(LMHWaterFallLayout *)waterFallLayout;/** * 每行之间的间距 */- rowMarginInWaterFallLayout:(LMHWaterFallLayout *)waterFallLayout;/** * 每个item的内边距 */- (UIEdgeInsets)edgeInsetdInWaterFallLayout:(LMHWaterFallLayout *)waterFallLayout;@end@interface LMHWaterFallLayout : UICollectionViewLayout/** 代理 */@property (nonatomic, weak) id<LMHWaterFallLayoutDeleaget> delegate;@end

.m文件

#import "LMHWaterFallLayout.h"/** 默认的列数 */static const CGFloat LMHDefaultColunmCount = 3;/** 每一列之间的间距 */static const CGFloat LMHDefaultColunmMargin = 10;/** 每一行之间的间距 */static const CGFloat LMHDefaultRowMargin = 10;/** 内边距 */static const UIEdgeInsets LMHDefaultEdgeInsets = {10,10,10,10};@interface LMHWaterFallLayout()/** 存放所有的布局属性 */@property (nonatomic, strong) NSMutableArray * attrsArr;/** 存放所有列的当前高度 */@property (nonatomic, strong) NSMutableArray *columnHeights;/** 内容的高度 */@property (nonatomic, assign) CGFloat contentHeight;- (NSUInteger)colunmCount;- columnMargin;- rowMargin;- (UIEdgeInsets)edgeInsets;@end@implementation LMHWaterFallLayout#pragma mark 懒加载- (NSMutableArray *)attrsArr{ if (!_attrsArr) { _attrsArr = [NSMutableArray array]; } return _attrsArr;}- (NSMutableArray *)columnHeights{ if (!_columnHeights) { _columnHeights = [NSMutableArray array]; } return _columnHeights;}#pragma mark - 数据处理/** * 列数 */- (NSUInteger)colunmCount{ if ([self.delegate respondsToSelector:@selector(columnCountInWaterFallLayout:)]) { return [self.delegate columnCountInWaterFallLayout:self]; }else{ return LMHDefaultColunmCount; }}/** * 列间距 */- columnMargin{ if ([self.delegate respondsToSelector:@selector(columnMarginInWaterFallLayout:)]) { return [self.delegate columnMarginInWaterFallLayout:self]; }else{ return LMHDefaultColunmMargin; }}/** * 行间距 */- rowMargin{ if ([self.delegate respondsToSelector:@selector(rowMarginInWaterFallLayout:)]) { return [self.delegate rowMarginInWaterFallLayout:self]; }else{ return LMHDefaultRowMargin; }}/** * item的内边距 */- (UIEdgeInsets)edgeInsets{ if ([self.delegate respondsToSelector:@selector(edgeInsetdInWaterFallLayout:)]) { return [self.delegate edgeInsetdInWaterFallLayout:self]; }else{ return LMHDefaultEdgeInsets; }}/** * 初始化 */- prepareLayout{ [super prepareLayout]; self.contentHeight = 0; // 清除之前计算的所有高度 [self.columnHeights removeAllObjects]; // 设置每一列默认的高度 for (NSInteger i = 0; i < LMHDefaultColunmCount ; i   ) { [self.columnHeights addObject:@(LMHDefaultEdgeInsets.top)]; } // 清楚之前所有的布局属性 [self.attrsArr removeAllObjects]; // 开始创建每一个cell对应的布局属性 NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i < count; i  ) { // 创建位置 NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0]; // 获取indexPath位置上cell对应的布局属性 UICollectionViewLayoutAttributes * attrs = [self layoutAttributesForItemAtIndexPath:indexPath]; [self.attrsArr addObject:attrs]; } }/** * 返回indexPath位置cell对应的布局属性 */- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ // 创建布局属性 UICollectionViewLayoutAttributes * attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //collectionView的宽度 CGFloat collectionViewW = self.collectionView.frame.size.width; // 设置布局属性的frame CGFloat cellW = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.colunmCount - 1) * self.columnMargin) / self.colunmCount; CGFloat cellH = [self.delegate waterFallLayout:self heightForItemAtIndexPath:indexPath.item itemWidth:cellW]; // 找出最短的那一列 NSInteger destColumn = 0; CGFloat minColumnHeight = [self.columnHeights[0] doubleValue]; for (int i = 1; i < LMHDefaultColunmCount; i  ) { // 取得第i列的高度 CGFloat columnHeight = [self.columnHeights[i] doubleValue]; if (minColumnHeight > columnHeight) { minColumnHeight = columnHeight; destColumn = i; } } CGFloat cellX = self.edgeInsets.left   destColumn * (cellW   self.columnMargin); CGFloat cellY = minColumnHeight; if (cellY != self.edgeInsets.top) { cellY  = self.rowMargin; } attrs.frame = CGRectMake(cellX, cellY, cellW, cellH); // 更新最短那一列的高度 self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame)); // 记录内容的高度 - 即最长那一列的高度 CGFloat maxColumnHeight = [self.columnHeights[destColumn] doubleValue]; if (self.contentHeight < maxColumnHeight) { self.contentHeight = maxColumnHeight; } return attrs;}/** * 决定cell的布局属性 */- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:rect{ return self.attrsArr;}/** * 内容的高度 */- collectionViewContentSize{ // CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];// for (int i = 0; i < LMHDefaultColunmCount; i  ) {// // // 取得第i列的高度// CGFloat columnHeight = [self.columnHeights[i] doubleValue];// // if (maxColumnHeight < columnHeight) {// maxColumnHeight = columnHeight;// }//// } return CGSizeMake(0, self.contentHeight   self.edgeInsets.bottom);}@end

接下去在调整器里面就只供给坚决守护第三个示范的步骤,创制结构,创设collectionView。在此边,瀑布流中每种cell的图样和尺寸是后台传过来的,所以只需在构造的代理方法里面将那么些数量传入,就能够完毕叁个简便的瀑布流了。实现效果与利益

图片 6

依据代码下载链接:用UICollectionView完成瀑布

发轫化仅三行代码,只需安装代理和体制,item的朗朗上口、头脚视图的朗朗上口、行列数以至距离都能够在对应样式的代办方法中自定义,然后设置为UICollectionView的机动流水构造样式,并构成UICollectionView的用法使用,详细情况看示例

关于UICollectionView,苹果是这么解释的:管理数据项的不改变聚焦,并应用可定制的构造突显它们。在iOS中最简便的UICollectionView正是GirdView,能够以多列的主意将数据开展彰显。规范的UICollectionView包括以下3个部分,他们都以UIView的子类:

本文由新浦京81707con发布于首页,转载请注明出处:用UICollectionView实现瀑布流详解,瀑布流封装

关键词: 新浦京81707con ios 详解 布局 瀑布

上一篇:如何从零开始写一款书籍阅读器,小说阅读类A

下一篇:没有了