一,轮播图
LCarouselUtils.h
#import <UIKit/UIKit.h>
@class LCarouselUtils;
@protocol LCarouselUtilsDelegate <NSObject>
@required
-(void)lcarouselUtils:(LCarouselUtils*)lscrollView didSelectedPicturedItem:(NSInteger)item;
@end
@interface LCarouselUtils : UIView
@property(nonatomic,strong)UIScrollView * lscrollView;
@property(nonatomic,strong)UIPageControl* lpageControl;
@property(nonatomic,assign)id<LCarouselUtilsDelegate> delegate;
/**
* 创建的轮图图片的个数
*/
@property(nonatomic,assign) NSUInteger itemNumber;
//展示方法
-(void)showLscrollViewWithNSArray:(NSArray *)picArray;
LCarouselUtils.m
#import "LCarouselUtils.h"
@interface LCarouselUtils()<UIScrollViewDelegate>
@property(nonatomic,assign) CGRect ViewFrame;
@property(nonatomic,strong) NSArray * PicArray;
@end
@implementation LCarouselUtils
-(instancetype)initWithFrame:(CGRect)frame{
if(self = [super initWithFrame:frame]){
[self setScrollViewAndPageControl];
_ViewFrame = frame;
self.backgroundColor =[UIColor yellowColor];
}
return self;
}
/**
* 创建scrollView和pageControl对象
*/
-(void)setScrollViewAndPageControl{
//设置scrollView
UIScrollView * myScrollView = [[UIScrollView alloc]initWithFrame:self.bounds];
self.lscrollView = myScrollView;
NSInteger ItemNum = self.itemNumber?self.itemNumber:3;//加入用户没有设置轮播图片的数量,就默认为三张.
self.lscrollView.contentSize = CGSizeMake(self.frame.size.width *ItemNum, self.frame.size.height);
NSLog(@"%@",NSStringFromCGSize(self.lscrollView.contentSize));
//隐藏竖向条,显示横向条
self.lscrollView.showsHorizontalScrollIndicator =YES;
self.lscrollView.showsVerticalScrollIndicator =NO;
self.lscrollView.pagingEnabled = YES;
self.lscrollView.delegate = self;
self.lscrollView.bounces =NO;
[self addSubview:self.lscrollView];
//设置pageControl
UIPageControl * myPageControl = [[UIPageControl alloc]initWithFrame:CGRectMake(0, 0, 100, 30)];
self.lpageControl = myPageControl;
self.lpageControl.numberOfPages =ItemNum;
self.lpageControl.currentPage = 0;
self.lpageControl.center = CGPointMake(self.frame.size.width/2, self.frame.size.height*3/4);
[self.lpageControl addTarget:self action:@selector(pageTurn:) forControlEvents:UIControlEventValueChanged];
[self addSubview:self.lpageControl];
[self bringSubviewToFront:self.lpageControl];
}
#pragma mark --触发方法
//pageControl
-(void)pageTurn:(UIPageControl *)pageControl{
double offset =pageControl.currentPage*(_ViewFrame.size.width);
// 初始化当前视图
self.lscrollView.contentOffset =CGPointMake(offset, 0);
}
//singleRecognizer(手势触发方法)
-(void)SingleTap:(UITapGestureRecognizer *)recognizer{
UIImageView * imageView =(UIImageView *)recognizer.view;
NSInteger item =imageView.tag;
if([self.delegate respondsToSelector:@selector(lcarouselUtils:didSelectedPicturedItem:)]){
[self.delegate lcarouselUtils:self didSelectedPicturedItem:item];//用代理实现触发图片时方法回调
}
}
#pragma mark --展示轮播图
-(void)showLscrollViewWithNSArray:(NSArray *)picArray{
self.PicArray =picArray;
NSUInteger count =picArray.count;
for (int i = 0;i<count; i++) {
UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(i*self.frame.size.width, 0, _ViewFrame.size.width, _ViewFrame.size.height)];
imageView.image=[UIImage imageNamed:picArray[i]];
imageView.userInteractionEnabled =YES;
imageView.tag =i;
imageView.contentMode = UIViewContentModeScaleToFill;
UITapGestureRecognizer * singleRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(SingleTap:)];
singleRecognizer.numberOfTapsRequired = 1;
[self.lscrollView addSubview:imageView];
[imageView addGestureRecognizer:singleRecognizer];
}
UIWindow * window = [UIApplication sharedApplication].keyWindow;
if (!window) {
window =[[UIApplication sharedApplication].windows objectAtIndex:0];
}
UIView * view = [window.subviews objectAtIndex:0];
[view addSubview:self];
}
#pragma mark --scrollView的代理方法
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
int index = fabs(self.lscrollView.contentOffset.x)/_ViewFrame.size.width;
self.lpageControl.currentPage =index;
}
效果图:
总结:
轮播图中的两个重要的方法
#pragma mark --触发方法
//pageControl
-(void)pageTurn:(UIPageControl *)pageControl{
double offset =pageControl.currentPage*(_ViewFrame.size.width);
// 初始化当前视图
self.lscrollView.contentOffset =CGPointMake(offset, 0);//设置偏移量
}
#pragma mark --scrollView的代理方法
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
int index = fabs(self.lscrollView.contentOffset.x)/_ViewFrame.size.width;
self.lpageControl.currentPage =index;//设置当前page
}
仅仅是一个简单的demo,仍可以有很多的拓展方法.比如加定时器实现无线轮播,给没张图片添加标题等等
二,容视图控制器
.h文件
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
.m文件
#import "ViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
#import "ThirdViewController.h"
#import "FourViewController.h"
#import "FivewViewController.h"
#import "UIView+GCSExtension.h"
@interface ViewController ()<UIScrollViewDelegate>
/**
* 标签栏底部的红色指示器
*/
@property(nonatomic,weak) UIView * indicatorView;
/**
* 当前选中的按钮
*/
@property(nonatomic,weak) UIButton * selectedButton;
/**
* 顶部的所有标签
*/
@property(nonatomic,weak) UIView * titlesView;
/**
* 顶部所有内容
*/
@property(nonatomic,weak) UIScrollView * contentView;
/**
* 菜单的数据源
*/
@property(nonatomic,strong) NSArray * sourceArray;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//第一步:添加子控制器
[self setupChildVces];
//第二步:设置标题栏
[self setupTitleView];
//第三步:设置底部的scrollView
[self setupContentView];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark --添加子控制器
-(void)setupChildVces{
FirstViewController * firstVC = [[FirstViewController alloc]init];
[self addChildViewController:firstVC];//将ViewController作为容视图控制器
SecondViewController * secondVC = [[SecondViewController alloc]init];
[self addChildViewController:secondVC];
ThirdViewController * thirdVC =[[ThirdViewController alloc]init];
[self addChildViewController:thirdVC];
FourViewController * fourVC =[[FourViewController alloc]init];
[self addChildViewController:fourVC];
FivewViewController * fiveVC =[[FivewViewController alloc]init];
[self addChildViewController:fiveVC];
}
#pragma mark --设置标题栏
-(void)setupTitleView{
//标签栏整体
UIView * titlesView = [[UIView alloc] init];
titlesView.backgroundColor =[[UIColor yellowColor] colorWithAlphaComponent:0.7];
titlesView.width =self.view.width;
titlesView.height = 35;
titlesView.y =20;
[self.view addSubview:titlesView];
self.titlesView =titlesView;
//底部红色指示器
UIView * indicatorView = [[UIView alloc]init];
indicatorView.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:1];
indicatorView.height = 2;
indicatorView.tag = -1;
indicatorView.y =titlesView.height-indicatorView.height;
self.indicatorView = indicatorView;
//内部的子标签
NSArray * titles =@[@"全部",@"视频",@"声音",@"图片",@"段子"];
CGFloat width =titlesView.width /titles.count;
CGFloat height =titlesView.height;
self.sourceArray =titles;
/**
* 循环创建button按钮
*/
for(NSInteger i = 0;i<titles.count;i++){
UIButton * button = [[UIButton alloc]init];
button.tag = i;
button.height = height;
button.width = width;
button.x =i * width;
[button setTitle:titles[i] forState:UIControlStateNormal];
[button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[button setTitleColor:[UIColor redColor] forState:UIControlStateDisabled];
button.titleLabel.font = [UIFont systemFontOfSize:14];
[button addTarget:self action:@selector(titleclick:) forControlEvents:UIControlEventTouchUpInside];
[titlesView addSubview:button];
//默认点击第一个按钮
if(i==0){
button.enabled =NO;
self.selectedButton=button;
//button 内部label根据文字的内容计算
[button.titleLabel sizeToFit];
//在创建button的循环方法中,对indicatorView进行宽度和X坐标的设置
self.indicatorView.width =button.titleLabel.width;
self.indicatorView.centerX =button.centerX;
}
}
[titlesView addSubview:indicatorView];
}
#pragma mark --设置底部的scrollView
-(void)setupContentView{
//不要自动调整inset
self.automaticallyAdjustsScrollViewInsets =NO;
UIScrollView * contentView =[[UIScrollView alloc]init];
contentView.frame =CGRectMake(0, 55, [UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height-55);
contentView.delegate = self;
contentView.pagingEnabled = YES;
[self.view insertSubview:contentView atIndex:0];//使用[self.view addSubview:contentView];效果一样
contentView.contentSize = CGSizeMake(contentView.width * self.childViewControllers.count, 0);
self.contentView = contentView;
//添加第一个控制器view
for (int i = 0;i<self.sourceArray.count; i++) {
//取出子控制器
UIViewController *vc = self.childViewControllers[i];
vc.view.x =self.view.width*i;
vc.view.y = 0;//设置控制器view的y值为0 默认是20;
vc.view.height = self.contentView.bounds.size.height;//设置控制器view的height值为整个屏幕的高度
[self.contentView addSubview:vc.view];
}
}
#pragma mark --button的触发方法
-(void)titleclick:(UIButton *)button{
//修改按钮状态
self.selectedButton.enabled = YES;
button.enabled = NO;
self.selectedButton = button;
//动画
[UIView animateWithDuration:0.25 animations:^{
self.indicatorView.width =button.titleLabel.width;
self.indicatorView.centerX = button.centerX;
}];
//滚动
CGPoint offset = self.contentView.contentOffset;
offset.x =button.tag * self.contentView.width;
[self.contentView setContentOffset:offset animated:YES];
}
#pragma mark --scrollView的代理方法
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{
//当前索引
NSInteger index = scrollView.contentOffset.x / scrollView.width;
//取出子控制器
UIViewController *vc = self.childViewControllers[index];
vc.view.x = scrollView.contentOffset.x;
vc.view.y = 0;//设置控制器view的y值为0 默认是20;
vc.view.height = scrollView.height;//设置控制器view的height值为整个屏幕的高度
[scrollView addSubview:vc.view];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[self scrollViewDidEndScrollingAnimation:scrollView];
//点击按钮
NSInteger index = scrollView.contentOffset.x / scrollView.width;
[self titleclick:self.titlesView.subviews[index]];
}
效果图:
总结:类比轮播图来实现,只不过,pageControl变成了自己封装的菜单栏.
比较重要的方法实现.(实现方法很多,仅供参考)
#pragma mark --button的触发方法
-(void)titleclick:(UIButton *)button{
//修改按钮状态
self.selectedButton.enabled = YES;
button.enabled = NO;
self.selectedButton = button;
//动画
[UIView animateWithDuration:0.25 animations:^{
self.indicatorView.width =button.titleLabel.width;
self.indicatorView.centerX = button.centerX;
}];
//滚动
CGPoint offset = self.contentView.contentOffset;
offset.x =button.tag * self.contentView.width;
[self.contentView setContentOffset:offset animated:YES];
}
#pragma mark --scrollView的代理方法
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{
//当前索引
NSInteger index = scrollView.contentOffset.x / scrollView.width;
//取出子控制器
UIViewController *vc = self.childViewControllers[index];
vc.view.x = scrollView.contentOffset.x;
vc.view.y = 0;//设置控制器view的y值为0 默认是20;
vc.view.height = scrollView.height;//设置控制器view的height值为整个屏幕的高度
[scrollView addSubview:vc.view];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[self scrollViewDidEndScrollingAnimation:scrollView];
//点击按钮
NSInteger index = scrollView.contentOffset.x / scrollView.width;
[self titleclick:self.titlesView.subviews[index]];
}
三,跑马灯效果
.h文件
@interface LXRunLabel : UIView
//文本label
@property(nonatomic,strong) UILabel * alabel;
//设置滚动时间
@property(nonatomic,assign) NSTimeInterval timeInterval;
//展示label
-(void)showLxRunLabelViewWithSuperView:(UIView *)aView;
//暂停跑马灯效果
-(void)pause;
//启动跑马灯效果
-(void)start;
//继续跑马灯效果
-(void)continues;
@end
.m文件
#import "LXRunLabel.h"
@interface LXRunLabel ()
@property(nonatomic,strong) NSTimer * timer ;//定义定时器
@property(nonatomic,strong) UIView * outView;
@end
@implementation LXRunLabel
-(id)initWithFrame:(CGRect)frame{
if(self =[super initWithFrame:frame]){
self.clipsToBounds = YES;
self.timeInterval = 0.1;
[self setLxRunLabel];
}
return self;
}
//设置lxRunLabel
-(void)setLxRunLabel{
UILabel * runLabel =[[UILabel alloc]initWithFrame:self.bounds];
runLabel.textColor =[UIColor redColor ];
runLabel.text =@"";
runLabel.font =[UIFont systemFontOfSize:17];
self.alabel = runLabel;
[self addSubview:runLabel];
}
-(void)showLxRunLabelViewWithSuperView:(UIView *)aView{
self.timer =[NSTimer scheduledTimerWithTimeInterval:self.timeInterval target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
[aView addSubview:self];
}
//定时器触发方法
-(void)timerAction:(id)sender{
CGPoint currentLabel =self.alabel.center;
if(currentLabel.x<-self.bounds.size.width/2){
self.alabel.center =CGPointMake(self.bounds.size.width*3/2, self.bounds.size.height/2);
}else{
self.alabel.center =CGPointMake(currentLabel.x-5, self.bounds.size.height/2);
}
}
//暂停跑马灯效果
-(void)pause{
self.timer.fireDate =[NSDate distantFuture];
}
//启动跑马灯效果
-(void)start{
self.timer.fireDate =[NSDate distantPast];
}
//继续跑马灯效果
-(void)continues{
self.timer.fireDate=[NSDate date];
}
@end
总结:
效果中主要是通过定时器实时改变label的中心位置来达到滚动的效果
demo中核心方法
-(void)timerAction:(id)sender{
CGPoint currentLabel =self.alabel.center;
if(currentLabel.x<-self.bounds.size.width/2){
self.alabel.center =CGPointMake(self.bounds.size.width*3/2, self.bounds.size.height/2);
}else{
self.alabel.center =CGPointMake(currentLabel.x-5, self.bounds.size.height/2);
}
}
效果图:
四,自定义九宫格
.h文件
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger,NineSquareViewType){
NineSquareViewUIViewType=0,
NineSquareViewUIButtonType,
};
@protocol ModuleDelegate <NSObject>
@optional
-(void)buttonTypeModuleAction:(UIButton *)button;
-(void)ViewTypeModuleAction:(UIGestureRecognizer *)gesture;
@end
@interface NineSquareView : UIView
//列数
@property(nonatomic,assign) NSInteger totalloc;
//行数
@property(nonatomic,assign) NSInteger linage;
//模块的尺寸(默认100,80)
@property(nonatomic,assign) CGSize moduleSize;
//创建模块的背景颜色
@property(nonatomic,strong) UIColor * bGroundColor;
//代理对象
@property(nonatomic,assign) id<ModuleDelegate> delegate;
-(void)createNineSquareViewWith:(UIView *)superView subViewType:(NineSquareViewType)nineSquareViewType;
@end
.m文件
#import "NineSquareView.h"
/*
思路:
1.设置想要的基本的模块尺寸(宽高)和想要创建的列数;
2.根据列数求出各个模块间的间距
3.根据间距,参数。计算出相应模块的位置
*/
@implementation NineSquareView
-(instancetype)initWithFrame:(CGRect)frame{
if (self=[super initWithFrame:frame]) {
self.moduleSize = CGSizeMake(100, 80);
self.totalloc = 3;
self.linage = 3;
self.bGroundColor =[UIColor redColor];
}
return self;
}
-(void)createNineSquareViewWith:(UIView *)superView subViewType:(NineSquareViewType)nineSquareViewType{
//1.设置基本属性
CGFloat W = self.moduleSize.width;
CGFloat H = self.moduleSize.height;
NSInteger totalloc =self.totalloc;
NSInteger linage =self.linage;
//2.确定间隙
CGFloat margin =(self.frame.size.width -W *totalloc) / (totalloc +1);
//3.根据间隙,参数,创建相应的模块位置
for(int index = 0; index <linage * totalloc ; index++){
int col = index %totalloc;
int row = index /totalloc;
CGFloat X =margin + col *(W +margin);
CGFloat Y =margin +row * (H + margin);
switch(nineSquareViewType){
case 0:{
UIButton * button =[[UIButton alloc]initWithFrame:CGRectMake(X, Y, W, H)];
[button setBackgroundColor:self.bGroundColor];
[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
break;
default:{
UIView * view =[[UIView alloc]initWithFrame:CGRectMake(X,Y, W, H)];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureAction:)];
view.backgroundColor =self.bGroundColor;
[view addGestureRecognizer:tapGesture];
[self addSubview:view];
}
break;
}
}
[superView addSubview:self];
}
#pragma mark --触发方法
-(void)buttonAction:(UIButton *)sender{
if([self.delegate respondsToSelector:@selector(buttonTypeModuleAction:)]){
[self.delegate buttonTypeModuleAction:sender];
}
}
-(void)tapGestureAction:(UITapGestureRecognizer *)tapRecogizer{
if ([self.delegate respondsToSelector:@selector(ViewTypeModuleAction:)]) {
[self.delegate ViewTypeModuleAction:tapRecogizer];
}
}
总结:
demo中的核心方法
int col = index %totalloc;
int row = index /totalloc;
CGFloat X =margin + col *(W +margin);
CGFloat Y =margin +row * (H + margin);
效果图
五,自定义UICollectionViewFlowLayout 瀑布流
.h
<pre code_snippet_id="1651881" snippet_file_name="blog_20161026_15_690915" name="code" class="objc">#import <UIKit/UIKit.h>
@interface LxCollectionWaterFallFlow : UICollectionViewFlowLayout
@end
#import "LxCollectionWaterFallFlow.h"
static NSUInteger const kColCount = 3;//列数
@interface LxCollectionWaterFallFlow ()
@property (nonatomic, strong) NSMutableDictionary *attributes;
@property (nonatomic, strong) NSMutableArray *colArr;
@property (nonatomic, assign) UIEdgeInsets edgeInsets;
@property (nonatomic, weak) id<UICollectionViewDelegateFlowLayout> delegate;
@end
@implementation LxCollectionWaterFallFlow
/**
*(1)默认下该方法什么也不做,但在子类实现中,一般在该方法中设定一些必要的layout的结构和初始化需要的参数等
*/
- (void)prepareLayout {
[super prepareLayout];
// 获取总的个数
NSUInteger itemCount = [self.collectionView numberOfItemsInSection:0];
if (!itemCount) {
return;
}
// 初始化
self.attributes = [[NSMutableDictionary alloc] init];
self.colArr = [NSMutableArray arrayWithCapacity:kColCount];
self.delegate = (id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate;
//_colArr 用来存放相邻的三个高度
CGFloat top = .0f;
for (NSUInteger idx = 0; idx < kColCount; idx ++) {
[_colArr addObject:[NSNumber numberWithFloat:top]];
}
// 遍历所有的item,重新布局
for (NSUInteger idx = 0; idx < itemCount; idx ++) {
[self layoutItemAtIndexPath:[NSIndexPath indexPathForItem:idx inSection:0]];
}
}
#pragma mark --私有方法 (为每个Item对象设置相应的frame)
- (void)layoutItemAtIndexPath:(NSIndexPath *)indexPath {
// 获取collectionView的edgeInsets
UIEdgeInsets edgeInsets = self.sectionInset;
if ([self.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]){
edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:indexPath.row];
}
self.edgeInsets = edgeInsets;
// 获取collectionView的itemSize
CGSize itemSize = self.itemSize;
if ([self.delegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
}
/****************************************核心代码************************************************/
// 遍历相邻三个高度获取最小高度
NSUInteger col = 0;
CGFloat shortHeight = [[_colArr firstObject] floatValue];
for (NSUInteger idx = 0; idx < _colArr.count; idx ++) {
CGFloat height = [_colArr[idx] floatValue];
if (height < shortHeight) {
shortHeight = height;
col = idx;
}
}
/**
* 释义:_colArr在出事时,为_colArr=[@"0",@"0",@"0"]; 通过循环取最小值,
i=0时 最小值肯定为_colArr[0] ,所以假如此时的item height为50, 那么此时的_colArr就会变成 _colArr=[@"50",@"0",@"0"];
i=1时 最小值肯定为_colArr[1] ,因为50时大于0,所以假如此时的item height为60,那么此时的_colArr就变成
_colArr=[@"50",@"60",@"0"]
i=2时,最小值肯定为_colorArr[2],因为50或者60都大于0, 所以假如此时的item height为30,那么此时的_colArr就变成了_colArr=[@"50",@"60",@"30"]
i=3时,最小值肯定为_colorArr[2],因为50,60都大于0, 所以假如此时的item height为65,那么此时的_colArr就变成了_colArr =[@"50",@"70",@"95"];
*/
// 得到最小高度的当前Y坐标起始高度
float top = [[_colArr objectAtIndex:col] floatValue];
// 设置当前cell的frame
CGRect frame = CGRectMake(edgeInsets.left + col * (edgeInsets.left + itemSize.width), top + edgeInsets.top, itemSize.width, itemSize.height);
// 把对应的indexPath存放到字典中保存
[_attributes setObject:indexPath forKey:NSStringFromCGRect(frame)];
// 跟新colArr数组中的高度
[_colArr replaceObjectAtIndex:col withObject:[NSNumber numberWithFloat:top + edgeInsets.top + itemSize.height]];
/****************************************核心代码************************************************/
}
/**
*(2)返回collectionView的内容尺寸(没有滚动)
通过_colArr数组中cell.height 得到collectionView 的contentSize
*/
- (CGSize)collectionViewContentSize {
CGSize size = self.collectionView.frame.size;
CGFloat maxHeight = [[_colArr firstObject] floatValue];
//查找最高的列的高度
for (NSUInteger idx = 0; idx < _colArr.count; idx++) {
CGFloat colHeight = [_colArr[idx] floatValue];
if (colHeight > maxHeight) {
maxHeight = colHeight;
}
}
size.height = maxHeight + self.edgeInsets.bottom;
return size;
}
/**
*(3)系统方法,获取当前可视界面显示的UICollectionViewLayoutAttributes数组(返回rect中的所有的元素的布局属性)
遍历所有_attributes 获取到rect内所有的cell; 并返回给collectionView
*/
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
// 把能显示在当前可视界面的所有对象加入在indexPaths 中
NSMutableArray *indexPaths = [NSMutableArray array];
for (NSString * rectStr in _attributes) {
CGRect cellRect = CGRectFromString(rectStr);
if (CGRectIntersectsRect(cellRect, rect)) {
NSIndexPath *indexPath = _attributes[rectStr];
[indexPaths addObject:indexPath];
}
}
/**
* CGRectIntersectsRect(rect 1,rect 2)可以判断矩形结构是否交叉,两个矩形对象是否重叠。
*/
// 返回更新对应的UICollectionViewLayoutAttributes数组
NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:indexPaths.count];
for (NSIndexPath *indexPath in indexPaths) {
UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexPath];
[attributes addObject:attribute];
}
return attributes;
}
/**
* (4)更新对应UICollectionViewLayoutAttributes的frame
*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
for (NSString *frame in _attributes) {
if (_attributes[frame] == indexPath) {
attributes.frame = CGRectFromString(frame);
}
}
return attributes;
}
@end
.m
总结:
demo核心方法
// 遍历相邻三个高度获取最小高度
NSUInteger col = 0;
CGFloat shortHeight = [[_colArr firstObject] floatValue];
for (NSUInteger idx = 0; idx < _colArr.count; idx ++) {
CGFloat height = [_colArr[idx] floatValue];
if (height < shortHeight) {
shortHeight = height;
col = idx;
}
}
/**
* 释义:_colArr在出事时,为_colArr=[@"0",@"0",@"0"]; 通过循环取最小值,
i=0时 最小值肯定为_colArr[0] ,所以假如此时的item height为50, 那么此时的_colArr就会变成 _colArr=[@"50",@"0",@"0"];
i=1时 最小值肯定为_colArr[1] ,因为50时大于0,所以假如此时的item height为60,那么此时的_colArr就变成
_colArr=[@"50",@"60",@"0"]
i=2时,最小值肯定为_colorArr[2],因为50或者60都大于0, 所以假如此时的item height为30,那么此时的_colArr就变成了_colArr=[@"50",@"60",@"30"]
i=3时,最小值肯定为_colorArr[2],因为50,60都大于0, 所以假如此时的item height为65,那么此时的_colArr就变成了_colArr =[@"50",@"70",@"95"];
*/
// 得到最小高度的当前Y坐标起始高度
float top = [[_colArr objectAtIndex:col] floatValue];
// 设置当前cell的frame
CGRect frame = CGRectMake(edgeInsets.left + col * (edgeInsets.left + itemSize.width), top + edgeInsets.top, itemSize.width, itemSize.height);
// 把对应的indexPath存放到字典中保存
[_attributes setObject:indexPath forKey:NSStringFromCGRect(frame)];
// 跟新colArr数组中的高度
[_colArr replaceObjectAtIndex:col withObject:[NSNumber numberWithFloat:top + edgeInsets.top + itemSize.height]];
效果图: