IOS控件系列二---优雅的UITableView的MVC模式设计,支持自定义下拉刷新/上提加载更多视图(含swift)


demo效果如下:










本小框架设计原则依旧按照之前的惯例:

1.扩展性好,代码不冗余(整个刷新的头部与底部代码不超过300行)。

2.逻辑清晰。

3.回调接口清晰。

4.移植性好。


对于扩展性本框架扩展点如下:

1.框架中的BaseTableView是直接扩展UITableView的,所以可以使用在VC中,也可以作为其他视图的子视图进行使用,具体的使用demo可参看,之前的BossJob项目,各位看客可以在本博客中找。

BossJob项目链接

2.支持一个tableList中的展现不同的Cell同时支持不同的cell展现不同的高度。

3.支持上拉刷新视图与底部加载更多视图的自定义。


二逻辑部分:个人认为还是比较清晰的,如果发现其中逻辑不清晰的地方,在下恳请各位大神不要吝啬您的批评批评指点,博客本身就是一个交流的平台,共同学习进步才是王道。具体的设计思路如下:

1.超类直接重载UITabView 并将如下接口丢给子类去扩展。各接口有详细的注释,此处不重复了。

/**
 初始化接口,子类重载时,可初始化自身的特有的对象
 */
-(void) initAttr;

/**
 构建单元格,子类需要重载此方法,方能达到效果

 @return UITableViewCell
 */
-(BaseTabViewCell*) buildTableViewCell;


/**
 获取单元格高度,子类需要重载

 @return 单元格高度
 */
-(CGFloat) getCellHeight;



/**
 上提加载更多底部视图,子类需要扩展此类,不然后返回的底部加载更多视图是一个默认的视图

 @return 返回一个扩展了ScrollViewRefreshView的具体子类
 */
-(ScrollViewRefreshView*) buildFootView;

-(void(^)()) buildLoadMoreListener;



/**
 构建下拉刷新头部视图,子类需要扩展此类,不然后返回的下拉刷新视图是一个默认的视图

 @return 返回一个扩展了ScrollViewHeadView的具体子类
 */
//-(ScrollViewHeadView*) buildHeadView;

对于展示不同的cell时需要重载

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

能够显示不同的cell是在数据模型的基类中定义了一个枚举,各个数据模型均扩展这个数据基类,然后每个模型返回一个惟一的枚举。在上面的方法时,遍历当前行的单元格获取当前数据的枚举类型,再创建这个cell就可以达到效果。部分代码如下:

数据模型部分:

/**
 构建UItableView cell的类型枚举

 - QuickWordsType: 快捷消息类型
 - QuickWordsType: 快捷消息增加类型
 */
typedef NS_ENUM(NSInteger, CellItemType) {
    
    CellItemDefaultType = 1,
    QuickWordsType,
    QuickWordsAddType,

    
};

/**
 数据类型协议接口,通常用于同一个tableView中展示不同的item类型
 */
@protocol ItemType <NSObject>

@optional
-(CellItemType) getItemType;

@end


/**
 列表中的基类接口
 */
@interface BaseModel : NSObject<ItemType>

@property(nonatomic,weak) id<ItemType> delegate;


@property(nonatomic,copy) NSString* name;

@end

重写如下方法显示不同的cell:

//重写此方法,达到一个列表中展现不同的cell
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    
    BaseModel *baseModel = self.dataList[indexPath.row];
    BaseTabViewCell *cell;
    NSString *cellIdentifier;
    
    switch ([baseModel getItemType]) {
        case ChatHeadType:
            cellIdentifier = @"ChatHeadType";
            break;
        case ChatType:
            cellIdentifier = @"ChatType";
            break;
        default:
            break;
    }
    
    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
    if (!cell) {
        switch ([baseModel getItemType]) {
            case ChatHeadType:
                cell = [[ChatHeadCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
                break;
            case ChatType:
                cell = [[ChatCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
                break;
            default:
                break;
        }
    }
    
    [cell bindData:baseModel];
    return cell;
}

因为不同的cell的高度可能不一致,所以还需要重载如下方法:

//重写此方法达到不同的cell有不同的高度
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    BaseModel *baseModel = self.dataList[indexPath.row];
    CGFloat height = 0.0f;
    
    switch ([baseModel getItemType]) {
            
        case ChatHeadType:
            height = 40.0f;
            break;
            
        case ChatType:
            height = 70.0f;
            break;
            
        default:
            break;
    }

    return height;
}

上面所陈述的内容涵盖了数据模型层 、控制器层、视图层。各位看官请自行分辨。


三。下拉刷新/上提加载更多视图核心设计思路:

监听UIScrollView的contentOffset 用以实现头部或底部视图的插入位置 ,

监听UIScrollView的contentSize用来更新底部加载更多视图的位置 ,因为内容的增长是从上往下增长的,即从0--n位置增长,不然会造成底加载更多视图位置的错乱。而头部永远数据前面的位置。所以不需要担心位置发生错乱。

本框架封装了基类,并将添加的接口封装到的BaseTableView基类中方便子类扩展,在本DEMO中提供了2种使用方式,一种是将视图接口,封装到BaseTableView,另一种是封装到具体的UItableView中,即哪一个列表需要使用上拉/下拉功能,就使用这个接口。


四。回调接口部分,使用block,具体见代码。 


先看控制器层的代码,详细代码如下:

basetableView.h:

#import <UIKit/UIKit.h>
#import "ScrollViewRefreshView.h"
#import "ScrollViewHeadView.h"

@class BaseTabViewCell;
@class BaseRefreshHeadView;





/**
 消息页面,列表基类
 */
@interface BaseTableView : UITableView<UITableViewDataSource,UITableViewDelegate,CAAnimationDelegate>


@property(nonatomic,strong)UITableView* mTableView;

@property(nonatomic,strong)NSMutableArray *dataList;

@property(nonatomic,assign) BOOL bIsRefreshing;

@property(nonatomic,assign) BOOL bIsLoading;

@property(nonatomic,strong) ScrollViewRefreshView* scrollFootView;

@property(nonatomic,strong) ScrollViewHeadView* scrollHeadView;




/**
 初始化接口,子类重载时,可初始化自身的特有的对象
 */
-(void) initAttr;

/**
 构建单元格,子类需要重载此方法,方能达到效果

 @return UITableViewCell
 */
-(BaseTabViewCell*) buildTableViewCell;


/**
 获取单元格高度,子类需要重载

 @return 单元格高度
 */
-(CGFloat) getCellHeight;



/**
 上提加载更多底部视图,子类需要扩展此类,不然后返回的底部加载更多视图是一个默认的视图

 @return 返回一个扩展了ScrollViewRefreshView的具体子类
 */
-(ScrollViewRefreshView*) buildFootView;

-(void(^)()) buildLoadMoreListener;



/**
 构建下拉刷新头部视图,子类需要扩展此类,不然后返回的下拉刷新视图是一个默认的视图

 @return 返回一个扩展了ScrollViewHeadView的具体子类
 */
//-(ScrollViewHeadView*) buildHeadView;

@end

baseTableView.m:

#import "BaseTableView.h"
#import "Constants.h"
#import "BaseModel.h"
#import "BaseTabViewCell.h"


#import "BaseRefreshHeadView.h"

@implementation BaseTableView

-(instancetype) initWithFrame:(CGRect)frame{

    if(self = [super initWithFrame:frame]){
    
        [self initAttr];
    
    }
    return self;

}

-(void) initAttr{

    self.dataList = [NSMutableArray array];
    self.backgroundColor = [UIColor colorWithRed:235.0 / 255.0 green:238.0/255.0 blue:237.0/255.0 alpha:1.0];
    self.delegate = self;
    self.dataSource = self;
    [self reloadData];
    

    [self addSubview:[self buildFootView]];
    [[self buildFootView] loadMore:[self buildLoadMoreListener]];

}

-(BaseTabViewCell*) buildTableViewCell{

    NSLog(@"这里必须重载");
    return [[BaseTabViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BaseTabViewCell"];;
}

-(CGFloat) getCellHeight{

    return 0.0f;
}

#pragma mark - UITableView delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    return [self.dataList count];

}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    
    BaseTabViewCell* cell = [self buildTableViewCell];
    
    [cell setFrame:CGRectMake(0, 0, SCREEN_WIDTH, [self getCellHeight])];
    
    cell.backgroundColor = [UIColor colorWithRed:235.0 / 255.0 green:238.0/255.0 blue:237.0/255.0 alpha:1.0];
    
    BaseModel* data = ((BaseModel* )self.dataList[indexPath.row]);
    
    [cell bindData:data];

    return cell;
    
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    return [self getCellHeight];
}

//-------------------uitableView 协议方法结束-----------------------


-(ScrollViewRefreshView*) buildFootView{

    if(!self.scrollFootView){
        self.scrollFootView = [[ScrollViewRefreshView alloc] initWithFrame:self.frame];
        [self.scrollFootView addTargetWith:self];
    }
    return self.scrollFootView;
}

-(void(^)()) buildLoadMoreListener{

    LoadMoreBlock loadMore = ^(){
        
        
        double delayTime = 3.0;
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delayTime * NSEC_PER_SEC);
        dispatch_after(time, dispatch_get_main_queue(), ^{
            
            [self buildFootView].loadMoreState = LoadMoreNoMoreData;
        });
    };
    
    return loadMore;
}




@end


视图层的代码:

.baseTableViewcell.h


#import <UIKit/UIKit.h>

@class BaseModel;

/**
 列表中基类单元格,所有的单元均需扩展此类
 */
@interface BaseTabViewCell : UITableViewCell


-(void) initItemView;

-(void) bindData:(BaseModel*_Nonnull) data;


/**
 此接口为回收资源接口,子类需要扩展
 */
-(void) recycRes;

@end

basetableViewcell.m

#import "BaseTabViewCell.h"
#import "BaseModel.h"

@implementation BaseTabViewCell


//留给子类类扩展
-(void) initItemView{

}

//留给子类类扩展
-(void) bindData:(BaseModel*_Nonnull) data{
    
}

//回收资源接口
-(void) recycRes{

    NSLog(@"看到此日志信息,说明你已经考滤的很全面了,不过还需要加油^_^");
}

@end



数据层的代码为:

BaseModel.h

#import <UIKit/UIKit.h>



/**
 构建UItableView cell的类型枚举

 - QuickWordsType: 快捷消息类型
 - QuickWordsType: 快捷消息增加类型
 */
typedef NS_ENUM(NSInteger, CellItemType) {
    
    CellItemDefaultType = 1,
    QuickWordsType,
    QuickWordsAddType,

    
};

/**
 数据类型协议接口,通常用于同一个tableView中展示不同的item类型
 */
@protocol ItemType <NSObject>

@optional
-(CellItemType) getItemType;

@end


/**
 列表中的基类接口
 */
@interface BaseModel : NSObject<ItemType>

@property(nonatomic,weak) id<ItemType> delegate;


@property(nonatomic,copy) NSString* name;

@end


baseMOdel.m


#import "BaseModel.h"

@interface BaseModel ()

@end

@implementation BaseModel


-(instancetype) init{

    if(self = [super init]){
    
        self.delegate = self;
    }
    return self;
}

//override 协议接口
-(CellItemType) getItemType{

    return CellItemDefaultType;
}

@end



 上提加载更多视图的代码,名字没取好:请自行忽略名字怪异大笑大笑大笑,对于本视图,本demo中设置一些状态枚举,用来控制刷新的表现过程。

#import <UIKit/UIKit.h>


typedef NS_ENUM(NSInteger,LoadMore){
    
    LoadMoreLoading = 1,
    LoadMoreComplete,
    LoadMoreNoMoreData,
    
};





typedef void(^LoadMoreBlock)(void);

/**
 滚动列表中下拉刷新/上提加载更多的公共刷新视图
 */
@interface ScrollViewRefreshView : UIView


@property(nonatomic,assign) LoadMore loadMoreState;



/**
 初始View布局与全局属性
 */
-(void) initView;

/**
 将当前视图绑定到滚动列表中

 @param scrollView 目标滚动列表
 */
-(void) addTargetWith:(UIScrollView* ) scrollView;



/**
 *  上提加载更多回调接口
 *  @param block 加载更多 block
 */
- (void)loadMore:(void(^)())block;


/**
 加载更多完成接口
 */
-(void) loadMoreComplete;



@end

.m文件:

#import "ScrollViewRefreshView.h"
#import "Constants.h"



#define kRefreshViewWidth  200
#define kRefreshViewHeight 80

#define kMaxPullUpDistance   84
#define MarginForLoadMore  60       //用来控制,上提多少point才调用加载更多接口


@interface ScrollViewRefreshView ()

@property (nonatomic, strong) UIScrollView *scrollView;

@property (nonatomic, assign) CGSize contentSize;
@property (nonatomic, copy) LoadMoreBlock loadMoreBlock;


@property(nonatomic,strong) UILabel* labelRefresh;

@end


@implementation ScrollViewRefreshView

-(instancetype) initWithFrame:(CGRect)frame{
    
    self = [super initWithFrame:CGRectMake(0,CGRectGetHeight(frame), SCREEN_WIDTH, kRefreshViewHeight)];
    
    if(self){
        
    }
    return self;

}

-(void) initView{
    
    
    self.labelRefresh = [[UILabel alloc] initWithFrame:CGRectMake(20, 0, self.frame.size.width, 40)];
    self.labelRefresh.text = @"上提加载更多";
    self.labelRefresh.backgroundColor = [UIColor greenColor];
    [self insertSubview:self.labelRefresh atIndex:0];

}

-(void) addTargetWith:(UIScrollView* ) scrollView {
    
    self.scrollView = scrollView;
    [self.scrollView insertSubview:self atIndex:0];
    [self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    [self.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    self.hidden = NO;
    

    self.labelRefresh = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 40)];
    self.labelRefresh.text = @"上提加载更多";
    self.labelRefresh.textColor = [UIColor greenColor];
    self.labelRefresh.textAlignment = NSTextAlignmentCenter;
    self.labelRefresh.font = [UIFont systemFontOfSize:12.0];
    [self insertSubview:self.labelRefresh atIndex:0];
    
    
    //延迟 0.2s更新位置,防止位置被遮挡
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_main_queue(), ^{
        self.center = CGPointMake(self.center.x, self.contentSize.height + kRefreshViewHeight/2);
    });
}


- (void)loadMore:(void (^)())block{
    self.loadMoreBlock = block;
}

-(void)loadMoreComplete{

    self.loadMoreState  = LoadMoreComplete;

    self.center = CGPointMake(self.center.x, self.contentSize.height + kRefreshViewHeight/2);
}

//override method
-(void) setLoadMoreState:(LoadMore)loadMoreState{
    
    if(_loadMoreState != loadMoreState){
    
         _loadMoreState = loadMoreState;
    }

    switch(_loadMoreState){
    
        case LoadMoreLoading:{
            self.labelRefresh.text = @"正在加载,请稍后...";
            
        }break;
            
        case LoadMoreComplete:{
        
            self.labelRefresh.text = @"上提加载更多";
            
        }break;
        case LoadMoreNoMoreData:{
            
            self.labelRefresh.text = @"---HAPPY END----";
        
        }break;
    
    }

}


#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
    if ([keyPath isEqualToString:@"contentSize"]) {
        self.contentSize = [[change valueForKey:NSKeyValueChangeNewKey] CGSizeValue];
        if (self.contentSize.height >= CGRectGetHeight(self.scrollView.frame)) {
            self.hidden = NO;
        }
        self.center = CGPointMake(self.center.x, self.contentSize.height + kRefreshViewHeight/2); //防止下拉刷新时,位置显示不对的情况
    }
    
    if ([keyPath isEqualToString:@"contentOffset"]) {
        
        if(self.loadMoreState == LoadMoreLoading || self.loadMoreState == LoadMoreNoMoreData) return;
        
        CGPoint contentOffset = [[change valueForKey:NSKeyValueChangeNewKey] CGPointValue];
        
        if (contentOffset.y >= MarginForLoadMore) {
            
            if (!self.scrollView.tracking ) {
                self.hidden = NO;
                self.center = CGPointMake(self.center.x, self.contentSize.height + kRefreshViewHeight/2);
                self.loadMoreState = LoadMoreLoading;
                self.scrollView.contentInset = UIEdgeInsetsMake(0, 0, self.labelRefresh.frame.size.height, 0);
                if (self.loadMoreBlock) {
                    self.loadMoreBlock();
                }

            }
            
        }
    }
}

#pragma mark - dealloc
- (void)dealloc {
    [self.scrollView removeObserver:self forKeyPath:@"contentOffset"];
    [self.scrollView removeObserver:self forKeyPath:@"contentSize"];
}

@end












 下拉刷新视图:


#import <UIKit/UIKit.h>


typedef NS_ENUM(NSInteger,PullDownRefresh){
    
    PullDownRefreshNomral = 1,
    PullDownRefreshing,
    PullDownRefreshComplete,
    
};


typedef void(^PullDownRefreshBlock)(void);

/**
 ScrollView列表的下拉刷新视图
 */
@interface ScrollViewHeadView : UIView


@property (nonatomic, strong) UIScrollView *scrollView;


//@property (nonatomic, assign) CGFloat originOffset;
@property (nonatomic, assign) CGFloat progress;

@property (nonatomic, assign) BOOL isLoading;
@property (nonatomic, assign) BOOL notTracking;

@property(nonatomic,strong) UILabel* labelRefresh;

@property (nonatomic, copy) PullDownRefreshBlock refreshingBlock;

@property(nonatomic,assign) PullDownRefresh refershState;


/**
 将当前视图绑定到滚动列表中
 
 @param scrollView 目标滚动列表
 */
-(void) addTargetWith:(UIScrollView* ) scrollView;



/**
 *  上提加载更多回调接口
 *  @param bolck 下拉刷新 block
 */
- (void) refresh:(PullDownRefreshBlock) bolck;


/**
 加载更多完成接口
 */
-(void) refreshComplete;



@end


.m文件:


#import "ScrollViewHeadView.h"
#import "Constants.h"


#define kRefreshViewWidth  200
#define kRefreshViewHeight 80

#define kMaxPullDownDistance   84

#define MarginForRefrshing  60       //用来控制,上提多少point才调用加载更多接口

@implementation ScrollViewHeadView

-(instancetype) initWithFrame:(CGRect)frame{
    
    self = [super initWithFrame:CGRectMake(0,-kRefreshViewHeight,SCREEN_WIDTH, kRefreshViewHeight)];
    if(self){
        
    }
    return self;
    
}


-(void) addTargetWith:(UIScrollView* ) scrollView {
    
    
    // self.originOffset = 70.0;
    
    self.scrollView = scrollView;
    [self.scrollView insertSubview:self atIndex:0];
    [self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
   
    //self.backgroundColor = [UIColor yellowColor];
    
    self.labelRefresh = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, kRefreshViewHeight)];
    self.labelRefresh.text = @"下拉刷新数据";
    self.labelRefresh.textColor = [UIColor greenColor];
    self.labelRefresh.textAlignment = NSTextAlignmentCenter;
    self.labelRefresh.font = [UIFont systemFontOfSize:12.0];
    [self insertSubview:self.labelRefresh atIndex:0];
    
    
//    //延迟 0.2s更新位置,防止位置被遮挡
//    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC);
//    dispatch_after(time, dispatch_get_main_queue(), ^{
//        self.center = CGPointMake(self.center.x, self.contentSize.height + kRefreshViewHeight/2);
//    });
}

//override --method
-(void) setRefershState:(PullDownRefresh)refershState{
    
    if(_refershState != refershState){
    
        _refershState = refershState;
    }
    
    switch(_refershState){
            
        case PullDownRefreshNomral:{
            
            self.labelRefresh.text = @"下拉刷新数据";
        
        }break;
    
        case PullDownRefreshing:{
            
            self.labelRefresh.text = @"正在刷新,请稍后...";
        
        }break;
            
            
        case PullDownRefreshComplete:{
            
            self.labelRefresh.text = @"刷新完成";
        
        }break;
    
    }

}

-(void) refresh:(PullDownRefreshBlock)bolck{

    self.refreshingBlock = bolck;
}

-(void) refreshComplete{

    self.refershState = PullDownRefreshNomral;
    self.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}


#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"contentOffset"]) {
        
        if(self.refershState == PullDownRefreshing) return;
        
        CGPoint contentOffset = [[change valueForKey:NSKeyValueChangeNewKey] CGPointValue];
        if (MarginForRefrshing + contentOffset.y <= 0) {
            
            if (!self.scrollView.tracking) {
                
                self.refershState = PullDownRefreshing;
                self.scrollView.contentInset = UIEdgeInsetsMake(kMaxPullDownDistance, 0, 0, 0);
                
                if (self.refreshingBlock) {
                    self.refreshingBlock();
                }
            }

        }
    }
}

#pragma mark - dealloc
- (void)dealloc {
    [self.scrollView removeObserver:self forKeyPath:@"contentOffset"];
}

@end


demo源码:github  劳驾留下您的星星与评论,谢谢


swift版本为oc的翻译版本,。。。。。


tab;eView相关的文件:

import Foundation
import UIKit

class BaseTableView : UITableView,UITableViewDelegate,UITableViewDataSource{
    
    
    var dataList:Array<BaseModel>?
    
    
    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        self.frame = frame
        initAttr()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func initAttr(){
        
        self.dataList = Array()
        self.dataSource = self
        self.delegate = self
        
    }

    
    
    /// 获取单元格高度--子类需要重载
    ///
    /// - Returns: 单元格高度
    func getCellHeight() -> CGFloat {
        
        return 70.0
    }
    
    
    /// 构建单元格视图子类需重载,不然显示默认视图
    ///
    /// - Returns: 单元格视图
    func buildTableViewCell() -> BaseTabViewCell {
        print("子类赶紧支重载吧,不然单元格是默认视图")
        
       return BaseTabViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: "BaseCell")
        
    }
    
    //implements protocol
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return (dataList?.count)!
    }
    
    
    //implements protocol
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        
        return getCellHeight()
    }
    
    //implements protocol
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = buildTableViewCell()
        
        cell.frame = CGRect(x : 0, y : 0, width : self.frame.width, height : self.getCellHeight())
        
        
        let data :BaseModel = (dataList?[indexPath.row])!
        
        cell.bindData(data: data)
        
        return cell
    
    }
    
    
}

import Foundation
import UIKit

class QuickWordsView: BaseTableView {
    
    
    
//    init(style: UITableViewStyle, reuseIdentifier: String){
//        //super.init(reuseIdentifier:reuseIdentifier,style:style)
//        
//    }
//    
//    required init?(coder aDecoder: NSCoder) {
//        fatalError("init(coder:) has not been implemented")
//    }
    
    override func initAttr() {
        
        super.initAttr()
        
        
        self.backgroundColor = UIColor.init(red: 235.0 / 255.0, green:238.0/255.0, blue:237.0/255.0, alpha:1.0)
        
        let wrods:[String] = ["能同时开发android/ios","我可以把简历发您看看么?",
                               "我能去贵司面试么?","对不起,贵司提供的职位可能不太适合,谢谢"]
        
        for item in wrods{
        
            let model : QuickWordsModel = QuickWordsModel()
            
            model.name = item
            
            self.dataList?.append(model)
        }
        
        
        //添加底部加载更多视图
        let scrollFootView : ScrollViewRefreshView = ScrollViewRefreshView.init(frame: self.frame)
        scrollFootView.addTargetWith(scrollView: self)
        
        scrollFootView.loadMore = {() ->Void in
        
            if((self.dataList?.count)! > 10){
            
                scrollFootView.setLoadMoreState(loadMoreState: LoadMoreType.LoadMoreNoMoreData)
                return
            }
            
            
            DispatchQueue.main.asyncAfter(deadline:DispatchTime.now() + Double(Int64(3 *  Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)){
                
                for i in 0 ..< 3{
                
                    let model:QuickWordsModel = QuickWordsModel()
                    
                    model.name = String.init(format: "loadmore data %d", i)
                    
                    self.dataList?.append(model)
                }
                
                self.reloadData()
                
                scrollFootView.loadMoreComplete()
                
            }
        }
        
        //添加头部刷新视图
        let scrollHeadView : ScrollViewHeadView = ScrollViewHeadView.init(frame: self.frame)
        scrollHeadView.addTargetWith(scrollView: self)
        scrollHeadView.refrsh(block:{()->Void in
        
            DispatchQueue.main.asyncAfter(deadline:DispatchTime.now() + Double(Int64(3 *  Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)){
                
                self.dataList?.removeAll()
                
                for i in 0 ..< 1{
                    
                    let model:QuickWordsModel = QuickWordsModel()
                    
                    model.name = String.init(format: "refresh data %d", i)
                    
                    self.dataList?.append(model)
                }
                
                self.reloadData()
                
                scrollHeadView.refreshComplete()
                
            }
            
        })
        
    }
    
    
    override func buildTableViewCell() -> BaseTabViewCell {
        return QiuckWordsCell(style:UITableViewCellStyle.default, reuseIdentifier : "QiuckWordsCell")
    }
    
    override func getCellHeight() -> CGFloat {
        
        return 40.0
    }
}



tableViewCell相关文件 ,先上基类文件:

import Foundation
import UIKit


/// UItableView 中的单元格基类  所有的单元格均需要重载本灰
class BaseTabViewCell: UITableViewCell {
    
    
    var label:UILabel?
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        initItemView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    /// 子类需要重载本接口
    func initItemView() {
        
        label = UILabel(frame:CGRect(x : 10.0 , y : self.center.y, width : 80, height:30))
        
        label?.text = "韦小宝"
        
        label?.font = UIFont.systemFont(ofSize: 14)
        
        self.addSubview(label!)
        
    }
    
    
    
    /// 将数据模型与单元格绑定起来,子类需要重载本接口
    ///
    /// - Parameter data: <#data description#>
    func bindData(data:BaseModel){
        
    }
    
    
    /// 回收资源接口,子类必要时重载
    func recycRes(){

    }
    
}



具体的单元格:

import Foundation
import UIKit

class QiuckWordsCell: BaseTabViewCell {
    
    var labelWords:UILabel?
    
    var data:QuickWordsModel?
    
    
    override func initItemView() {
    
        self.backgroundColor = UIColor.clear
        
        labelWords = UILabel(frame:CGRect(x : 10.0 , y : 0, width : self.frame.width, height:30))
        labelWords?.textAlignment = NSTextAlignment.center
        labelWords?.text = "韦小宝"
        
        labelWords?.font = UIFont.systemFont(ofSize: 14)
        
        self.addSubview(labelWords!)
    }
    
    override func bindData(data: BaseModel) {
        
        if self.data != data {
            
            self.data = data as? QuickWordsModel
            labelWords?.text = self.data?.name
        }
    }
}



数据框架类:


import Foundation


enum CellItemType {
    
    case DefaultType
    
    case QuickWordsType
    
    case QuickWordsAddType
    
}


/// 单元格对应的数据类型接口
protocol ItemType {
    
    func getItemType() -> CellItemType
}


class BaseModel : NSObject,ItemType{

    var name:String = "defalue name"
    
    var delegate: ItemType?
    
    override init() {
        super.init()
        
        self.delegate = self
    }
    
    //implement ItemType interface
    func getItemType() -> CellItemType {
        
        return CellItemType.DefaultType
    }
    

}


具体的数据模型:

import Foundation


class QuickWordsModel: BaseModel {
    
    
    override func getItemType() -> CellItemType {
        
        return CellItemType.QuickWordsType
    }
}


在viewController中使用使用


import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        test()
    
    }
    
    func test() {
        
        let qwv: QuickWordsView = QuickWordsView.init(frame:CGRect(x : 0, y : 50,width: self.view.frame.width, height: 400))
        qwv.initAttr()
        qwv.separatorInset = UIEdgeInsetsMake(0, 10, 0, 10)
        qwv.tableFooterView = UIView(frame:CGRect.zero)
        
        self.view.addSubview(qwv)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值