view的封装
- 如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部子控件的创建屏蔽起来,不让外界关心
- 外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应的数据
- 封装控件的基本步骤
- 在initWithFrame:方法中添加子控件,提供便利构造方法
- 在layoutSubviews方法中设置子控件的frame(
一定要调用super的layoutSubviews
切记,这个坑好大)
- 增加模型属性,在模型属性set方法中设置数据到子控件上
自定义控件
- 一个控件有2种创建方式
- 通过`代码创建`
- 初始化时一定会调用`initWithFrame:方法`
- 通过`xib\storyboard创建`
- 初始化时不会调用initWithFrame:方法,只会调用`initWithCoder:方法`
- 初始化完毕后会调用`awakeFromNib方法`
- 有时候希望在控件初始化时做一些初始化操作,
- 比如添加子控件、设置基本属性
- 这时需要根据控件的创建方式,来选择在initWithFrame:、initWithCoder:、awakeFromNib的哪个方法中操作
- 目的:封装控件内部的细节,不让外界关心
- 步骤
- 新建一个继承`UIView`的类
- 在`initWithFrame:`方法中添加子控件
- 在`layoutSubviews`方法中设置子控件的frame
- 一定要调用`[super layoutSubviews]`;
- 提供一个模型属性,重写模型属性的set方法
- 在set方法中取出模型属性,给对应的子控件赋值
// 1.纯代码自定义控件
+ (instancetype)<#model#>ViewWithProduct:(<#modelClass#> *)<#model#>{
<#modelClass#> *view = [[self alloc] init];
view.<#model#> = <#model#>;
return view;
}
/*************** 初始化子控件内容 ***************/
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
// 初始化当前视图/添加子控件到当前视图上,不设置frame
}
return self;
}
/*************** 布局子控件frame(每次当前view的frame一改变就会调用) ***************/
- (void)layoutSubviews{
[super layoutSubviews];
// 计算子控件的frame
}
/*************** 设置子控件数据 ***************/
- (void)setProduct:(<#modelClass#> *)<#model#>{
// 设置子控件展示的数据
}
// 2.xib自定义控件
+ (instancetype)<#model#>ViewWithProduct:(<#modelClass#> *)<#model#>{
<#modelClass#> *view = [[[NSBundle mainBundle] loadNibNamed:@"<#modelClass#>" owner:nil options:nil] lastObject];
// 通过传入的模型,给xib中的控件赋值
return view;
}
- 新建一个xib文件(xib的文件名最好跟控件类名一样)
- 添加子控件、设置子控件属性
- 修改最外面那个控件的class为控件类名
- 将子控件进行连线
- 提供模型属性,重写模型的set方法
- 在set方法中给子控件设置数据
创建自定义视图(3种创建自定义View的方法,都是对外提供接口)
// 1.对外提供模型对象接口
VVLProductView *subView = [VVLProductView productViewWithProduct:product];
// 2.对外提供数据接口
VVLProductView *subView = [VVLProductView productView];
[subView setTitle:product.title icon:product.icon];
// 3.对外提供控件接口
VVLProductView *subView = [VVLProductView productView];
subView.iconImageView.image = [UIImage imageNamed:product.icon];
subView.titleLabel.text = product.title;