界面:代码 vs Xib
代码:提供xxxView.h 和 xxxView.m两个文件
PAChartView-codexib:提供xxxView.h 和 xxxView.m和xxxView.xib三个文件
PAChartView-xibxib:需要拖动IBOutlet引用界面元素
xib:要用加载函数将界面资源加载进来,然后使用
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
UIView *view = nib[0];
[self addSubview:view];
- 一般自定义UIView都是公共控件,并且还会用到CALayer,所以还是用纯代码写界面比较好。
初始化函数
只需要重写initWithFrame:就可以了。因为当外部调用init的方法的时候,其内部也会默默地调用initWithFrame:方法
一般的格式:
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.imageView = [[UIImageView alloc]init];
[self addSubview:self.imageView];
self.label = [[UILabel alloc]init];
[self addSubview:self.label];
}
return self;
}
初始化函数,主要是子视图的生成函数,这里不需要有布局信息。
可以根据情况,提供便利的初始化函数,这种函数需要写到h文件中,比如:
- (instancetype)initWithTitle:(NSString *)title andImage:(UIImage *)image {
self = [self init];
if (self) {
self.label.text = title;
self.imageView.image = image;
}
return self;
}
布局
在layoutSubViews方法里面布局
要先调用父类的layoutSubviews方法,不然在iOS7中可能会崩溃
如果要更新布局,调用函数
[self setNeedsLayout];
- (void)layoutSubviews {
// 确定子控件的frame(这里得到的self的frame/bounds才是准确的)
CGFloat width = self.bounds.size.width;
CGFloat height = self.bounds.size.height;
self.imageView.frame = CGRectMake(0, 0, width, width);
self.label.frame = CGRectMake(0, width, width, height - width);
// 一定要调用super的方法,并且放在后面比较好,不然iOS7可能会崩溃
[super layoutSubviews];
}
layoutSubViews中可以直接使用frame,需要用到的时候可以用。
如果是AutoLayout,建议使用第三方库Masonry,布局内容写在专门的布局函数中
// tell UIKit that you are using AutoLayout
+ (BOOL)requiresConstraintBasedLayout {
return YES;
}
// this is Apple's recommended place for adding/updating constraints
- (void)updateConstraints {
// --- remake/update constraints here
[self.button remakeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(@(self.buttonSize.width));
make.height.equalTo(@(self.buttonSize.height));
}];
//according to apple super should be called at end of method
[super updateConstraints];
}
对外接口:属性 vs 方法
使用默认的getter和setter方法,不要自定义
如果只是普通的设置和读取,不会做额外的事情,那么用属性方便一点
如果要做额外的事情,用方法,不要重写setter方法
如果会引起布局调整,用方法,不要重写setter方法,在方法内部调用
[self setNeedsLayout];