1.自定义视图的目的
- 通常在开发APP时,系统自带的视图控件不能满足我们的要求,或者需要经常使用模块的视图控件,这里我们可以将该模块封装,封装后的视图就是自定义视图
- 目的:
- 提高代码的复用性
- 屏蔽内部的实现细节
2.如何创建一个自定义视图
这里的每一个红色模块都是一个自定义视图
1.自定义一个类继承于UIView
- UIView中声明模型属性,方便根据传入的值设置控件的数据
#import <UIKit/UIKit.h>
@class ZJShop;
@interface NJShopView : UIView
// 数据模型
@property(nonatomic, strong)ZJShop *shop;
@end
- 2.在initWithFrame方法中添加子控件
- 注意: 如果自定义一个View,不建议在init方法中设置子控件的位置
- 因为如果子控件的位置需要根据父控件的frame来计算, 在init方法中拿不到父控件的frame
- 注意:在调用init和initWithFrame:时,都会调用initWithFrame:方法,而调用initWithFrame:不会调用init方法,所以这里建议在重写init方法时,重写父类的initWithFrame:方法
- 这样我们不论是通过alloc init和alloc initWithFrame:的时候,都能正常进行初始化
- -
#import "ZJShopView.h"
#import "ZJShop.h"
@interface ZJShopView ()
// 定义子控件视图
// 内部控件属性一般定义在匿名分类中
@property (nonatomic, weak) UIImageView *iv;
@property (nonatomic, weak) UILabel *introLabel;
@end
@implementation ZJShopView
-(nonnull instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
// 创建头像控件
UIImageView *imgView = [[UIImageView alloc] init];
[self addSubview:imgView];
self.iv = imgView;
// 创建label控件
UILabel *contentLabel = [[UILabel alloc] init];
contentLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:contentLabel];
self.introLabel = contentLabel;
}
return self;
}
@end
- 3.在layoutSubviews中设置子控件的位置
- layoutSubviews方法是专门用于布局子控件的位置的
- 注意: 重写layoutSubviews方法, 一定要调用[super layoutSubviews]方法,如果不调用, 会出现一些奇葩的错误
- layoutSubviews方法什么时候调用
- 1.只要创建一个控件, 那么就会调用
- 2.只要修改控件的尺寸就会调用(bounds/frame)
- 3.修改位置不会调用
- 4.如果当前修改的尺寸和上一次的尺寸没有变化, 不会调用
/**
* 重写layoutSubviews,设置子控件的位置尺寸
*/
-(void)layoutSubviews{
[super layoutSubviews];
self.iv.frame = CGRectMake(0, 0, kShopViewW, kShopViewW);
self.introLabel.frame = CGRectMake(0, kShopViewW, kShopViewW, kShopViewH - kShopViewW);
}
- 4.提供一个属性保存外界传入的数据(模型对象),重写setter方法设置子控件的数据
/**
* 重写setter方法,设置控件数据
*/
-(void)setShop:(ZJShop *)shop{
_shop = shop;
// 设置子控件的数据
self.iv.image = [UIImage imageNamed:shop.icon];
self.introLabel.text = shop.intro;
}
3.类工厂方法(便利构造器)
- 按照苹果的风格和规范,一般情况一个用于创建对象的对象方法会对应一个类方法
- 可以通过类工厂方法, 快速的根据数据创建一个对象
- 注意点:
- 返回值一定要使用instancetype, 不要使用id
- 在类工厂方法中创建对象, 使用self, 不要使用类名
//快速构造方法
-(instancetype)initWithShop:(ZJShop *)shop;
+(instancetype)shopViewWith:(ZJShop *)shop;
// 实现
-(instancetype)initWithShop:(ZJShop *)shop{
if (self = [super init]) {
self.shop = shop;
}
return self;
}
+(instancetype)shopViewWith:(ZJShop *)shop{
return [[self alloc] initWithShop:shop];
}
4.layoutSubViews方法
作用:
- 布局子控件,用于调整子控件的位置
调用时间:
- 控件第一次被创建
- 控件的尺寸被修改时
注意点:
- 重写layoutSubViews方法时,一定要调用父类的方法[super layoutSubViews];