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];
总结
看待view要像看待模块一样;
对待装备要像对待情人一样。
网友评论