Yoona
背景
最近产品部门提了一点需求,修改了一下“选择收货时间”页面,我也因此回顾了一下前年(16年)写的代码,不得不说,太臭了。
详情
如图:
这里面有个温馨提示view:
展示数据来自后台,这里只是一条数据,其实有可能是多条数据,如:
多条数据
16年的做法
那个时候我对MVC的理解还不到位,这种模块view我都是一口气写到控制器里的。
或许你觉得这个view并不复杂,但是写个上百行代码还是没问题的。
现在的做法
将这个view看作一个模块,然后抽离出来。代码文件如下:
总共分成了三个类:
1. CQPickTimeAlertModel
@interface CQPickTimeAlertModel : NSObject /** 标题 */ @property (nonatomic, copy) NSString *title; /** 内容 */ @property (nonatomic, copy) NSString *desc; @end
2. CQPickTimeAlertItem
对应一个model,它的表现形式如下:
item
.h文件:
@interface CQPickTimeAlertItem : UIView @property (nonatomic, strong) CQPickTimeAlertModel *model; @end
.m文件:
@interface CQPickTimeAlertItem () @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *descLabel; @end @implementation CQPickTimeAlertItem - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self setUpUI]; } return self; } - (void)setUpUI { self.titleLabel = [[UILabel alloc] init]; [self addSubview:self.titleLabel]; self.titleLabel.font = [UIFont systemFontOfSize:10]; self.titleLabel.textColor = [UIColor redColor]; self.titleLabel.textAlignment = NSTextAlignmentCenter; self.titleLabel.layer.cornerRadius = 3; self.titleLabel.layer.borderWidth = 1; self.titleLabel.layer.borderColor = [UIColor redColor].CGColor; self.descLabel = [[UILabel alloc] init]; [self addSubview:self.descLabel]; self.descLabel.font = [UIFont systemFontOfSize:12]; self.descLabel.textColor = [UIColor orangeColor]; self.descLabel.numberOfLines = 0; [self bringSubviewToFront:self.titleLabel]; } - (void)setModel:(CQPickTimeAlertModel *)model { _model = model; self.titleLabel.text = _model.title; self.descLabel.text = _model.desc; [self layoutIfNeeded]; } - (void)layoutSubviews { [super layoutSubviews]; [self.titleLabel sizeToFit]; self.titleLabel.frame = CGRectMake(0, 0, self.titleLabel.frame.size.width + 6, self.titleLabel.frame.size.height + 2); // 设置富文本:首行缩进 NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc]init]; style.firstLineHeadIndent = self.titleLabel.frame.size.width + 4; NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:self.descLabel.text]; [attrString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, self.titleLabel.text.length)]; self.descLabel.attributedText = attrString; self.descLabel.frame = CGRectMake(0, 0, self.frame.size.width, 30); [self.descLabel sizeToFit]; self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, CGRectGetMaxY(self.descLabel.frame)); } @end
3. CQPickTimeAlertView
也就是这整个的模块view:
.h文件:
@interface CQPickTimeAlertView : UIView @property (nonatomic, strong) NSArray *itemsArray; @end
.m文件:
@implementation CQPickTimeAlertView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self setUpUI]; } return self; } - (void)setUpUI { UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, 100, 30)]; [self addSubview:titleLabel]; titleLabel.text = @"温馨提示"; titleLabel.font = [UIFont systemFontOfSize:14]; titleLabel.textColor = [UIColor greenColor]; } - (void)setItemsArray:(NSArray *)itemsArray { _itemsArray = itemsArray; UIView *lastView = nil; for (int i = 0; i < _itemsArray.count; i ++) { CQPickTimeAlertItem *itemView = [[CQPickTimeAlertItem alloc] init]; [self addSubview:itemView]; if (!lastView) { itemView.frame = CGRectMake(5, 40, self.frame.size.width-10, 0); } else { itemView.frame = CGRectMake(5, CGRectGetMaxY(lastView.frame) + 5, self.frame.size.width-10, 0); } itemView.model = _itemsArray[i]; lastView = itemView; } // 调整自身高度 self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, CGRectGetMaxY(lastView.frame)+10); // 虚线边框 CAShapeLayer *imaginaryLine = [CAShapeLayer layer]; imaginaryLine.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); imaginaryLine.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:0].CGPath; imaginaryLine.lineWidth = 1. / [[UIScreen mainScreen] scale]; imaginaryLine.lineDashPattern = @[@2, @2]; imaginaryLine.fillColor = [UIColor clearColor].CGColor; imaginaryLine.strokeColor = [UIColor grayColor].CGColor; [self.layer addSublayer:imaginaryLine]; } @end
注:以上是我demo里的代码,没有用任何三方或category,命名也比较随意,大家就别吐槽了。主要看思路。
相比16年的代码有何进步?
极大的减少了C层的代码,更加简洁及优雅。
现在创建这个模块只需几行代码:
CQPickTimeAlertView *aview = [[CQPickTimeAlertView alloc] initWithFrame:CGRectMake(50, 100, self.view.frame.size.width - 100, 20)]; [self.view addSubview:aview]; aview.itemsArray = modelsArray;
分层更清晰了修改自然也就更容易了。
有用的知识点
1.首行缩进:
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc]init]; style.firstLineHeadIndent = self.titleLabel.frame.size.width + 4;
这个很关键,要不然处理下面这两个label的时候你可能会走弯路。
2.虚线边框
用CAShapeLayer:
CAShapeLayer *imaginaryLine = [CAShapeLayer layer]; imaginaryLine.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); imaginaryLine.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:0].CGPath; imaginaryLine.lineWidth = 1. / [[UIScreen mainScreen] scale]; imaginaryLine.lineDashPattern = @[@2, @2]; imaginaryLine.fillColor = [UIColor clearColor].CGColor; imaginaryLine.strokeColor = [UIColor grayColor].CGColor; [self.layer addSublayer:imaginaryLine];
Demo
https://github.com/CaiWanFeng/BeautifulView
demo效果
总结
看待view要像看待模块一样;
对待装备要像对待情人一样。
死肥宅.gif
作者:无夜之星辰
链接:https://www.jianshu.com/p/400450be1e37