美文网首页iOS 控件定制ios底层原理iOS学习笔记
iOS进阶|适配器模式(解决设置页面)

iOS进阶|适配器模式(解决设置页面)

作者: 艾江山 | 来源:发表于2016-11-13 20:52 被阅读2295次

前言:

现在各大应用类APP都会有个设置页面,设置界面通常是这种


设置页面.PNG

我们可以发现每一个cell长得很相似但是有会有比较小的差别。

效果:

今天我们要实现的效果:

效果.png
看到这种情况最傻的办法是在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。
cell分析
  • 实现
    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

源码位置

相关文章

网友评论

  • 蜀山之光:你这有个问题,如果再点击的时候需要做传值,动画,block处理等等,你用同一个方法不是还需要判断吗
  • kirito_song:可不可以理解为适配器模式必须要通过协议或者继承来实现?
    kirito_song:@艾江山 嗯嗯。懂了。谢谢
    艾江山:@kirito_song 不是必须,它只是一个中转,把数据处理成你想要的。也可以使用class实现
  • 吴欧:1、你这里面的 accessibilityView 对于相同样式的能复用吗?
    艾江山:@疾风劲草_c920 可以的
    b5cb115ed780:@艾江山 如果是一个有20几行的表单界面,cell样式多,这种模式还能适用吗?
    艾江山:没有,我这里只是提供一个面对模型开发的思路:blush:
  • LD_左岸:有个问题 不知道算不算bug
    //分割线
    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上的子控件 常常遇见蛋疼的匪夷所思的问题:disappointed_relieved:
    艾江山:@左岸__ 控件是加到cell的contentview上的,contentview的层次结构是和accessoryView平行的
    LD_左岸: //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);
    //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);
    }];
    当我这么写的时候 看到了想达到的效果::smile:
  • Beta_0:虽然离iOS渐行渐远、不过先留着吧:relaxed:
  • 0诛仙0:感觉没什么用,是我理解太浅吗,还是你写的比较鸡肋
    a3ff24dd7e3b:像这种不复用的cell直接用静态的不就行了,简单实在,搞不懂这是在搞什么
    艾江山:@0诛仙0 如果你设置页面每一个cell点进去还是一样的tableView这样循环很多层,你在用判断的方式你的代码量,以及维护成本就上来了,我们应该用更好的技术避免自己加班
    艾江山:@0诛仙0 到后期维护的时候就可以看出作用了,特别是大工程。以及设置页面非常复杂的情况。像我demo这种小工程确实没直接判断快
  • cf5fd31d8916:好厉害,棒棒哒👏👏👏
    艾江山:@谣谣归期 谢谢
  • 清無:我把你的设置页面布局【Masonry】完善了下。

    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;
    艾江山:@菲拉兔 我觉得辅助视图用苹果默认的更符合苹果设计的审美,当然这个也是应该根据公司美工取舍距离。如果使用自己添加view当成辅助视图,应该在-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;这个方法内添加控件,setData方法中使用Macsonry的update方法
    第二个使用iOS8的预估高度设置cell自适应,因为目前多数设置页面cell高度一致,而且预估高度执行效率不高,所以没有使用。还是非常感谢您的宝贵意见,希望以后多多交流一起进步
  • 清無:MVVM。。。。
    艾江山:@kelvin943 https://github.com/ReactiveCocoa/ReactiveObjC这个是reactiveOC版本,
    kelvin943:@艾江山 Unable to find a specification for `ReactiveObjC (~> 1.0.1)` 这个pod 为什么搜索不到
    艾江山:@菲拉兔 MVVM还没有具体的研究过
  • f7139db11dcd:能不能做个demo
    艾江山:@城北小客 不应该啊 :joy: 要不是在github上直接搜索AIAnimationDemo
    脚下的斑马线:@艾江山 连接点不开啊
    艾江山:@HZW_sister 点击最后的“源码”,第16个cell就是。或者点击这个链接,喜欢给个star:smile:
    https://github.com/aizexin/AIAnimationDemo
  • Kevin_Jia:你长得太吃藕,不看! :v:

本文标题:iOS进阶|适配器模式(解决设置页面)

本文链接:https://www.haomeiwen.com/subject/ioufpttx.html