android中UIColletionView瀑布流布局實(shí)現(xiàn)思路以及封裝的實(shí)現(xiàn)
瀑布流實(shí)現(xiàn)思路
- 第一種就是用ScrollView來進(jìn)行實(shí)現(xiàn),由于它不具備復(fù)用的功能,因此我們需要自己寫一套類似復(fù)用的模塊來進(jìn)行優(yōu)化
- 第二種就是利用apple做好的復(fù)用模塊,自定義UIColletionLayout來實(shí)現(xiàn)瀑布流,想想也是第二種實(shí)現(xiàn)起來更快更優(yōu),OK,封裝一個(gè)小小的框架來試試
默認(rèn)兩列
其他案例
上面的動(dòng)畫切換布局也是自定義UICollectionLayout來進(jìn)行布局的,簡(jiǎn)單的靜態(tài)圖片布局展示其實(shí)就重寫幾個(gè)方法就可以了
1.prepareLayout 每次重新刷新collectionView的時(shí)候會(huì)調(diào)用一次,做一些初始化的工作
2.layoutAttributesForElementsInRect 返回已經(jīng)制定好之后的每個(gè)cell對(duì)應(yīng)的attribute屬性對(duì)象進(jìn)行布局
3.layoutAttributesForItemAtIndexPath 該方法會(huì)一直調(diào)用,每次cell出來就會(huì)根據(jù)對(duì)應(yīng)的indexpath來進(jìn)行方法調(diào)用,因此關(guān)鍵布局代碼就可以放置在這里進(jìn)行重新計(jì)算
4.collectionViewContentSize 計(jì)算整體的大小,實(shí)現(xiàn)滾動(dòng)
上面插入樣式實(shí)現(xiàn)的傳送門
瀑布流實(shí)現(xiàn)分析
1.基本變量的聲明
// 每一列的間距
static const CGFloat MKJDefaultColumnMargin = 10;
// 每一行間距
static const CGFloat MKJDefaultRowMargin = 10;
// 整體的上間距,左間距,下間距,右間距
static const UIEdgeInsets MKJDefaultEdgeInsets = {10,10,10,10};
// 默認(rèn)是多少列
static const NSUInteger MKJDefaultColumnCounts = 2;
@interface MKJWaterFallLayout ()
@property (nonatomic,strong) NSMutableArray *attributeArr; // cell屬性的數(shù)組
@property (nonatomic,strong) NSMutableArray *columnHeightArr; // 每列的高度數(shù)組
@end
2.初始化
// 每次刷新會(huì)調(diào)用一次
- (void)prepareLayout
{
[super prepareLayout];
// 每次重新刷新的時(shí)候清除之前的所有高度值,默認(rèn)就是UIEdg給定的top
[self.columnHeightArr removeAllObjects];
for (NSInteger i = 0; i < [self columnCount]; i++) {
[self.columnHeightArr addObject:@([self insetMargin].top)];
}
// 每次刷新把對(duì)應(yīng)的att屬性清空
[self.attributeArr removeAllObjects];
// 初始化一次每個(gè)cell對(duì)應(yīng)的attribute屬性
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (NSInteger i = 0; i < count; i++) {
NSIndexPath *indexpath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexpath];
[self.attributeArr addObject:attribute];
}
}
3.關(guān)鍵計(jì)算代碼
// 返回attribute屬性數(shù)組決定最后的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.attributeArr;
}
// 返回對(duì)應(yīng)的indexpath下每個(gè)cell的屬性 cell的出現(xiàn)會(huì)一直刷新該方法
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 初始化布局屬性---> 對(duì)應(yīng)的indexpath
UICollectionViewLayoutAttributes *att = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGFloat collectionW = self.collectionView.frame.size.width;
// 寬度是根據(jù)列數(shù)和間距固定算出來的
CGFloat width = (collectionW - [self insetMargin].left - [self insetMargin].right - ([self columnCount] - 1) * [self columnMargin]) / [self columnCount];
// 高度是根據(jù)代理的數(shù)據(jù)源返回比例計(jì)算的
CGFloat height = [self.delegate MKJWaterFallLayout:self heightForItemAtIndexPath:indexPath] * width;
// X 和 Y值都是在找出最小column之后才能確定,核心就是根據(jù)列數(shù),找出最小高度的那一列
// 先取出第一個(gè)默認(rèn)是最小的
CGFloat minColumnHeight = [self.columnHeightArr[0] doubleValue];
// 默認(rèn)最小的是第0列
NSUInteger finalCol = 0;
for (NSInteger i = 1 ; i < [self columnCount]; i++) {
CGFloat currentColHeight = [self.columnHeightArr[i] doubleValue];
if (minColumnHeight > currentColHeight) {
minColumnHeight = currentColHeight;
finalCol = i;
}
}
// x,y值是根據(jù)最小高度列算出來的
CGFloat x = [self insetMargin].left + (width + [self columnMargin]) * finalCol;
CGFloat y = minColumnHeight;
// 當(dāng)你是一個(gè)行排布的時(shí)候 默認(rèn)是top值,不需要加間距
NSInteger count = indexPath.item;
if ((count / ([self columnCount])) >= 1) {
y += [self rowMargin];
}
att.frame = CGRectMake(x, y, width, height);
self.columnHeightArr[finalCol] = @(CGRectGetMaxY(att.frame));
return att;
}
這里的計(jì)算簡(jiǎn)概括為就是對(duì)每個(gè)cell進(jìn)行frame的計(jì)算
1.寬度的計(jì)算是根據(jù)列間距和整體左右間距以及行數(shù)進(jìn)行限制,這些參數(shù)可以是固定值,也可以是代理傳進(jìn)去的
2.高度的計(jì)算必定是根據(jù)外部代理進(jìn)行計(jì)算的
3.X值的計(jì)算是根據(jù)這個(gè)框架內(nèi)部的每一列的高度數(shù)組進(jìn)行之前的緩存高度,進(jìn)行最小值計(jì)算,然后拿出最小值對(duì)應(yīng)的列數(shù),根據(jù)上面算出來的高度進(jìn)行X值的計(jì)算
4.Y值的計(jì)算和X值一樣,根據(jù)給定的數(shù)組,比出最小高度列的列數(shù),根據(jù)數(shù)組的高度,計(jì)算出對(duì)應(yīng)的Y值,最終再進(jìn)行數(shù)組對(duì)應(yīng)列數(shù)的高度更新
4.獲取實(shí)際能容大小,讓其可以滾動(dòng)
// 計(jì)算出滾動(dòng)區(qū)域的大小
- (CGSize)collectionViewContentSize
{
CGFloat maxColumHeight = [self.columnHeightArr[0] doubleValue];
for (NSInteger i = 1; i < [self columnCount]; i++) {
CGFloat currentColHeight = [self.columnHeightArr[i] doubleValue];
if (maxColumHeight < currentColHeight) {
maxColumHeight = currentColHeight;
}
}
return CGSizeMake(0, maxColumHeight + [self insetMargin].bottom);
}
5.這個(gè)小框架已經(jīng)封裝好了,簡(jiǎn)單介紹下用法
// 聲明如下
- (UICollectionView *)colletionView
{
if (_colletionView == nil) {
MKJWaterFallLayout *layout = [[MKJWaterFallLayout alloc] init];
layout.delegate = self;
UICollectionView *collectionV = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
collectionV.backgroundColor = [UIColor redColor];
[collectionV registerNib:[UINib nibWithNibName:productID bundle:nil] forCellWithReuseIdentifier:productID];
collectionV.delegate = self;
collectionV.dataSource = self;
_colletionView = collectionV;
}
return _colletionView;
}
// 內(nèi)部行數(shù),間距的控制
#pragma mark - waterfallLayoutDelegate
- (CGFloat)MKJWaterFallLayout:(MKJWaterFallLayout *)layout heightForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 返回寬度和高度比例
MKJProductModel *product = self.dataSource[indexPath.item];
return product.h / product.w;
}
// 控制列間距
- (CGFloat)columnMarginForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
return 10;
}
// 控制行間距
- (CGFloat)rowMarginForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
return 30;
}
// 控制列數(shù)
- (NSUInteger)columnCountForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
// if (self.dataSource.count > 50) {
// return 3;
// }
return 3;
}
// 控制整體上左下右間距
- (UIEdgeInsets)insetForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
return UIEdgeInsetsMake(10, 10, 10, 10);
}
Demo地址: http://xiazai.jb51.net/201702/yuanma/MKJWaterFallLayout_jb51.rar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android編程實(shí)現(xiàn)Gallery中每次滑動(dòng)只顯示一頁的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)Gallery中每次滑動(dòng)只顯示一頁的方法,涉及Android擴(kuò)展Gallery控件實(shí)現(xiàn)翻頁效果控制的功能,涉及Android事件響應(yīng)及屬性控制的相關(guān)技巧,需要的朋友可以參考下2015-11-11
Android中LinearLayout布局的常用屬性總結(jié)
這篇文章主要介紹了Android中LinearLayout布局的常用屬性總結(jié),包括居中、重心、比例等線性布局中的基本設(shè)置,需要的朋友可以參考下2016-04-04
Android使用自定義View實(shí)現(xiàn)餅狀圖的實(shí)例代碼
這篇文章主要介紹了Android使用自定義View實(shí)現(xiàn)餅狀圖的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05
Flutter WillPopScope攔截返回事件原理示例詳解
這篇文章主要為大家介紹了Flutter WillPopScope攔截返回事件原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
Android編程實(shí)現(xiàn)大圖滾動(dòng)顯示的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)大圖滾動(dòng)顯示的方法,涉及Android使用imageView配合onTouch事件操作圖片顯示的相關(guān)技巧,需要的朋友可以參考下2016-10-10
Android 8.0中一些坑以及對(duì)應(yīng)的解決方法
這篇文章主要給大家介紹了關(guān)于Android 8.0中一些坑以及對(duì)應(yīng)的解決方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09

