一、由于“设置类”控制器就是为了导航多种设置功能,所以它的主界面会包含多项设置,而且每一项点击进去又会包含多项子设置。
所以要将“设置类”控制器抽出来一个父类BaseSettingController(属于TableViewController),让每一个具有多项导航功能的tableViewController都继承于这个父类。
在这个父类要实现所有“设置类”都具有的基本功能:
1、 有一个属性用于保存表数据
//保存表的数据
@property (nonatomic,strong) NSMutableArray *cellData;//暴露出来,保证子类都能继承这个属性
2、要实现数据源和代理方法。具体的表数据则由继承自它的子类具体实现,不在BaseSettingController中实现。
BaseSettingController的实现:
// FYBaseSettingVC.m
#import "FYBaseSettingVC.h"
#import "FYSettingItem.h"
#import "FYSettingItemArrow.h"
#import "FYSettingItemSwitch.h"
#import "MBProgressHUD+MJ.h"
#import "FYSettingGroup.h"
@implementation FYBaseSettingVC
//设置cell的分组样式
- (instancetype)init{
if (self = [super initWithStyle:UITableViewStyleGrouped]) {
//
}
return self;
}
//懒加载
- (NSMutableArray *)cellData{
if (!_cellData) {
_cellData = [NSMutableArray array];
}
return _cellData;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//返回有多少个分组
return self.cellData.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//返回每一组的行数,先获取组,再获取该组的行数
FYSettingGroup *group = self.cellData[section];
return group.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ID = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
// 获取行模型数据
FYSettingGroup *group = self.cellData[indexPath.section];//先获取组
FYSettingItem *item = group.items[indexPath.row];//再获取组中的数据
if (item.icon) {
cell.imageView.image = [UIImage imageNamed:item.icon];
}
cell.textLabel.text = item.title;
//根据不同的行模型的类型确定辅助标志
if ([item isKindOfClass:[FYSettingItemArrow class]]) {//判断不同行的item的类名
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"CellArrow"]];
} else if ([item isKindOfClass:[FYSettingItemSwitch class]]){
cell.accessoryView = [[UISwitch alloc]init];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// 获取行模型数据
FYSettingGroup *group = self.cellData[indexPath.section];//先获取组
FYSettingItem *item = group.items[indexPath.row];//再获取组中的数据
if (item.operation) {//判断是否有特殊操作
item.operation();//有特殊操作执行特殊操作
} else if(item.vcClass) {//判断该行cell的vcClass属性是否有值,有值说明点击该行需要跳转
id vc = [[item.vcClass alloc]init];//创建跳转控制器并加载
[self.navigationController pushViewController:vc animated:YES];
}
}
//设置每组的头标题
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
// 获取组数据
FYSettingGroup *group = self.cellData[section];//先获取组
return group.headerTitle;
}
//设置每组的尾标题
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
// 获取组数据
FYSettingGroup *group = self.cellData[section];//先获取组
return group.footerTitle;
}
@end
二、为每一行数据建模型、为每一组数据建模型
要知道cell一般会包含图标、标题、辅助图标等,但又不是有所有的cell都长得一样,所以创建行数据模型时要考虑:点击该行是否需要跳转(即行模型要有一个属性决定是否能跳转到下一个控制器);辅助标志不一样,有的要显示箭头有的要显示开关(如何判断?可以设计两种行模型,一种是带箭头的SettingItemArrow,一种是带开关的SettingItemSwitch,这两种模型都继承自父类SettingItem,根据不同的类新显示不同的辅助标志)。
行数据模型头文件:
// FYSettingItem.h
#import <Foundation/Foundation.h>
typedef void (^OperationBlock)();//定义一个block
@interface FYSettingItem : NSObject
@property (nonatomic,copy) NSString *icon;//cell的图标
@property (nonatomic,copy) NSString *title;//cell的标题
//添加一个Class属性,用于标注点击cell时将跳转到的下一个控制器的类型
@property (nonatomic,assign) Class vcClass;
//添加一个block属性,保存操作,因为有的cell点击后不是跳转到别的控制器而是执行一段代码,比如“检查软件更新”选项
@property (nonatomic,copy) OperationBlock operation;
- (instancetype)initWithIcon:(NSString *)icon title:(NSString *)title;
+ (instancetype)itemWithIcon:(NSString *)icon title:(NSString *)title;
/**
* 带有控制器类的item模型
*/
+ (instancetype)itemWithIcon:(NSString *)icon title:(NSString *)title vcClass:(Class)vcClass;
@end
行数据模型的实现:
// FYSettingItem.m
#import "FYSettingItem.h"
@implementation FYSettingItem
//对象方法
- (instancetype)initWithIcon:(NSString *)icon title:(NSString *)title{
if ([super init]) {
self.icon = icon;
self.title = title;
}
return self;
}
//类方法
+ (instancetype)itemWithIcon:(NSString *)icon title:(NSString *)title{
return [[self alloc] initWithIcon:icon title:title];
}
+ (instancetype)itemWithIcon:(NSString *)icon title:(NSString *)title vcClass:(Class)vcClass{
FYSettingItem *item = [[self alloc] initWithIcon:icon title:title];
item.vcClass = vcClass;
return item;
}
@end