前言:
现在各大应用类APP都会有个设置页面,设置界面通常是这种
我们可以发现每一个cell长得很相似但是有会有比较小的差别。
效果:
今天我们要实现的效果:

看到这种情况最傻的办法是在
tableView
的代理方法里对indexpath
做判断像下面一样👇
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.seesion == 0){
if(indexPath.row == 1){
//todo
}
}else if (indexPath.seesion == 1){
if(indexPath.row == 1){
//todo
}
}
}
这种判断的方法维护的成本可想而知,哪天产品经理觉得第二个session
应该放在第一个位置,第二天又想放回第二位子,小伙子漫漫加班路等着你的。
如果你经验比较多可能会想到面对模型开发,在model
中使用多态,然后在cell
中对进来的model
判断实现对应的效果可以看我这篇文章关于tableview的cell差异不大的处理方法这也是一种比较好的处理方式(demo),但是这种方式对于没加一种新的cell都会对cell代码有所改动,下面我会介绍一种更好用的解决方案
适配器模式:
今天我们要讲的是试用iOS设计模式中的适配器模式来解决这个问题。
简单讲适配器模式的作用就是在封装控件,接收数据的时候,数据通过中间的适配器处理后再传给控件,主要是在自定义控件时使用。

- 分析:
我们把设置页面的cell
看成一个自定义的view
他需要的参数是:iconNameString、titleString、accessibilityView分别为下图的1、2、3。
除了这个三个看得到的参数我们可能还需要cell点击跳转的目标控制器,或者有的cell点击不是跳转到某个页面而是执行一段代码,这里我们把参数写成block。

- 实现
1、创建抽象适配器对象
这里首先创建一个协议AISettingCellAdapterProtocol
#import <Foundation/Foundation.h>
typedef void(^optionBlock)(void);
@protocol AISettingCellAdapterProtocol <NSObject>
- (NSString*)iconNameString;
- (NSString*)titleString;
- (optionBlock)optionBlock;
- (Class)destVC;
- (UIView*)accessibilityView;
@end
协议完成后创建抽象适配器遵循这个协议。由于oc中没有虚函数的说法,我们只有空实现来模拟虚函数
#pragma mark --AISettingCellAdapterProtocol
- (NSString*)iconNameString{
return nil;
}
- (NSString*)titleString{
return nil;
}
- (optionBlock)optionBlock{
return nil;
}
- (Class)destVC{
return nil;
}
- (UIView*)accessibilityView{
return nil;
}
2、适配器与数据层建立输入联系
我们需要再创建一个适配器继承刚才创建的抽象适配器。
/**
装载AISettingModel的适配器
*/
@interface AISettingModelAdapter : AISettingCellAdapter
在这个实体适配器中实现适配方法
#pragma mark --AISettingCellAdapterProtocol
- (NSString*)iconNameString{
AISettingModel *model = self.data;
return model.icon;
}
- (NSString*)titleString{
AISettingModel *model = self.data;
return model.title;
}
- (optionBlock)optionBlock{
AISettingModel *model = self.data;
return model.block;
}
- (Class)destVC{
AISettingModel *model = self.data;
return model.destVC;
}
- (UIView*)accessibilityView{
AISettingModel *model = self.data;
return model.accessibilityView;
}
建立输入链接
AISettingModel *model1 = [[AISettingModel alloc]initWithIcon:@"banben" title:@"版本" destClass:[AIDestOneViewController class] andAccessibilityView:imageiew];
AISettingCellAdapter *adapter1 = [[AISettingModelAdapter alloc]initWithData:model1];
3、适配器与视图层建立输出联系
AISettingTableViewCell *cell = [AISettingTableViewCell createTableViewCellWithTableView:tableView];
AISettingCellAdapter *cellAdapter = self.dataSource[indexPath.section][indexPath.row];
cell.data = cellAdapter;
查看完整的源码第16个cell
喜欢的给个star

网友评论
//分割线
UIView *lineView = [[UIView alloc]init];
lineView.backgroundColor = [UIColor lightGrayColor];
self.lineView = lineView;
[self.contentView addSubview:lineView];
[self.lineView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.iconImageView.mas_right).offset = 8;
make.right.mas_equalTo(@-8);
make.height.mas_equalTo(@1);
make.bottom.mas_equalTo(@0);
}];
这个分割线 距离屏幕的最右边 缩进8个像素? 但是效果不是这样的
用masonry约束cell上的子控件 常常遇见蛋疼的匪夷所思的问题
[self.lineView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.iconImageView.mas_right).offset = 8;
//make.right.mas_equalTo(@-8);
make.height.mas_equalTo(@1);
make.bottom.mas_equalTo(@0);
//make.right.mas_offset(-8);
//make.right.mas_equalTo(self.contentView.mas_right).mas_offset(-8);
// CGFloat width = [UIScreen mainScreen].bounds.size.width - 16;
// make.width.mas_equalTo(width);
// make.right.mas_offset(-8).priorityHigh();
make.right.mas_equalTo(self.mas_right).mas_offset(-8);
}];
当我这么写的时候 看到了想达到的效果:
setData{
self.accView = [data accessibilityView]?[data accessibilityView]:nil;
[self.contentView addSubview:self.accView];
[self.accView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(@(-20));
make.centerY.mas_equalTo(self.contentView);
make.width.equalTo(@(CGRectGetWidth(self.accView.bounds)));
make.height.equalTo(@(CGRectGetHeight(self.accView.bounds)));
}];
}
这样就会让accessoryView始终处于最右边,而ipad上,若用默认的cell.accessoryView去设置的话,两边是有空白区域,且不会铺到右边的。【你可以完善下】
// 还有tableview可以快速自适应:
self.view.autoresizesSubviews = true;
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
第二个使用iOS8的预估高度设置cell自适应,因为目前多数设置页面cell高度一致,而且预估高度执行效率不高,所以没有使用。还是非常感谢您的宝贵意见,希望以后多多交流一起进步
https://github.com/aizexin/AIAnimationDemo