UITableView最簡單的用法(CHGAdapter)

UITableView編程之現階段的問題ios

作ios開發的同窗都知道使用UITableView開發的時候必須實現其dataSource、delegate兩個協議,而且須要實現其相應的方法,感受還算簡單。可是隨着開發的深刻愈來愈發現幾乎每一個使用UITableView的頁面都須要實現以上2哥協議實現其方法,並且發現每次實現的邏輯大同小異;感受本身就是代碼的搬運工。並且UITableViewCell和UITableView幾乎是強綁定關係耦合度過高。因爲須要在代理方法中經過indexPath來返回相應的內容所以對之後的業務擴展也很差,哪天產品說這個cell和上面的cell換個位置,這是好可能就須要修改好幾處的delegate方法。git

如下爲傳統使用UITableView的代碼,真實狀況會更加凌亂。github

#import "ViewController.h"

@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic,copy) NSArray *data;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
}

- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
//    根據不一樣的view獲取cell
    UITableViewCell * cell;
    if (indexPath.section == 0) {
        if (indexPath.row == 0) {
            cell = [tableView dequeueReusableCellWithIdentifier:@""];
            cell.textLabel.text = @"";
            cell.imageView.image = [UIImage imageNamed:@""];
        } else if(indexPath.row == 1) {
            cell = [tableView dequeueReusableCellWithIdentifier:@""];
            cell.textLabel.text = @"";
            cell.imageView.image = [UIImage imageNamed:@""];
        } else if (indexPath.row == 0) {
            cell = [tableView dequeueReusableCellWithIdentifier:@""];
            cell.textLabel.text = @"";
            cell.imageView.image = [UIImage imageNamed:@""];
        } else if(indexPath.row == 1) {
            cell = [tableView dequeueReusableCellWithIdentifier:@""];
            cell.textLabel.text = @"";
            cell.imageView.image = [UIImage imageNamed:@""];
        }
    }
    return cell;
}

- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.data.count;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        if (indexPath.row == 0) {
            return 70;
        } else if(indexPath.row == 1) {
            return 80;
        } else if (indexPath.row == 0) {
            return 90;
        } else if(indexPath.row == 1) {
            return 100;
        }
    }
    return 0;
}

@end

那麼咱們再想既然以上代碼每一個UITableView的頁面都有而且邏輯差很少,無非就是根據IndexPath或者其餘條件做爲判斷來返回結果。那麼根據軟件的設計思路,可不能夠把和業務邏輯無關的內容封裝起來呢?答案固然是確定的。那麼咱們就想了,UITableView無非就是須要給Cell提供數據、高度、位置、處理cell點擊等內容,並且這些和業務邏輯確實一點關係都沒有。那麼咱們看看兄弟平臺的Android是如何處理相似的問題的呢?若是瞭解Android的同窗可能會很熟悉,Android的ListView,GridView等等相似控件都是使用Adapter提供數據給ListView、GridView使用以解決以上ios的問題。那麼咱們也能夠參照Android的設計思路來設計ios開發。所以就開發了一款相似Android平臺下的處理方式的框架,而且山寨其命名叫「CHGAdapter」。廢話很少說,咱們先看一下的使用。編程

使用CHGAdapter構建UITableViewswift

ViewController中的寫法 只須要給UITableView提供數據模型網絡

#import <UIKit/UIKit.h>

@interface Test1ViewController : UIViewController

@end
#import "Test1ViewController.h"
#import "Test1Model.h"

@interface Test1ViewController ()

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic,strong) NSArray *data;

@end

@implementation Test1ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.cellDatas = @[self.data];
}

///構造cell的數據,此處模擬  這些數據能夠從網絡獲取
-(NSArray*)data {
    if (!_data) {
        _data = @[
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試1"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試2"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試3"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試4"]
                  ];
    }
    return _data;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

Model寫法 Test1Model類 Model類必須實現CHGTableViewCellModelProtocol,主要返回Model對應的Cell的一些參數,好比當前Model應該使用哪個Cell類,當前Cell的高度應該是多少。另外還能夠根據需求在Model中計算Cell的高度等操做。框架

#import <Foundation/Foundation.h>
#import "CHGAdapter.h"

@interface Test1Model : NSObject<CHGTableViewCellModelProtocol>

@property (nonatomic,strong) NSString *cellClassName;
@property (nonatomic,assign) CGFloat cellHeight;
//如下爲業務參數
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSString *otherProperty2;

+(instancetype)initWithCellClassName:(NSString*)cellClassName cellHeight:(CGFloat)cellHeight name:(NSString*)name;

@end
#import "Test1Model.h"

@implementation Test1Model


+(instancetype)initWithCellClassName:(NSString*)cellClassName cellHeight:(CGFloat)cellHeight name:(NSString *)name{
    Test1Model * t1 = [Test1Model new];
    t1.cellHeight = cellHeight;
    t1.cellClassName = cellClassName;
    t1.name = name;
    return t1;
}


- (NSString *)cellClassNameInTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
    //若是一個model只對應一個cell  這裏能夠寫死,就不須要外部傳入。也能夠根據model的某一個字段來判斷使用哪個cell
    return self.cellClassName;
}

- (CGFloat)cellHeighInTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
    return self.cellHeight;
}

@end

UITableViewCell的寫法 Test1TableViewCell類 必須繼承CHGTableViewCell類ide

#import "CHGTableViewCell.h"

@interface Test1TableViewCell : CHGTableViewCell
@property (weak, nonatomic) IBOutlet UILabel *name;

@end
#import "Test1TableViewCell.h"
#import "Test1Model.h"

@implementation Test1TableViewCell

- (void)awakeFromNib {
    [super awakeFromNib];
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (void)cellForRowAtIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView withData:(id)data {
    [super cellForRowAtIndexPath:indexPath tableView:tableView withData:data];
    Test1Model * t1 = data;
    self.name.text = t1.name;
    
}

@end

運行效果圖以下測試

咱們發現TableView的上下有一塊空白區域,那個空白區域是tableView的HeaderView和FooterView,框架中默認設置HeaderView和FooterView的高度爲30,所以咱們能夠設置其默認高度,代碼以下:ui

#import "Test1ViewController.h"
#import "Test1Model.h"

@interface Test1ViewController ()

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic,strong) NSArray *data;

@end

@implementation Test1ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.cellDatas = @[self.data];
    //設置默認高度
    self.tableView.tableViewAdapter.headerHeight = 0.01;
    self.tableView.tableViewAdapter.cellHeight = 50;
    self.tableView.tableViewAdapter.footerHeight = 0.01;
}

///構造cell的數據,此處模擬  這些數據能夠從網絡獲取
-(NSArray*)data {
    if (!_data) {
        _data = @[
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試1"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試2"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試3"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試4"]
                  ];
    }
    return _data;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

以上代碼設置tableView的header、cell、footer的高度:

self.tableView.tableViewAdapter.headerHeight = 0.01;//設置headerView的默認高度若是在model的協議中有設置則優先使用model中返回的

self.tableView.tableViewAdapter.cellHeight = 50;//設置cell的默認高度,若是在model的協議中有設置則優先使用model中返回的

self.tableView.tableViewAdapter.footerHeight = 0.01;//設置footerView的默認高度若是在model的協議中有設置則優先使用model中返回的

設置後運行效果以下:

咱們看到只有cell,那麼如何添加headerView和footerView呢?請往下看

首先建立header的Model 而且實現CHGTableViewHeaderFooterModelProtocol協議而且實現其required方法

#import <Foundation/Foundation.h>
#import "CHGAdapter.h"

@interface Test1HeaderFooterViewModel : NSObject<CHGTableViewHeaderFooterModelProtocol>

@property (nonatomic,copy) NSString *name;

+(instancetype)initWithName:(NSString*)name;

@end
#import "Test1HeaderFooterViewModel.h"

@implementation Test1HeaderFooterViewModel

+(instancetype)initWithName:(NSString*)name {
    Test1HeaderFooterViewModel * t1hf = [Test1HeaderFooterViewModel new];
    t1hf.name = name;
    return t1hf;
}

- (NSString *)headerFooterClassInTableViw:(UITableView *)tableView section:(NSInteger)section type:(CHGTableViewHeaderFooterViewType)type {
    return @"Test1HeaderFooterView";
}

- (CGFloat)headerFooterHeighInTableViw:(UITableView *)tableView section:(NSInteger)section type:(CHGTableViewHeaderFooterViewType)type {
    return 30;
}

@end

而後添加TableView的headerView  Test1HeaderFooterView類 必須繼承CHGTableViewHeaderFooterView類

#import "CHGTableViewHeaderFooterView.h"
#import "CHGAdapter.h"

@interface Test1HeaderFooterView : CHGTableViewHeaderFooterView

@property (nonatomic,weak) IBOutlet UILabel *name;

@end
#import "Test1HeaderFooterView.h"
#import "Test1HeaderFooterViewModel.h"

@implementation Test1HeaderFooterView

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

- (void)headerFooterForSection:(NSInteger)section inTableView:(UITableView *)tableView withData:(id)data type:(CHGTableViewHeaderFooterViewType)type {
    [super headerFooterForSection:section inTableView:tableView withData:data type:type];
    Test1HeaderFooterViewModel * model = data;
    self.name.text = model.name;
}

@end

這裏偷懶使用xib。可是須要注意使用xib來關聯headerFooterView必需要作以下設置,不然會失敗

而後是ViewController中的設置

#import "Test1ViewController.h"
#import "Test1Model.h"
#import "Test1HeaderFooterViewModel.h"

@interface Test1ViewController ()

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic,strong) NSArray *data;
@property (nonatomic,strong) NSArray *headerData;
@property (nonatomic,strong) NSArray *footerData;

@end

@implementation Test1ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.cellDatas = @[self.data];
    self.tableView.headerDatas = self.headerData;
    self.tableView.footerDatas = self.footerData;//header和footer的全部元素均可以通用包括model和UI
    //設置默認高度
    self.tableView.tableViewAdapter.headerHeight = 0.01;
    self.tableView.tableViewAdapter.cellHeight = 50;
    self.tableView.tableViewAdapter.footerHeight = 0.01;
}

-(NSArray*)headerData {
    if (!_headerData) {
        _headerData = @[
                        [Test1HeaderFooterViewModel initWithName:@"header 標題"]
                        ];
    }
    return _headerData;
}

-(NSArray*)footerData {
    if (!_footerData) {
        _footerData = @[
                        [Test1HeaderFooterViewModel initWithName:@"footer 標題"]
                        ];
    }
    return _footerData;
}

///構造cell的數據,此處模擬  這些數據能夠從網絡獲取
-(NSArray*)data {
    if (!_data) {
        _data = @[
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試1"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試2"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試3"],
                    [Test1Model initWithCellClassName:@"Test1TableViewCell" cellHeight:50 name:@"測試4"]
                  ];
    }
    return _data;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

運行效果圖

上面demo只有一種cell,接下來咱們再建立一種類型的Cell。首先建立一個新model明明Test2Model及cell

Test2Model類

#import <Foundation/Foundation.h>
#import "CHGAdapter.h"

@interface Test2Model : NSObject<CHGTableViewCellModelProtocol>

@property (nonatomic,copy) NSString *placeholder;//輸入框佔位符
@property (nonatomic,copy) NSString *inputText;//輸入的內容

+(instancetype)initWithPlaceholder:(NSString*)placeholder inputText:(NSString*)inputText;

@end
#import "Test2Model.h"

@implementation Test2Model

+(instancetype)initWithPlaceholder:(NSString*)placeholder inputText:(NSString*)inputText {
    Test2Model * t2 = [Test2Model new];
    t2.placeholder = placeholder;
    t2.inputText = inputText;
    return t2;
}

- (NSString *)cellClassNameInTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
    //若是一個model只對應一個cell  這裏能夠寫死,就不須要外部傳入。也能夠根據model的某一個字段來判斷使用哪個cell
    return @"Test2TableViewCell";
}

- (CGFloat)cellHeighInTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
    return 80;
}

@end

Test2TableViewCell類

#import "CHGTableViewCell.h"

@interface Test2TableViewCell : CHGTableViewCell

@property (nonatomic,weak) IBOutlet UITextField *textField;

@end
#import "Test2TableViewCell.h"
#import "Test2Model.h"

@implementation Test2TableViewCell

- (void)awakeFromNib {
    [super awakeFromNib];
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (void)cellForRowAtIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView withData:(id)data {
    [super cellForRowAtIndexPath:indexPath tableView:tableView withData:data];
    Test2Model * model = data;
    self.textField.placeholder = model.placeholder;
    self.textField.text = model.inputText;
}

@end

運行效果

以上是運行效果,是否是在想如何把輸入框的內容實時的在UIViewController中顯示?因爲篇幅問題,講在下一篇文章中詳細介紹。

GitHub地址:

OC版Swift版

碼雲地址:

OC版Swift版

UITableView最簡單的用法(CHGAdapter)事件傳遞

相關文章
相關標籤/搜索