iOS开发 | “我的”页面的纯代码做法

作者: 无夜之星辰 | 来源:发表于2018-01-09 23:57 被阅读1009次
iu

app中常见的“我的”页面

大部分app都有“我的”页面,也就是个人中心,下图是我们公司app的“我的”页面:


这个页面的tableView我把它看做三部分:

  • 表头:


    表头
  • 表尾:

表尾
  • 主内容:


    主内容

今天我们就来聊一聊主内容这一块的做法,为了不那么单调,我稍微改了一下,如下:


方案一:使用静态单元格

对于这种数据不变的tableView,使用静态单元格还是比较方便的,我认识的不少开发者也是采用的这种方法,不清楚的同学可以网上搜下,这里就不讨论了。

方案二:直接在cell上addSubview

首先我们封装好下面这种样式的cell:


@interface CQUserCenterCell : UITableViewCell

@property (nonatomic, strong) CQUserCenterCellModel *model;

/** 隐藏cell右边的箭头 */
- (void)hideIndicator;

@end

model:

@interface CQUserCenterCellModel : NSObject

@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *title;

@end

那几个独立控件:积分label、未读信息label和夜间模式switch,作为controller的属性,直接添加在相应的cell上。代码如下:

/** 积分label */
@property (nonatomic, strong) UILabel *pointsLabel;
/** 未读消息 */
@property (nonatomic, strong) UILabel *unreadLabel;
/** 夜间模式开关 */
@property (nonatomic, strong) UISwitch *nightModeSwitch;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 使用唯一复用id
    NSString *reuseCellID = [NSString stringWithFormat:@"%ld_%ld", indexPath.section, indexPath.row];
    CQUserCenterCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseCellID];
    if (!cell) {
        cell = [[CQUserCenterCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseCellID];
        cell.model = self.modelArray[indexPath.row];
        
        switch (indexPath.row) {
            case 2: // 我的积分
            {
                self.pointsLabel = [[UILabel alloc]initWithFrame:CGRectMake(140, 0, 100, 40)];
                [cell.contentView addSubview:self.pointsLabel];
                self.pointsLabel.textColor = [UIColor redColor];
                self.pointsLabel.font = [UIFont systemFontOfSize:14];
            }
                break;
                
            case 3: // 未读消息
            {
                self.unreadLabel = [[UILabel alloc] initWithFrame:CGRectMake(130, 5, 16, 16)];
                [cell.contentView addSubview:self.unreadLabel];
                self.unreadLabel.backgroundColor = [UIColor redColor];
                self.unreadLabel.textColor = [UIColor whiteColor];
                self.unreadLabel.font = [UIFont systemFontOfSize:12];
                self.unreadLabel.textAlignment = NSTextAlignmentCenter;
                self.unreadLabel.layer.cornerRadius = 8;
                self.unreadLabel.clipsToBounds = YES;
                self.unreadLabel.hidden = YES; // 默认隐藏
            }
                break;
                
            case 4: // 夜间模式
            {
                // 隐藏cell右边的箭头
                [cell hideIndicator];
                
                // 夜间模式开关
                self.nightModeSwitch = [[UISwitch alloc] init];
                [cell.contentView addSubview:self.nightModeSwitch];
                self.nightModeSwitch.center = CGPointMake(self.view.frame.size.width - 50, 20);
                [self.nightModeSwitch addTarget:self action:@selector(changeTheme:) forControlEvents:UIControlEventValueChanged];
            }
                break;
                
            default:
                break;
        }
        
    }
    return cell;
}

我这里使用的唯一cell复用id,避免了因cell复用带来的细节问题,也少写了一些代码。

这种方案的优点是:简单明了,任何段位的开发者来维护你的代码都无压力;缺点是代码都写在了C层,让C有点臃肿。

方案三:扩展

扩展cell:


@interface CQUserCenterCell (Util)

/** 设置积分 */
- (void)setPoints:(NSInteger)points;
/** 设置未读消息数量 */
- (void)setUnreadMessageNum:(NSInteger)unreadMessageNum;
/**
 添加控制夜间模式的switch

 @param handler 开启\关闭夜间模式时回调的block
 */
- (void)addNightModeSwitchWithHandler:(void(^)(BOOL isOn))handler;

@end

controller的代码相对简练了一些:

/** 积分cell */
@property (nonatomic, strong) CQUserCenterCell *pointsCell;
/** 未读消息cell */
@property (nonatomic, strong) CQUserCenterCell *unreadCell;
/** 夜间模式cell */
@property (nonatomic, strong) CQUserCenterCell *nightModeCell;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 使用唯一复用id
    NSString *reuseCellID = [NSString stringWithFormat:@"%ld_%ld", indexPath.section, indexPath.row];
    CQUserCenterCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseCellID];
    if (!cell) {
        cell = [[CQUserCenterCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseCellID];
        cell.model = self.modelArray[indexPath.row];
        
        switch (indexPath.row) {
            case 2: // 我的积分
            {
                self.pointsCell = cell;
            }
                break;
                
            case 3: // 未读消息
            {
                self.unreadCell = cell;
            }
                break;
                
            case 4: // 夜间模式
            {
                [cell addNightModeSwitchWithHandler:^(BOOL isOn) {
                    [self changeTheme:isOn];
                }];
            }
                break;
                
            default:
                break;
        }
        
    }
    return cell;
}
// 加载数据
- (void)loadData {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 设置积分
        [self.pointsCell setPoints:200];
        // 设置未读消息数量
        [self.unreadCell setUnreadMessageNum:3];
    });
}

// 改变主题色
- (void)changeTheme:(BOOL)isNightMode {
    if (isNightMode) {
        self.tableView.backgroundColor = [UIColor grayColor];
    } else {
        self.tableView.backgroundColor = [UIColor whiteColor];
    }
}

我的做法

我用的方案二,因为最简单。
C层臃肿?不存在的,这种简单页面本来就写不到多少代码。

最后

想知道你们是怎么做的。


2018年1月24日更新

最终的做法:使用唯一标识符+懒加载来处理那几个独立控件,放弃使用category,因为在category中添加属性太繁琐。

Demo:
https://github.com/CaiWanFeng/UserCenter

相关文章

网友评论

  • 风谷先生:Demo俩面,点击未读消息的时候label(UILabel *unreadMessageNumLabel;)红色消失,建议在
    - (void)layoutSubviews {
    _unreadMessageNumLabel.backgroundColor = [UIColor redColor];
    }
    label红色背景在点击时就不会消失.
  • 荔枝lizhi_iOS程序猿:挺好的,给我启发:heart_eyes:
  • Mr_Lucifer:你方案2写法 我只有在用系统的UITableViewCell的时候才会用. 你既然自定义cell为什么不在cell中直接写好控件, 然后用数据参数控制cell内控件的显示与否?这样可读性 复用性都会好些.
  • b2f70a645712:没图了呢
  • CepheusSun:感觉有凑文章嫌疑,而且3个方案都一般,方案是对的,但是你写的都没有体现方案的优势和劣势
    无夜之星辰:@CepheusSun 师傅们怀疑的,我统统改
    CepheusSun:@Mikebanana 偶像怀疑的,我统统都要怀疑 @moonCoder
    Mikebanana:门徒师傅居然敢怀疑快师傅 少见少见
  • 北极XinO:就是方法二提出几点个人看法:1.cell可以先注册 ,然后在返回cell的数据源方法中就不用再判断是否有cell了 2.其实不用在返回cell的数据源方法中用字符串方法拼接重用标识符,可以在cell的头文件暴露出一个类方法,用来返回类名称的字符串;3.返回cell的数据源方法中不要做太多的逻辑,就是取cell,给cell赋值model然后返回cell
  • moonCoder:感觉有凑文章嫌疑,而且3个方案都一般,方案是对的,但是你写的都没有体现方案的优势和劣势
  • PGOne爱吃饺子:快师傅,CQUserCenterCell (Util) 这个方法的.m文件是怎么实现的啊,最重要的代码没有贴啊。。
  • 玉思盈蝶:整个一个cell把所有的控件都创建出来,在控制器根据不同的样式进行隐藏和显示不挺好么。
    安静守护你:就是这么做的
    无夜之星辰:不错,给了我一些思路
    CepheusSun:同意
  • 亦歌三折:我只想知道你夜间模式怎么实现的
    无夜之星辰:可以简单参考下:https://www.jianshu.com/p/ffc39669b81e

本文标题:iOS开发 | “我的”页面的纯代码做法

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