1. 程式人生 > >UICollectionViewLayout的簡單使用(簡單瀑布流)

UICollectionViewLayout的簡單使用(簡單瀑布流)

對於需要使用到列表的頁面,一般是使用UITableView或者是UICollectionView來實現。一直以來都是直接使用UICollectionViewFlowLayout,基本都能實現需求功能,但是對於直接利用UICollectionViewLayout來自定義view的layout沒怎麼使用過,這裡查了蠻多資料自己寫了demo,僅供日後參考了。
參考資料地址:
http://blog.csdn.net/majiakun1/article/details/17204921
http://www.cnblogs.com/wangyingblock/p/5627448.html

UICollectionViewLayoutAttrubutes

一個很重要的類主要記錄了cells,supplementaryViews,decorationviews的位置,size,透明度,層級等
- @property (nonatomic) CGRect frame; frame資訊
- @property (nonatomic) CGPoint center; 中心點
- @property (nonatomic) CGSize size;大小
- @property (nonatomic) CATransform3D transform3D;
- @property (nonatomic) CGRect bounds NS_AVAILABLE_IOS(7_0);
- @property (nonatomic) CGAffineTransform transform NS_AVAILABLE_IOS(7_0);
- @property (nonatomic) CGFloat alpha;透明度
- @property (nonatomic) NSInteger zIndex; // default is 0 層級
- @property (nonatomic, getter=isHidden) BOOL hidden; // As an optimization, UICollectionView might not create a view for items whose hidden attribute is YES
- @property (nonatomic, strong) NSIndexPath *indexPath;位置
- @property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;
- @property (nonatomic, readonly, nullable) NSString *representedElementKind; 響應型別(區分cell,supple,decaration)
那麼當UICollectionView獲取佈局的時候會通過訪問每個位置的部件通過其attribute來詢問其佈局資訊

自定義一個UICollectionViewLayout

繼承自UICollectionViewLayout類,然後一般需要過載下列方法:
- -(void)prepareLayout;
- 每次請求佈局時候都會自動呼叫,可以在這裡修改一些必要的layout的結構和初始需要的引數等
- -(CGSize)collectionViewContentSize;
- 定義UIcollectionView的ContentSize,內容大小
- 返回可見區域rect內的所有元素的佈局資訊
- 返回包含attributes的陣列
- -(UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath

)indexPath;
- 定義每個indexpath的item的佈局資訊
- 相應的還有定義supplement以及decoration的方法 這裡就不在進行列舉
- -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
- 當邊界發生改變時,是否應該重新整理佈局。如果YES則在邊界變化(一般是scroll到其他地方)時,將重新計算需要的佈局資訊。

##demo
demo地址
Simulator Screen Shot 2016年10月13日 上午10.52.12.png
使用了一組圖片和一個json檔案(如果新增過後發現解析為空,在target ->Build Phase - >copy Bundle Resource新增需要的json檔案) 正在減肥用的都是減肥勵志的哈哈

PickModel

使用到的model
.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface PicModel : NSObject
@property(nonatomic,strong) NSString *picPath;//影象
@property(nonatomic,strong) NSString *picDetail;//詳細內容
@property(nonatomic,assign) CGFloat rowHeight;//行高

+(instancetype)initWithDic:(NSDictionary*)dic;
-(instancetype)initWithDic:(NSDictionary*)dic;

@end

.m 通過detail計算高度,計算所在item的高度,這裡圖片的高度直接約束限制死了,可以改為按比例計算等。

#import "PicModel.h"

@implementation PicModel

+(instancetype)initWithDic:(NSDictionary*)dic{

    PicModel *model = [self alloc];
    return [model initWithDic:dic];
}

-(instancetype)initWithDic:(NSDictionary*)dic{

    if (self = [super init]) {
        self.picPath = dic[@"path"];
        self.picDetail = dic[@"detail"];

        CGFloat width = ([UIScreen mainScreen].bounds.size.width -(MAXCOUNT - 1) * 10)/MAXCOUNT;
        CGSize size = [dic[@"detail"] boundingRectWithSize:CGSizeMake(([UIScreen mainScreen].bounds.size.width -(MAXCOUNT - 1) * 10)/MAXCOUNT, MAXFLOAT) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil].size;
        self.rowHeight = size.height + 59 *width / 100 ;
    }
    return self;
}
@end

通過修改定義的列數
Pch檔案.png

ViewController

.m檔案

#import "BaseViewController.h"
#import "PicModel.h"
#import "PureLayout.h"
#import "PureCollectionViewCell.h"

@interface BaseViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>
@property(nonatomic,strong) UICollectionView *mainCollectionView;
@property(nonatomic,strong) NSMutableArray *dataArray;//資料來源陣列
@end

@implementation BaseViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    self.dataArray = [NSMutableArray array];
    //解析geojson檔案
    NSString *jsonPath = [[NSBundle mainBundle] pathForResource:@"Detail" ofType:@"geojson"];
    NSArray *detailArr = [[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:jsonPath] options:NSJSONReadingMutableContainers error:nil] objectForKey:@"data"
    ];

    //處理model資料
    for (int i =0; i<12; i++) {
        NSString *path = [NSString stringWithFormat:@"%d.jpg",i];
        PicModel *model = [PicModel initWithDic:[NSDictionary dictionaryWithObjectsAndKeys:path,@"path",detailArr[i],@"detail", nil]];
        [self.dataArray addObject:model];
    }

    [self definationMainCollectionView];

    //新增MJRefreshFooter 新增資料
    __weak typeof(self)weakSelf = self;
    self.mainCollectionView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{

        for (int i =0; i<12; i++) {
            NSString *path = [NSString stringWithFormat:@"%d.jpg",i];
            PicModel *model = [PicModel initWithDic:[NSDictionary dictionaryWithObjectsAndKeys:path,@"path",detailArr[i],@"detail", nil]];
            [weakSelf.dataArray addObject:model];
        }
        [weakSelf.mainCollectionView reloadData];
        [weakSelf.mainCollectionView.mj_footer endRefreshing];
    }];
}

/**
 *  設定相關UICollectionView資訊
 */
-(void)definationMainCollectionView{

    PureLayout *layout = [[PureLayout alloc] init];
    layout.dataArray = self.dataArray;

    self.mainCollectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
    [self.mainCollectionView registerNib:[UINib nibWithNibName:@"PureCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"pureCell"];
    self.mainCollectionView.delegate = self;
    self.mainCollectionView.dataSource = self;
    self.mainCollectionView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:self.mainCollectionView];
}
#pragma mark - UICollectionViewDataSource
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{

    return 1;
}

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

   return  self.dataArray.count;
}

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

    PureCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"pureCell" forIndexPath:indexPath];
    PicModel *model = self.dataArray[indexPath.row];
    cell.model = model;
    return cell;
}

PureLayout

.h檔案,這裡簡單的直接傳遞了資料來源

@interface PureLayout : UICollectionViewLayout

@property(nonatomic,strong)NSArray *dataArray;//資料來源
@property(nonatomic,assign) NSInteger maxCount;//列數
@end

.m檔案 定義需要展示的列數,水平 垂直間隔等基本資訊

#import "PureLayout.h"
#import "PicModel.h"

static CGFloat horizonalSpace = 10;//水平間隔
static CGFloat verticalSpace = 15;//垂直間隔

@interface PureLayout ()
@property(nonatomic,strong) NSMutableArray *offSets;//用於儲存不同列的MAXY資訊
@end

@implementation PureLayout

-(void)prepareLayout{

    _maxCount = MAXCOUNT;
}

根據需要展示的列數,使用陣列分別記錄每行所在列item的frame.origin.y,進行對比,設定UICollectionView的contentsize

-(CGSize)collectionViewContentSize{

    CGFloat width = [UIScreen mainScreen].bounds.size.width;
    CGFloat height = 0.0;

   _offSets = [NSMutableArray array];

    for (int i =0; i<_maxCount; i++) {
        [_offSets addObject:@0];
    }

    for (int i = 0; i<self.dataArray.count; i++) {
        NSInteger col = i % _maxCount;
        PicModel *model = self.dataArray[i];

        CGFloat offSetY ;
        offSetY = [_offSets[col] floatValue] + model.rowHeight + verticalSpace;
        _offSets[col] = @(offSetY);
        height = MAX(height, offSetY);
    }

    if (height < [UIScreen mainScreen].bounds.size.height) {
        height = [UIScreen mainScreen].bounds.size.height;
    }
    return CGSizeMake(width, height);
}

返回可見Rect內的元素的attributes資訊

-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{

    NSMutableArray * attributes = [NSMutableArray array];
    for (int i =0 ; i<self.dataArray.count; i++) {
        UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
        [attributes addObject:attribute];
    }
    return attributes;
}

對不同的indexpath的items設定attributes資訊

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{

    UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    PicModel *model = self.dataArray[indexPath.row];
    CGFloat itemWidth = ([UIScreen mainScreen].bounds.size.width - (MAXCOUNT - 1) * 10)/_maxCount;
    attribute.size = CGSizeMake(itemWidth, model.rowHeight);
    CGFloat itemY = 0.0;
    CGFloat itemX = 0.0;

    NSInteger col = indexPath.row % _maxCount;
    itemX = (([UIScreen mainScreen].bounds.size.width - (MAXCOUNT - 1) * 10)/_maxCount + horizonalSpace)* col;
    if (indexPath.row <_maxCount) {
        itemY = 0.0;
    }else{
        UICollectionViewLayoutAttributes *otherAttribute = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row - _maxCount inSection:0]];
        itemY = CGRectGetMaxY(otherAttribute.frame) + verticalSpace;
    }

    attribute.frame = CGRectMake(itemX, itemY, itemWidth,  model.rowHeight);
    return attribute;
}

最後新增上該方法,邊界改變是重新佈局

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{

    return YES;
}

只是一個簡單的額瀑布流demo,還有蠻多地方需要優化,這裡僅僅寫下一些基本思路。

官方給出的兩個demo很有學習價值,CircleLayout以及LinLayout,在我之前的給出的參考連結裡面都是可以直接下載的,對於與文章中的CircleLayout用法,insert和delete方法已經被appearing和disappearing取代了,參考的githubdemo被我fork了一份,可以進行下載學習 https://github.com/w467364316/CircleLayout.git

相關推薦

利用JS實現簡單瀑布效果

color position func 如何實現 利用 無限 bar 拓展 復制代碼 一.瀑布流之準備工作    首先聲明下, 為了方便演示和聯系, 我使用的是本地圖片, 如果大家有需要的話可以嘗試著寫下網絡的, 不過本地和遠端的大致是相同的. 那麽我就來簡單介紹下本地

簡單瀑布

ctype reg 門店銷售 pla rms .html child wal tran 最近需要一個簡單的瀑布流效果,所以網上找了一個,修改了部分代碼 1、輕量代碼,壓縮2kb。 2、適用寬度自適應布局。瀑布流列由css控制。(先加入空列,獲取寬度,刪除空列,根據總寬計算列

【css】最簡單瀑布佈局方法

前言:用column-count就能實現簡單的瀑布流佈局 一、程式碼 <body> <style> .parent { width:100%; -moz-co

一個簡單瀑布效果

window.onload = function(){ // 獲取元素 var oBox = document.getElementById('box'); var oUl = document.getElements

一個簡單瀑布佈局的實現

詳細程式碼下載:http://download.csdn.net/detail/hbblzjy/9537567(實現了瀑布流功能,但是不能新增頭部和底部檢視,如專案中有新增頭部或底部檢視的需求,請自行修改) 實現思路 collectionView能實現各中吊炸天的佈局,其精髓就在於UICollectionVi

iOS自定義UICollectionViewLayout佈局實現瀑布

自定義 UICollectionViewLayout 佈局,實現瀑布流;UICollectionView和UICollectionViewCell 另行建立,這只是佈局檔案, 外界控制器只要遵守協議併成為他的代理並實現代理方法heightForItemAtIndex:返回每個cell的高

UICollectionViewLayout簡單使用(簡單瀑布)

對於需要使用到列表的頁面,一般是使用UITableView或者是UICollectionView來實現。一直以來都是直接使用UICollectionViewFlowLayout,基本都能實現需求功能,但是對於直接利用UICollectionViewLayout來

RecyclerView 實現簡單瀑布的應用

效果 實現程式碼 需要的jar包 com.android.support:recyclerview-v7:28.0.0 com.android.support:cardview-v7:28.0.0 activitymain的xml程式碼 <?xml version=

js簡單瀑布實現

什麼是瀑布流 瀑布流其實就是一種佈局方式,比如說有很多模組,這些模組大小不一,怎樣才能把這些模組相對漂亮的排列到一起?瀑布流就可以很好地解決這個問題。首先把這些模組的寬(高)都設定一樣,然後讓他們像瀑布一樣從上到下依次排列。如果還不清楚的話,強烈建議大家去看一

原生JavaScript實現簡單瀑布

瀑布流,想必大家都有所瞭解,簡單說就是一些等寬不等高的模組組成的頁面,可以一直進行載入,比如淘寶購物介面、百度瀏覽圖片介面,都採用了瀑布流,接下來使用原生JS程式碼進行實現。 html結構: <!DOCTYPE html> <html lang

簡單易懂的瀑布

最原始簡單易懂的瀑布流的佈局方式 <?xml version="1.0" encoding="utf-8"?> <com.example.app_work_three.TitleCustomView android:id="@+id/title" android

iOS之簡單瀑布的實現

前言 超簡單的瀑布流實現,這裡說一下筆者的思路,詳細程式碼在這裡 效果演示 實現思路 collectionView能實現各中吊炸天的佈局,其精髓就在於UICollectionViewLayout,因此我們要自定義一個layout來繼承系統的UICollectionViewLayout,所有工作都在這個

RecyclerView的簡單使用以及實現瀑布效果

RecyclerView 簡介 RecyclerView是support.v7包中的控制元件,可以認為是ListView和GridView的增強版,RecyclerView提供了一個耦合度更低的方式來複用ViewHolder,可以更輕鬆的實現瀑布流的效果,為增加和刪除條目提

簡單好用,支援PC/移動端】 vue-waterfall2 基於Vue.js 瀑布元件

[email protected] 1.寬度自適應,資料繫結特性 2.自定義程度高 3.使用極為簡便,適用於PC/移動端 4.提供Event:loadmore (pc端滑動到底部觸發,移動

固定列寬的簡單瀑布實現

在看JavaScript實戰中看到瀑布流,決定記錄下程式碼,以備不時之需。 首先寫一個HTML程式碼 <!DOCTYPE html> <html> <head> <title>瀑布流</title> <link

iOS 瀑布簡單用法

- (void)viewDidLoad { [super viewDidLoad]; mainScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; [

簡單瀑布小外掛(寬度一定)

瀑布流這個東西,學過很久了,現在把它記錄一下。 簡單說一下原理:定義一個數組儲存第一行中的所有div的高度(如果有間隙,加上間隙),找出第一行中的最小高度,然後下一行第一個div的top值就等於這個最小高度,然後更新儲存的最小高度,繼續重複執行。 如果我們要

簡單粗暴實現RecycleView的瀑布的粘性頭部(非ItemDecoration實現)

專案要用到粘性頭部,以前的ListView和GridView的還好整,RecycleView的一片茫然,在github上找了很多發現好複雜,使用ItemDecoration實現,這貨以我的智商真難搞懂,或者只適配了LinearLayoutManager和Grid

CSS浮動&簡單瀑布佈局

浮動(float) float屬性 left:元素向左浮動 right:元素向又浮動 none:元素不浮動 inherit:從父級繼承浮動屬性 clear屬性 l

WPF下制作的簡單瀑布效果

瀑布流 height value get == protected property loaded rop 原文:WPF下制作的簡單瀑布流效果最近又在搞點小東西,美化界面的時候發現瀑布流效果比較不錯.順便就搬到了WPF,下面是界面 我對WEB前端不熟,JS和CS