zoukankan      html  css  js  c++  java
  • iOS开发之设置界面的抽取

    几乎每款app都会有一个设置的界面!!!

    那么我们的设置界面到底要怎么写才能最方便使用呢?下面我就来说说我的想法。

    1.观察原型图

    2.找出相同的东西,目的是抽出一个基类模块,只要我写好了这个控制器,其它的界面全部都写好了

    3.判断是用纯代码还是storyboard,如果界面的控件位置都是固定,用storyboard。

    什么时候用静态单元格:如果界面cell跟系统自带的cell完全差不多,就可以选择静态单元格

    如果不相似:

    1.判断其它cell是否全部差不多,如果全部差不多,可以使用静态单元格

    2.如果界面差别很大,就不使用静态单元格,就用代码

    然后要注意一点的就是循环利用的问题了

    如果一个控件,经常循环利用,就不能在给这个控件属性赋值的时候,添加它的子控件,应该在初始化这个控件的时候把所有的子控件加上去

    注意在循环利用的时候,只要有if就一定要有else,else做的事情就是把之前的状态清空,就是还原最开始的状态。

    那么下面我们就来抽取设置界面:

    首先继承UITableViewController写一个BasicSettingViewController
    .h
    //这一组有多少行cell<SettingItem>
    @property (nonatomic, strong) NSMutableArray *groups;
    .m
    #import "BasicTableViewController.h"
    #import "GroupItem.h"
    #import "SettingItem.h"
    #import "BasicCell.h"
    
    @interface BasicTableViewController ()
    
    @end
    
    @implementation BasicTableViewController
    
    //让这个类一初始化就是组样式的
    - (instancetype)init { return [self initWithStyle:UITableViewStyleGrouped]; } - (void)viewDidLoad { [super viewDidLoad];
    //设置tableView的一些基本信息 self.tableView.backgroundColor
    = [UIColor colorWithRed:211 green:211 blue:211 alpha:1]; self.tableView.sectionHeaderHeight = 10; self.tableView.sectionFooterHeight = 0; self.tableView.contentInset = UIEdgeInsetsMake(-25, 0, 0, 0); self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; } //一定要对组进行懒加载,不然的话,子类是没有办法初始化他的 - (NSMutableArray *)groups { if (!_groups) { _groups = [NSMutableArray array]; } return _groups; } #pragma mark - Table view data source //返回组数 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Incomplete implementation, return the number of sections return self.groups.count; } //返回行数 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete implementation, return the number of rows GroupItem *group = self.groups[section]; return group.items.count; } //初始化cell并给cell赋值 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { BasicCell *cell = [BasicCell cellWithTableView:tableView]; GroupItem *group = self.groups[indexPath.section]; SettingItem *item = group.items[indexPath.row]; cell.item = item; [cell setIndexPath:indexPath rowCount:group.items.count]; return cell; } //返回脚部标题 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { GroupItem *group = self.groups[section]; return group.footTitle; } //返回头部标题 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { GroupItem *group = self.groups[section]; return group.headTitle; } //当cell选中的时候执行该方法 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; GroupItem *group = self.groups[indexPath.section]; SettingItem *item = group.items[indexPath.row]; if (item.destVc) {//如果有跳转就执行跳转 UIViewController *destVc = [[item.destVc alloc] init]; [self.navigationController pushViewController:destVc animated:YES]; } if (item.option) {//哪个cell有事情就做事情(自己的事情自己干) item.option(); } }

    设置组模型(基类):

    @interface GroupItem : NSObject
    //每一组的行数
    @property (nonatomic, strong) NSArray *items;
    //头标题
    @property (nonatomic, copy) NSString *headTitle;
    //脚标题
    @property (nonatomic, copy) NSString *footTitle;
    
    @end
    typedef void (^SettingItemOption) ();
    
    @interface SettingItem : NSObject
    //左边神图
    @property (nonatomic, strong) UIImage *image;
    //标题
    @property (nonatomic, copy) NSString *title;
    //子标题
    @property (nonatomic, copy) NSString *subTitle;
    @property (nonatomic, assign) Class destVc;//跳转到目标控制器(最好不要用NSString)
    @property (nonatomic, copy) SettingItemOption option;//在ARC模型下只能使用copy,MRC可以使用copy或者strong,为了把他放到堆内存中,如果放在栈内存中会被释放
    
    //提供两个创建的item的方法
    + (instancetype)itemWithTitle:(NSString *)title;
    + (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image;
    
    @end

    因为内容是根据模型的改变而改变,那么我们就创建几个模型(继承于SettingItem):

    每个基类要是有自己特有的一些属性也可以设置

    @interface ArrowItem : SettingItem
    
    @end
    @interface BadgeItem : SettingItem
    
    @property (nonatomic, copy) NSString *badgeValue;
    
    @end
    @interface SwitchItem : SettingItem
    
    @property (nonatomic, assign) BOOL isOn;//是否打开
    
    @end
    @interface LabelItem : SettingItem
    
    @property (nonatomic, copy) NSString *text;//label上面的text
    
    @end
    @interface CheakItem : SettingItem
    
    @property (nonatomic, assign) BOOL isCheak;//是否打勾
    
    @end

    设置的cell(基类):

    @class SettingItem;
    
    @interface BasicCell : UITableViewCell
    //根据settingItem模型来显示内容
    @property (nonatomic, strong) SettingItem *item;
    //给外部提供一个创建cell的方法
    + (instancetype)cellWithTableView:(UITableView *)tableView;
    //设置每一组的背景图片的方法
    - (void)setIndexPath:(NSIndexPath *)indexPath rowCount:(NSInteger)rowCount; @end
    @interface BasicCell ()
    //这里一定要用strong,因为是加在视图上面而不是加在contentView;
    //箭头格式的cell
    @property (nonatomic, strong) UIImageView *arrowView;
    //开关格式的cell
    @property (nonatomic, strong) UISwitch *switchView;
    //打勾格式的cell
    @property (nonatomic, strong) UIImageView *cheakView;
    //label格式的cell
    @property (nonatomic, weak) UILabel *labelView;
    
    @end
    
    //不变形的拉伸图片(一般要是写项目最好写成category)
    @implementation UIImage (Resizable)
    
    + (UIImage *)resizableWithImageName:(NSString *)imageName {
        UIImage *image = [UIImage imageNamed:imageName];
        return [image stretchableImageWithLeftCapWidth:image.size.width/2 topCapHeight:image.size.height/2];
    }
    
    @end
    
    @implementation BasicCell
    
    #pragma mark - 对所有的控件懒加载
    
    - (UIImageView *)arrowView
    {
        if (_arrowView == nil) {
            _arrowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"common_icon_arrow"]];
        }
        return _arrowView;
    }
    
    - (UISwitch *)switchView
    {
        if (_switchView == nil) {
            _switchView = [[UISwitch alloc] init];
            [_switchView addTarget:self action:@selector(switchChange:) forControlEvents:UIControlEventValueChanged];
            
        }
        return _switchView;
    }
    
    - (UIImageView *)cheakView
    {
        if (_cheakView == nil) {
            _cheakView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"common_icon_checkmark"]];
        }
        return _cheakView;
    }
    
    - (UILabel *)labelView {
        if (!_labelView) {
            UILabel *labelView = [[UILabel alloc] initWithFrame:self.bounds];
            labelView.textAlignment = NSTextAlignmentCenter;
            labelView.textColor = [UIColor redColor];
            [self.contentView addSubview:labelView];
            _labelView = labelView;
        }
        return _labelView;
    }
    
    #pragma mark - switchChange
    - (void)switchChange:(UISwitch *)switchView {
        
    }
    
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
    //只需要设置一次的东西最好放到这个方法中执行,因为这个方法只会在创建cell的时候执行一次,而不会每次给模型赋值的时候都会执行 self.detailTextLabel.font
    = [UIFont systemFontOfSize:14]; self.backgroundColor = [UIColor clearColor]; self.backgroundView = [[UIImageView alloc] init]; self.selectedBackgroundView = [[UIImageView alloc] init]; } return self; } + (instancetype)cellWithTableView:(UITableView *)tableView { static NSString *ID = @"cell"; BasicCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (!cell) { //这里一定要用self cell = [[self alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID]; } return cell; } - (void)setItem:(SettingItem *)item { _item = item; //设置数据 [self setUpData]; //设置模型 [self setUpRightView]; } - (void)setUpData { self.textLabel.text = _item.title; self.detailTextLabel.text = _item.subTitle; self.imageView.image = _item.image; } - (void)setUpRightView { if ([_item isKindOfClass:[ArrowItem class]]) { //箭头 self.accessoryView = self.arrowView; } else if ([_item isKindOfClass:[BadgeItem class]]) { //badgeView self.accessoryView = self.badgeView; } else if ([_item isKindOfClass:[SwitchItem class]]) { //开关 self.accessoryView = self.switchView; } else if ([_item isKindOfClass:[LabelItem class]]) { //Label LabelItem *labelItem = (LabelItem *)_item; UILabel *label = self.labelView; label.text = labelItem.text; } else if ([_item isKindOfClass:[CheakItem class]]) { //打勾 CheakItem *cheakItem = (CheakItem *)_item; if (cheakItem.isCheak) { self.accessoryView = self.cheakView; } else { self.accessoryView = nil; } } else { [_labelView removeFromSuperview]; _labelView = nil; self.accessoryView = nil; } } - (void)setIndexPath:(NSIndexPath *)indexPath rowCount:(NSInteger)rowCount { UIImageView *bgView = (UIImageView *)self.backgroundView; UIImageView *selBgView = (UIImageView *)self.selectedBackgroundView; if (rowCount == 1) { // 只有一行 bgView.image = [UIImage resizableWithImageName:@"common_card_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_background_highlighted"]; }else if(indexPath.row == 0){ // 顶部cell bgView.image = [UIImage resizableWithImageName:@"common_card_top_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_top_background_highlighted"]; }else if (indexPath.row == rowCount - 1){ // 底部 bgView.image = [UIImage resizableWithImageName:@"common_card_bottom_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_bottom_background_highlighted"]; }else{ // 中间 bgView.image = [UIImage resizableWithImageName:@"common_card_middle_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_middle_background_highlighted"]; } } #pragma mark - 这里写才能居中对齐 - (void)layoutSubviews { [super layoutSubviews]; _labelView.frame = self.bounds; }

    到此,所有的都已经抽出来了。你可能想问了那要么是子类和父类长的很像但是却不一样怎么办?那么就能用到OC中继承的这个性质了,子类只要重写一下父类的方法就可以了。

    随便写几个控制器,继承于BasicSettingViewController

    我的界面

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        [self setUpNav];
        [self setUpGroup0];
        [self setUpGroup1];
        [self setUpGroup2];
        [self setUpGroup3];
    }
    
    - (void)setUpNav {
        UIBarButtonItem *setting = [[UIBarButtonItem alloc] initWithTitle:@"设置" style:UIBarButtonItemStylePlain target:self action:@selector(setting)];
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSForegroundColorAttributeName] = [UIColor blackColor];
        [setting setTitleTextAttributes:dict forState:UIControlStateNormal];
        self.navigationItem.rightBarButtonItem = setting;
    }
    
    #pragma mark - 设置
    
    - (void)setting {
        SettingViewController *setVc = [[SettingViewController alloc] init];
        [self.navigationController pushViewController:setVc animated:YES];
    }
    
    - (void)setUpGroup0
    {
        // 新的好友
        ArrowItem *friend = [ArrowItem itemWithTitle:@"新的好友" image:[UIImage imageNamed:@"new_friend"]];
        
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[friend];
        [self.groups addObject:group];
    }
    - (void)setUpGroup1
    {
        // 我的相册
        ArrowItem *album = [ArrowItem itemWithTitle:@"我的相册" image:[UIImage imageNamed:@"album"]];
        album.subTitle = @"(12)";
        
        // 我的收藏
        ArrowItem *collect = [ArrowItem itemWithTitle:@"我的收藏" image:[UIImage imageNamed:@"collect"]];
        collect.subTitle = @"(0)";
        
        //
        ArrowItem *like = [ArrowItem itemWithTitle:@"" image:[UIImage imageNamed:@"like"]];
        like.subTitle = @"(0)";
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[album,collect,like];
        [self.groups addObject:group];
    }
    - (void)setUpGroup2{
        // 微博支付
        ArrowItem *pay = [ArrowItem itemWithTitle:@"微博支付" image:[UIImage imageNamed:@"pay"]];
        // 个性化
        ArrowItem *vip = [ArrowItem itemWithTitle:@"个性化" image:[UIImage imageNamed:@"vip"]];
        vip.subTitle = @"微博来源、皮肤、封面图";
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[pay,vip];
        [self.groups addObject:group];
    }
    - (void)setUpGroup3
    {
        // 我的二维码
        ArrowItem *card = [ArrowItem itemWithTitle:@"我的二维码" image:[UIImage imageNamed:@"card"]];
        // 草稿箱
        ArrowItem *draft = [ArrowItem itemWithTitle:@"草稿箱" image:[UIImage imageNamed:@"draft"]];
        
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[card,draft];
        [self.groups addObject:group];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        ProfileCell *cell = [ProfileCell cellWithTableView:tableView];
        GroupItem *group = self.groups[indexPath.section];
        SettingItem *item = group.items[indexPath.row];
        cell.item = item;
        [cell setIndexPath:indexPath rowCount:group.items.count];
        return cell;
    }

    因为cell和父类不太一样,所以cell要继承于BasicCell重写一下

    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            self.detailTextLabel.font = [UIFont systemFontOfSize:12];
        }
        return self;
    }
    //一定要在这个方法中重写,不然可能会没用,这个是在加载完成即将显示的时候调用,加载的frame是100%正确的
    - (void)layoutSubviews {
        [super layoutSubviews];
        CGRect frame = self.detailTextLabel.frame;
        frame.origin.x = CGRectGetMaxX(self.textLabel.frame) + 5;
        self.detailTextLabel.frame = frame;
    }

    设置界面

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        // 添加第0组
        [self setUpGroup0];
        // 添加第1组
        [self setUpGroup1];
        // 添加第2组
        [self setUpGroup2];
        // 添加第3组
        [self setUpGroup3];
    }
    
    - (void)setUpGroup0
    {
        // 账号管理
        ArrowItem *account = [ArrowItem itemWithTitle:@"账号管理"];
    //    account.badgeValue = @"8";
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[account];
        [self.groups addObject:group];
    }
    - (void)setUpGroup1
    {
        // 提醒和通知
        ArrowItem *notice = [ArrowItem itemWithTitle:@"我的相册" ];
        // 通用设置
        ArrowItem *setting = [ArrowItem itemWithTitle:@"通用设置" ];
        setting.destVc = [CommonViewController class];
        // 隐私与安全
        ArrowItem *secure = [ArrowItem itemWithTitle:@"隐私与安全" ];
        
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[notice,setting,secure];
        [self.groups addObject:group];
    }
    - (void)setUpGroup2{
        // 意见反馈
        ArrowItem *suggest = [ArrowItem itemWithTitle:@"意见反馈" ];
        // 关于微博
        ArrowItem *about = [ArrowItem itemWithTitle:@"关于微博"];
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[suggest,about];
        [self.groups addObject:group];
    }
    - (void)setUpGroup3
    {
        // 账号管理
        LabelItem *layout = [[LabelItem alloc] init];
        layout.text = @"退出当前账号";
        
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[layout];
        [self.groups addObject:group];
    }

    通用设置界面

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        // 添加第0组
        [self setUpGroup0];
        // 添加第1组
        [self setUpGroup1];
        // 添加第2组
        [self setUpGroup2];
        // 添加第3组
        [self setUpGroup3];
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refresh:) name:@"FontSizeChangeNote" object:nil];
    }
    
    - (void)refresh:(NSNotification *)notification {
        _fontSize.subTitle = notification.userInfo[FontSizeKey];
        [self.tableView reloadData];
    }
    
    - (void)setUpGroup0
    {
        // 阅读模式
        SettingItem *read = [SettingItem itemWithTitle:@"阅读模式"];
        read.subTitle = @"有图模式";
        
        // 字体大小
        SettingItem *fontSize = [SettingItem itemWithTitle:@"字体大小"];
        _fontSize = fontSize;
        NSString *fontSizeStr =  [[NSUserDefaults standardUserDefaults] objectForKey:FontSizeKey];
        if (fontSizeStr == nil) {
            fontSizeStr = @"";
        }
        fontSize.subTitle = fontSizeStr;
        fontSize.destVc = [FontViewController class];
        
        // 显示备注
        SwitchItem *remark = [SwitchItem itemWithTitle:@"显示备注"];
        
        
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[read,fontSize,remark];
        [self.groups addObject:group];
    }
    - (void)setUpGroup1
    {
        // 图片质量
        ArrowItem *quality = [ArrowItem itemWithTitle:@"图片质量" ];
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[quality];
        [self.groups addObject:group];
    }
    - (void)setUpGroup2{
        // 声音
        SwitchItem *sound = [SwitchItem itemWithTitle:@"声音" ];
        
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[sound];
        [self.groups addObject:group];
    }
    - (void)setUpGroup3
    {
        // 多语言环境
        SettingItem *language = [SettingItem itemWithTitle:@"多语言环境"];
        language.subTitle = @"跟随系统";
        GroupItem *group = [[GroupItem alloc] init];
        group.items = @[language];
        [self.groups addObject:group];
    }

    字体大小界面

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        [self setUpGroup0];
    }
    
    - (void)setUpGroup0
    {
        
    #pragma mark - 这种方法能消除block中的循环警告
        //
        __weak typeof(self) weakSelf = self;
         CheakItem * __weak big = [CheakItem itemWithTitle:@""];
        big.option = ^{
            [weakSelf selItem:big];
        };
        
        //
        CheakItem * __weak middle = [CheakItem itemWithTitle:@""];
        
        middle.option = ^{
            [weakSelf selItem:middle];
        };
        _selCheakItem = middle;
        //
        CheakItem * __weak small = [CheakItem itemWithTitle:@""];
        small.option = ^{
            [weakSelf selItem:small];
        };
        GroupItem *group = [[GroupItem alloc] init];
        group.headTitle = @"上传图片质量";
        group.items = @[big,middle,small];
        [self.groups addObject:group];
        
        // 默认选中item
        [self setUpSelItem:middle];
        
    }
    
    - (void)setUpSelItem:(CheakItem *)item
    {
        NSString *fontSizeStr =  [[NSUserDefaults standardUserDefaults] objectForKey:FontSizeKey];
        if (fontSizeStr == nil) {
            [self selItem:item];
            return;
        }
        
        for (GroupItem *group in self.groups) {
            for (CheakItem *item in group.items) {
                if ( [item.title isEqualToString:fontSizeStr]) {
                    [self selItem:item];
                }
                
            }
            
        }
    }
    
    - (void)selItem:(CheakItem *)item
    {
        _selCheakItem.isCheak = NO;
        item.isCheak = YES;
        _selCheakItem = item;
        [self.tableView reloadData];
        
        
        // 存储
        [[NSUserDefaults standardUserDefaults] setObject:item.title forKey:FontSizeKey];
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        // 发出通知
        [[NSNotificationCenter defaultCenter] postNotificationName:@"FontSizeChangeNote" object:nil userInfo:@{FontSizeKey:item.title}];
        
    }

     具体也可以下载的我的上传的DEMO看一下,http://i.cnblogs.com/Files.aspx

  • 相关阅读:
    day15 web框架和Django基础
    activiti5.22 获得mybatis sessionFactory
    activiti 视图
    activiti 任意退
    spring cloud &&spring boot
    JPA 一对多关联
    webstorm 快捷键
    web storm 破解
    Excel通用导出
    activiti 小计
  • 原文地址:https://www.cnblogs.com/wuhongxing/p/5031685.html
Copyright © 2011-2022 走看看