幾乎每一個App都有一個設(shè)置菜單頁,而且他們幾乎都長這樣:
反面教材
最簡單最原始的做法是這樣的:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"
forIndexPath:indexPath];
switch (indexPath.row) {
case 0:
// configure cell
break;
case 1:
// configure cell
break;
case 2:
// configure cell
break;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
switch (indexPath.row) {
case 0:
// click cell 0
break;
case 1:
// click cell 1
break;
case 2:
// click cell 2
break;
}
}
這樣做不僅違反了DRY原則,在菜單項比較多的情況下煩不勝煩,而且一旦需要修改某個菜單項的內(nèi)容,或者插入或者刪除,修改起來都是非常容易出錯的,換句話說,可維護性非常差。
抽象、依賴轉(zhuǎn)移
通過觀察我們可以發(fā)現(xiàn),這些列表的結(jié)構(gòu)非常相似,那么很自然地我們可以想到建立一個通用的模型來表示一個菜單.
KOSettingItem.h
@interface KOSettingItem : NSObject
@property (copy, nonatomic) NSString *title;
@property (strong, nonatomic) UIImage *imageIcon;
@property (assign, nonatomic) UITableViewCellAccessoryType accessoryType;
@property (copy, nonatomic) void(^handleCallback)();
+ (instancetype) itemWithTitle:(NSString *)title
icon:(UIImage *)image;
+ (instancetype) itemWithTitle:(NSString *)title
icon:(UIImage *)image
block:(void(^)())handle;
- (id)initWithTitle:(NSString *)title
icon:(UIImage *)image
block:(void(^)())handle;
@end
KOSettingItem.m
@implementation KOSettingItem
+ (instancetype) itemWithTitle:(NSString *)title
icon:(UIImage *)image{
return [[self alloc] itemWithTitle:title icon:image];
}
+ (instancetype) itemWithTitle:(NSString *)title
icon:(UIImage *)image
block:(void(^)())handle{
KOSettingItem *item = [[self alloc] initWithTitle:title icon:image block:handle];
return item;
}
- (id)initWithTitle:(NSString *)title
icon:(UIImage *)image
block:(void(^)())handle{
if (self = [super init]) {
self.title = title;
self.imageIcon = image;
self.handleCallback = handle;
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return self;
}
@end
一個簡單的模型就這樣建好了,其中我們用block寫了一個handleCallback用來處理表格的點擊事件,接著我們來應(yīng)用到TableView中,首先新增一個property @property (strong, nonatomic) NSArray *settingItems;
然后在ViewDidLoad中
KOSettingItem *item1 = [KOSettingItem itemWithTitle:@"菜單1" icon:[UIImage imageNamed:@"Carrot"]];
[item1 setHandleCallback:^{
NSLog(@"點擊菜單1");
}];
KOSettingItem *item2 = [KOSettingItem itemWithTitle:@"菜單2" icon:[UIImage imageNamed:@"Owl"]];
[item1 setHandleCallback:^{
NSLog(@"點擊菜單2");
}];
KOSettingItem *item3 = [KOSettingItem itemWithTitle:@"菜單3" icon:[UIImage imageNamed:@"Rubber-Duck"]];
[item1 setHandleCallback:^{
NSLog(@"點擊菜單3");
}];
KOSettingItem *item4 = [KOSettingItem itemWithTitle:@"菜單4" icon:[UIImage imageNamed:@"Snowman"]];
[item1 setHandleCallback:^{
NSLog(@"點擊菜單4");
}];
self.settingItems = @[item1, item2, item3, item4];
最后修改一下TableView的Datasource和Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.settingItems.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 44;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"
forIndexPath:indexPath];
KOSettingItem *item = self.settingItems[indexPath.row];
cell.textLabel.text = item.title;
cell.imageView.image = item.imageIcon;
cell.accessoryType = item.accessoryType;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
KOSettingItem *item = self.settingItems[indexPath.row];
if (item.handleCallback) {
item.handleCallback();
}
}
我們發(fā)現(xiàn)再也不需要冗長的switch語句,如果需要增刪菜單項,只需要修改settingItems里面的item順序,并且由于點擊事件綁定到KOSettingItem里面,也不需要擔心事件與item不對應(yīng)的情況,除非有特殊的樣式需求,我們可以幾乎不用再更改UITableViewDataSource與UITableViewDelegate的實現(xiàn)。
尾聲
文章只是提供了一個思路,而且出于簡明的目的KOSettingItem的模型非常簡單,實際上你可以通過添加變量達到更多的可定制化效果,比如分割線的offset,自定義的accessoryView等等,完整的demo可以戳這里。
運行一下,最后的結(jié)果如圖,雖然依舊平淡無奇 :)