瀑布流接口的设计以及应用(一)

//
//  MyWaterFlowView.h
//  瀑布流
//
//  Created by Jose on 15-7-11.
//  Copyright (c) 2015年 Jose. All rights reserved.
//


#import <UIKit/UIKit.h>
//枚举方法
typedef enum {
    MyWaterFlowViewMarginTypeTop,
    MyWaterFlowViewMarginTypeBottom,
    MyWaterFlowViewMarginTypeLeft,
    MyWaterFlowViewMarginTypeRight,
    //每一列
    MyWaterFlowViewMarginTypeColumn,
    //没一行
    MyWaterFlowViewMarginTypeRow
}MyWaterFlowViewMarginType;


@class MyWaterFlowView,MyWaterFlowViewCell;


/**
 *  数据源方法
 */
@protocol MyWaterFlowViewDataSource <NSObject>
@required


//  一共有多少个数据
//  NSUInteger是无符号类型,即没有负数
-(NSUInteger)NumberOfCellInWaterFlowView:(MyWaterFlowView *)mywaterflowview;


// 返回index位置对应的cell
-(MyWaterFlowViewCell *)WaterFlowViewCell:(MyWaterFlowView *)mywaterflowview CellAtIndex:(NSUInteger)index;
@optional
// 返回一共有多少列
-(NSUInteger)NumberOfColumsInWaterFlowView:(MyWaterFlowView *)mywateflowview;


@end


/**
 *  代理方法
 */
@protocol MyWaterFlowViewDelegate <UIScrollViewDelegate>
@optional


// 返回第index位置cell的高度
-(CGFloat)MyWaterFlowView:(MyWaterFlowView *)mywaterflowview HeightAtIndex:(NSUInteger)index;


// 选中在index位置的cell
-(void)MyWaterFlowView:(MyWaterFlowView *)mywaterflowview DidSelectAtIndex:(NSUInteger)index;


//返回间隙
-(CGFloat)MyWaterFlowView:(MyWaterFlowView *)mywaterflowview MarginType:(MyWaterFlowViewMarginType)type;
@end




@interface MyWaterFlowView : UIScrollView
/** 数据源*/
@property(nonatomic,weak)id<MyWaterFlowViewDataSource>MyDataSource;
/** 代理方法*/
@property(nonatomic,weak)id<MyWaterFlowViewDelegate>MyDelegate;
/** 刷新数据(只要调用这个方法,会重新向数据源和代理发送请求)*/
-(void)ReloadData;
/** 根据标识去缓存池查可重复利用的cell*/
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
/** cell的宽度*/
-(CGFloat)cellWidth;

@end


*************************************************************************************************************************************

************************************************************************************************************************************

*************************************************************************************************************************************
//
//  MyWaterFlowView.m
//  瀑布流
//
//  Created by Jose on 15-7-11.
//  Copyright (c) 2015年 Jose. All rights reserved.
//


#import "MyWaterFlowView.h"
#import "MyWaterFlowViewCell.h"


#define CellHeight 70
#define CellColums 3
#define CellMargin 8


@interface MyWaterFlowView()
/** 存放cell的frame的数组*/
@property(nonatomic,strong)NSMutableArray *CellFrames;
/** 存放正在展示的cell*/
@property(nonatomic,strong)NSMutableDictionary *displayingCells;
/** 缓存池用set存放离开屏幕的cell*/
@property(nonatomic,strong)NSMutableSet *reusableCells;
@end


@implementation MyWaterFlowView


#pragma mark - 初始化
-(NSMutableArray *)CellFrames{
    if (_CellFrames==nil) {
        self.CellFrames=[NSMutableArray array];
    }
    return _CellFrames;
}


-(NSMutableDictionary *)displayingCells{
    if (_displayingCells==nil) {
        self.displayingCells=[NSMutableDictionary dictionary];
    }
    return _displayingCells;
}


-(NSMutableSet *)reusableCells{
    if (_reusableCells==nil) {
        self.reusableCells=[NSMutableSet set];
    }
    return _reusableCells;
}


-(id)initWithFrame:(CGRect)frame{
    self=[super initWithFrame:frame];
    if (self) {
    }
    return self;
}


//对于内存控制很重要
-(void)willMoveToSuperview:(UIView *)newSuperview{
    [self ReloadData];
}




/**
 *  公共接口
 */
-(void)ReloadData{
    //移除正在显示的cell
    [self.displayingCells.allValues makeObjectsPerformSelector:@selector(removeFromSuperview)];
    //清空之前的所有数据
    [self.displayingCells removeAllObjects];
    [self.CellFrames removeAllObjects];
    [self.reusableCells removeAllObjects];
    //获取cell的总数
    int numberofcells=[self.MyDataSource NumberOfCellInWaterFlowView:self];
    //获取总列数
    int numberofcolums=[self NumberOfColumns];
    //获取间距
    CGFloat top=[self MarginForType:MyWaterFlowViewMarginTypeTop];
    CGFloat bottom=[self MarginForType:MyWaterFlowViewMarginTypeBottom];
    CGFloat left=[self MarginForType:MyWaterFlowViewMarginTypeLeft];
    //CGFloat right=[self MarginForType:MyWaterFlowViewMarginTypeRight];
    CGFloat column=[self MarginForType:MyWaterFlowViewMarginTypeColumn];
    CGFloat row=[self MarginForType:MyWaterFlowViewMarginTypeRow];
    
    //4.获取宽度
    //CGFloat cellwidth=(self.width-left-right-(numberofcolums-1)*column)/numberofcolums;
    CGFloat cellwidth=[self cellWidth];
    
    //c语言数组用来存放每一列最大的y值
    CGFloat MaxYOfColumns[numberofcolums];
    for (int i=0; i<numberofcolums; i++) {
        MaxYOfColumns[i]=0.0;
    }
    
    //计算所有cell的frame
    for (int i=0; i<numberofcells;i++) {
        //cell所处最短的那列
        NSUInteger CellColumn=0;
        //cell所处最短那列的最大y值
        CGFloat MaxYOfCellColumn=MaxYOfColumns[CellColumn];
        //求出最短的那一列
        for (int j=1; j<numberofcolums; j++) {
            if (MaxYOfColumns[j]<MaxYOfCellColumn) {
                CellColumn=j;
                MaxYOfCellColumn=MaxYOfColumns[j];
            }
        }
        //询问代理i位置的高度
        CGFloat cellheight=[self HeightAtIndex:i];
        //cell的位置
        CGFloat cellx=left+CellColumn*(cellwidth+column);
        CGFloat celly=0;
        //判断是否是首行
        if (MaxYOfCellColumn==0.0) {
            celly=top;
        }
        else{
            celly=MaxYOfCellColumn+row;
        }
        
        //添加到frame数组中
        CGRect cellframe=CGRectMake(cellx, celly, cellwidth, cellheight);
        [self.CellFrames addObject:[NSValue valueWithCGRect:cellframe]];
        //更新最短那一列的y值
        MaxYOfColumns[CellColumn]=CGRectGetMaxY(cellframe);
        
        //显示cell
        /***
        MyWaterFlowViewCell *cell=[self.MyDataSource WaterFlowViewCell:self CellAtIndex:i];
        cell.frame=cellframe;
        [self addSubview:cell];
         **/
}
    //设置contentsize


    CGFloat contentheight=MaxYOfColumns[0];
    for (int j=1; j<numberofcolums; j++) {
        if (MaxYOfColumns[j]>contentheight) {
            contentheight=MaxYOfColumns[j];
        }
    }
    contentheight+=bottom;
    self.contentSize=CGSizeMake(0,contentheight);
}


-(void)layoutSubviews{
    [super layoutSubviews];
    
    //向数据源索要对应位置的cell
    NSUInteger numberOfCells=self.CellFrames.count;
    for (int i=0; i<numberOfCells; i++) {
        //取出i对应位置的frame
        CGRect cellframe=[self.CellFrames[i]CGRectValue];
        //优先从字典中取出i位置的cell
        MyWaterFlowViewCell *cell=self.displayingCells[@(i)];
        if ([self isInScreen:cellframe]) {
            if (cell==nil) {
                cell=[self.MyDataSource WaterFlowViewCell:self CellAtIndex:i];
                cell.frame=cellframe;
                [self addSubview:cell];
                //存放到字典中
                self.displayingCells[@(i)]=cell;
            }
            
      }
        else{
            if (cell) {
                //从scrollview中移除cell
                [cell removeFromSuperview];
                //从字典中移除cell
                [self.displayingCells removeObjectForKey:@(i)];
                //将移除的cell存放到缓存池中
                [self.reusableCells addObject:cell];
            }
            
        }
        
    }
    
    
}




//返回cell的宽度
-(CGFloat)cellWidth{
    //1.获取总列数
    int numberofcolums=[self NumberOfColumns];
    CGFloat left=[self MarginForType:MyWaterFlowViewMarginTypeLeft];
    CGFloat right=[self MarginForType:MyWaterFlowViewMarginTypeRight];
    CGFloat column=[self MarginForType:MyWaterFlowViewMarginTypeColumn];
    return (self.bounds.size.width-left-right-(numberofcolums-1)*column)/numberofcolums;
}


//从缓存池中取出出可以重复利用的cell
-(id)dequeueReusableCellWithIdentifier:(NSString *)identifier{
    __block MyWaterFlowViewCell *reusableCell=nil;
    [self.reusableCells enumerateObjectsUsingBlock:^(MyWaterFlowViewCell *cell,BOOL *stop){
        if ([cell.identifier isEqualToString:identifier]) {
            reusableCell=cell;
            *stop=YES;
        }
    }];
    if (reusableCell) {
        // 从缓存池移除
        [self.reusableCells removeObject:reusableCell];
    }
    return reusableCell;
    
}






/**
 *  私有方法
 */
//判断一个frame有没有显示在屏幕上
-(BOOL)isInScreen:(CGRect)frame{
    return (CGRectGetMaxY(frame)>self.contentOffset.y)&&(CGRectGetMinY(frame)<self.contentOffset.y+self.bounds.size.height);
}


//获取index位置对应cell的高度
-(CGFloat)HeightAtIndex:(NSUInteger)index{
    if ([self.MyDelegate respondsToSelector:@selector(MyWaterFlowView:HeightAtIndex:)]) {
        return [self.MyDelegate MyWaterFlowView:self HeightAtIndex:index];
    }
    else{
        return CellHeight;
    }
}








//事件处理
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    if (![self.MyDelegate respondsToSelector:@selector(MyWaterFlowView:DidSelectAtIndex:)])return;
    UITouch *touch=[touches anyObject];
    CGPoint point=[touch locationInView:self];
    __block NSNumber *selectIndex=nil;
    [self.displayingCells enumerateKeysAndObjectsUsingBlock:^(id key,MyWaterFlowViewCell *cell,BOOL *stop){
        if (CGRectContainsPoint(cell.frame, point)) {
            selectIndex=key;
            *stop=YES;
        }
    }];
    if (selectIndex) {
        [self.MyDelegate MyWaterFlowView:self DidSelectAtIndex:selectIndex.unsignedIntegerValue];
    }
}


//获取列数
-(NSUInteger)NumberOfColumns{
    if ([self.MyDataSource respondsToSelector:@selector(NumberOfColumsInWaterFlowView:)]) {
        return [self.MyDataSource NumberOfColumsInWaterFlowView:self];
    }
    else{
        return CellColums;
    }
}


//获取间距
-(CGFloat)MarginForType:(MyWaterFlowViewMarginType)type{
    if ([self.MyDelegate respondsToSelector:@selector(MyWaterFlowView:MarginType:)]) {
        return [self.MyDelegate MyWaterFlowView:self MarginType:type];
    }
    else{
        return CellMargin;
    }
}
@end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值