练手小demo

一,轮播图

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]];

效果图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值