一.纯代码自定义View
1. 首先在initWithFrame:方法中将需要的子控件加入view中
注意,这里只是加入到view中,并没有设置各个子控件的尺寸。
为什么要在initWithFrame:方法而不是在init方法?
因为使用纯代码的方式自定义View,在以后使用的时候可能使用init方法创建,也有可能使用initWithFrame:方法创建,但是无论哪种方式,最后都会调用到initWithFrame:方法。在这个方法中创建子控件,可以保证无论哪种方式都可以成功创建。为什么要在initWithFrame:方法里面只是将子控件加到view而不设置子控件尺寸?
前面已经说过,两种方式最后都会调用到initWithFrame:方法。如果使用init方法创建,那么这个view的frame有可能是不确定的,
CYLView *view = [[CYLView alloc] init];
view.frame = CGRectMake(0,0, 100,100);
如果是这种情况,那么在init方法中,frame是不确定的,此时如果在initWithFrame:方法中设置子控件的尺寸,那么各个子控件的尺寸都会是0,因为这个view的frame还没有设置。(可以看到是在发送完init消息才设置的)。
所以我们应该保证view的frame设置完才会设置它的子控件的尺寸。
所以在layoutSubviews设置内部控件的frame。
2. 在layoutSubviews设置内部控件的frame
view第一次将要显示的时候会调用这个方法,之后当view的尺寸(不是位置)改变时,会调用这个方法。
简单的自定义一个ShopView里面有个Shop模型,代码如下:
Shop模型.h文件
#import <Foundation/Foundation.h>
@interface Shop : NSObject
@property (nonatomic, copy) NSString *icon; //商品的图标
@property (nonatomic, copy) NSString *name; //商品的名称
// 提供构造方法
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)shopWithDict:(NSDictionary *)dict;
@end
Shop模型.m文件
#import "Shop.h"
@implementation Shop
//对象方法
- (instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
self.icon = dict[@"icon"];
self.name = dict[@"name"];
}
return self;
}
//类方法
+ (instancetype)shopWithDict:(NSDictionary *)dict{
return [[self alloc] initWithDict:dict];
}
@end
ShopView.h文件
#import <UIKit/UIKit.h>
@class Shop;
@interface ShopView : UIView
// 商品模型
@property (nonatomic, strong) Shop *shop;
// 构造方法
- (instancetype)initWithShop: (Shop *)shop;
+ (instancetype)shopViewWithShop: (Shop *)shop;
@end
ShopView.m
#import "ShopView.h"
#import "Shop.h"
@interface ShopView ()
@property (nonatomic, weak) UIImageView *iconView; //图片控件
@property (nonatomic, weak) UILabel *titleLabel; //标题控件
@end
@implementation ShopView
//初始化子控件(不要设置frame)
- (instancetype)init{
if (self = [super init]) {
[self setUp];
}
return self;
}
//注意: 创建对象用[[xxx alloc]init]方法和[[xxx alloc]initWithFrame]:方法都会调用initWithFrame:
- (instancetype)initWithFrame:(CGRect)frame{
if (self =[super initWithFrame:frame]) {
[self setUp];
}
return self;
}
//对象方法
- (instancetype)initWithShop:(XMGShop *)shop{
if (self = [super init]) {
// 注意:先创建后赋值
[self setUp];
self.shop = shop;
}
return self;
}
//类方法
+ (instancetype)shopViewWithShop:(XMGShop *)shop{
return [[self alloc] initWithShop:shop];
}
// 初始化
- (void)setUp{
// 1.创建商品的UIImageView对象
UIImageView *iconView = [[UIImageView alloc] init];
iconView.backgroundColor = [UIColor blueColor];
[self addSubview:iconView];
_iconView = iconView;
// 2.创建商品标题对象
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.backgroundColor = [UIColor yellowColor];
titleLabel.textAlignment = NSTextAlignmentCenter; // 居中
[self addSubview:titleLabel];
_titleLabel = titleLabel;
}
// 布局子控件(可以拿到frame)
- (void)layoutSubviews{
// 一定要调用super
[super layoutSubviews];
// 1.获取当前控件的尺寸
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
// 2.设置子控件的frame
self.iconView.frame = CGRectMake(0, 0, width, width);
self.titleLabel.frame = CGRectMake(0, width, width, height - width);
}
// 重写set方法:只要外边传数据就会调用
- (void)setShop:(Shop *)shop{
_shop = shop;
// 设置数据
self.iconView.image = [UIImage imageNamed:shop.icon];
self.titleLabel.text = shop.name;
}
@end
二. 使用xib自定义View
- 创建xib,在xib中拖入需要添加的控件并设置好尺寸。并且要将这个xib的Class设置为我们的自定义类,通过IBOutlet的方式,将xib中的控件与自定义类进行关联。
- 使用xib的方式可以省去initWithFrame:和layoutSubviews中添加子控件和设置子控件尺寸的步骤,以及省略在viewController里面设置view的frame的过程,因为添加子控件和设置子控件的尺寸以及整个view的尺寸在xib中就已经完成(注意整个view的位置还没有设置,需要在viewController里面设置)。
- 我们只需对外提供数据接口,重写setter方法就可以显示数据
- 建议在awakeFromNib方法中进行初始化的额外操作,因为awakeFromNib是在初始化完成后调用,所以在这个方法里面访问属性(IBOutlet)就可以保证不为nil。
- 使用xib自定义view后一定会调下面两个方法:
//因为xib文件就是本地的一个文件所以要进行解档操作,那肯定调这个方法啦
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self) {
}
return self;
}
//从xib初始化完会调用,所以建议在awakeFromNib方法中进行初始化的额外操作
- (void)awakeFromNib{
[super awakeFromNib];
}
代码如下:
ShopView.h
#import <UIKit/UIKit.h>
@class Shop;
@interface ShopView : UIView
@property (nonatomic, strong) Shop *shop; //数据模型
+ (instancetype)shopView; // 快速构造方法
@end
ShopView.m
#import "ShopView.h"
#import "Shop.h"
@interface ShopView ()
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *titlelabel;
@end
@implementation ShopView
+ (instancetype)shopView{
return [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] firstObject];
}
- (void)setShop:(Shop *)shop{
_shop = shop;
// 设置数据
self.iconView.image = [UIImage imageNamed:shop.icon];
self.titleLabel.text = shop.name;
}
//- (void)awakeFromNib
@end