IOS控制元件系列二---優雅的UITableView的MVC模式設計,支援自定義下拉重新整理/上提載入更多檢視(含swift)
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
}
}
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.
}
}
相關推薦
IOS控制元件系列二---優雅的UITableView的MVC模式設計,支援自定義下拉重新整理/上提載入更多檢視(含swift)
demo效果如下: 本小框架設計原則依舊按照之前的慣例: 1.擴充套件性好,程式碼不冗餘(整個重新整理的頭部與底部程式碼不超過300行)。 2.邏輯清晰。 3.回撥介面清晰。 4.移植性好。 對於擴充套件性本框架擴充套件點如下: 1.框架中的
IOS控制元件系列----使用UITableView實現網格佈局,自定義顯示列數
先放一引效果圖: 在IOS中達到類似Android中的GridLayout 通常是使用UIConlectionView,這個元件是平果公司已經封裝好的,直接實現相應的介面即可。不知道各位道友是否也曾想過用UItableView來擼一個這個東西,這可能會有一點偏執,但對
自定義下拉重新整理上拉載入控制元件(SwipeRefreshLayout + recyclerView)
感覺還可以的star下謝謝! 效果圖:(效果圖迴圈播放後,總感覺有些詭異!, 可能是gif截的點不對, 在手機上看效果正常的) 我就不講程式碼是如何實現的了。說下實現了什麼內容: 支援自動下拉重新整理 //設定自動下拉重新整理,切記要
iOS開發-ios7下拉重新整理 上提載入快速整合
在ios7之前,一直在使用開源的EGO庫。但是,在使用過程中發現,普遍封裝得過於複雜、耦合性強,不利於整合到自己的專案中。另外,在ios7之後,一些原有的下拉重新整理,上提載入控制元件表現的就不是那麼出色了。除了可能出錯外,也不符合扁平化的風格。後來,在code4App上發現了
自定義下拉重新整理控制元件-仿美團重新整理效果
概述 下拉重新整理是平時專案中最常用的功能,今天要說的就是如何自定義下拉重新整理控制元件。 第三方重新整理控制元件也比較多,例如Android-PullToRefresh,XListView等,但是這些控制元件自定義重新整理頭部不那麼容易擴充套件,它
android自定義下拉重新整理和上拉載入控制元件
import android.content.Context; import android.graphics.Point; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.NestedScro
優雅地為RecyclerView加上頭部、下拉重新整理、自動載入
一、概述 我們在寫專案的時候,永遠都離不開ListView、RecyclerView這類的控制元件,幾乎是在任何的APP中都可以看到他們的影子,但是RecyclerView並沒有像ListView提供了addHeadView、addFooterView
畢業設計之android混合模式開發第一天--具有下拉重新整理和頁面載入等待的WebView搭建
第一次真正接觸android的混合模式開發,之前瞭解過如何進行混合模式的開發,常見的是通過WebView元件載入url,使用HTML5和CSS3構建手機端響應式佈局。 今天主要是搭建出一個可載入url,具有下拉重新整理和頁面等待的WebView。 2.頁面等待的實現主要是
C#:C#控制元件系列二 (文字框類控制元件)
文字框類控制元件1. Label 控制元件1.1. 常用屬性:1.1.1. Text屬性:用來設定或返回標籤控制元件中顯示的文字資訊。1.1.2. AutoSize屬性:用來獲取或設定一個值,該值指示是否自動調整控制元件的大小以完整顯示其內容。—— 取值為true時,控制元
Android自定義控制元件系列二:自定義開關按鈕(一)
這一次我們將會實現一個完整純粹的自定義控制元件,而不是像之前的組合控制元件一樣,拿系統的控制元件來實現;計劃分為三部分:自定義控制元件的基本部分,和自定義控制元件的自定義屬性; 下面就開始第一部分的編寫,本次以一個定義的開關按鈕為例,下面就開始吧: 先看看效果,一個點選開
Android自定義控制元件系列(二)—icon+文字的多種效果實現
今天給大家帶來一個很簡單但是很常用的控制元件ButtonExtendM,在開發中我們經常會用到圖片加文字的組合控制元件,像這樣: 以上圖片都是從微信上擷取的。(暫時沒有找到icon在下,文字在上的例子) 下面我們通過一個控制元件來實現上下左右全部
Android自定義控制元件實戰——實現仿IOS下拉重新整理上拉載入 PullToRefreshLayout
下拉重新整理控制元件,網上有很多版本,有自定義Layout佈局的,也有封裝控制元件的,各種實現方式的都有。但是很少有人告訴你具體如何實現的,今天我們就來一步步實現自己封裝的 PullToRefreshLayout 完美的解決下拉重新整理,上拉載入問題。
自個兒寫Android的下拉重新整理/上拉載入控制元件
前段時間自己寫了一個能夠“通用”的,支援下拉重新整理和上拉載入的自定義控制元件。可能現如今這已經不新鮮了,但有興趣的朋友還是可以一起來看看的。 與通常的View配合使用(比如ImageView) 與ListView配合使用 與Recycl
RecyclerView實現下拉重新整理與自動載入控制元件封裝
CommonAdapter.java public abstract class CommonAdapter<T> extends RecyclerView.Adapter<ViewHolder> { protected Context mContext; prot
Android自定義控制元件並且使其可以在xml中自定義屬性
package org.xiaom.customView.view; import org.xiaom.customView.R; public class MyView extends LinearLayout { private View root = null; // 上面的img priva
JAVA應用程式整合控制元件JxBrowser v7.2來啦!允許自定義錯誤頁面
JxBrowser更新至最新版v7.2,允許針對HTTP和網路錯誤覆蓋標準Chromium錯誤頁面,允許設定不安全的來源視為安全,改進多種功能,修復多項Bug,具體更新情況如下: 新增功能 自定義錯誤頁面:通過兩個新的回撥擴充套件了API,該回調允許針對HTTP和網路錯誤覆蓋標準Chrom
使用 CSS overscroll-behavior 控制滾動行為:自定義下拉刷新和溢出效果
pull str 新的 title contain 下拉刷新 介紹 select data CSS 的新屬性 overscroll-behavior 允許開發者覆蓋默認的瀏覽器滾動行為,一般用在滾動到頂部或者底部。 背景 滾動邊界和滾動鏈接(boundary & c
Android打造 ListView GridView等 通用的下拉重新整理 上拉自動載入的元件
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
vue自定義下拉框元件
<template> <div class="selection-component"> <div class="selection-show" @click="toggleDrop"> <span :class="{'active': isDr
IOS-給UIScrollView(包括繼承它的UITableView、UICollectionView)新增下拉重新整理-上拉載入更多
IOS裡面用到的下拉重新整理、上拉載入更多控制元件,開源的第三方框架很多,我們可以直接拿過來用,別人造好的輪子我們就沒有必要再造一遍了,這裡推薦幾款下拉重新整理、上拉載入更多控制元件 只有下拉重新整