demo效果如下:
本小框架设计原则依旧按照之前的惯例:
1.扩展性好,代码不冗余(整个刷新的头部与底部代码不超过300行)。
2.逻辑清晰。
3.回调接口清晰。
4.移植性好。
对于扩展性本框架扩展点如下:
1.框架中的BaseTableView是直接扩展UITableView的,所以可以使用在VC中,也可以作为其他视图的子视图进行使用,具体的使用demo可参看,之前的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
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
}
}
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.
}
}