本章知识点:xib与storyboard的区别,xib的基本使用,xib的加载原理,渐变动画,调整UIButton内部子控件的位置,调整UIButton内边距,UIButton图片拉伸,KVC,KVO
xib与storyboard的区别
- 共同点:
1 都用来描述软件界面
2 都用Interface Builder工具来编辑
3 本质都是转换成代码去创建控件 - 不同点:
1 Xib是轻量级的,用来描述局部的UI界面
2 Storyboard是重量级的,用来描述整个软件的多个界面,并且能展示多个界面之间的跳转关系
xib的基本使用
- xib的加载
//方式一
NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"xibname" owner:nil options:nil];
UIView *view = [[[NSBundle mainBundle] loadNibNamed:@"xibname" owner:nil options:nil] firstObject];
//方式二
UINib *nib = [UINib nibWithNibName:@"xibname" bundle:nil];
NSArray *views = [nib instantiateWithOwner:nil options:nil];
UIView *view = [[nib instantiateWithOwner:nil options:nil] firstObject];
[self.view addSubview:view];
- xib的使用
注意事项:
1 如果一个view从xib中加载,就不能用init和initWithFrame:方法创建
2 如果一个xib经常被使用,应该提供快速构造类方法
3 如果一个view从xib中加载,想用代码添加一些子控件,得在initWithCoder:和 awakeFromNib 创建
4 如果一个view从xib中加载,会调用initWithCoder: 和awakeFromNib,不会调用init和initWithFrame:方法
//关联XYProView类
//XYProView.h
#import
@interface XYProView: UIView
// 提供set方法
- (void)setIcon: (NSString *)icon;
- (void)setName: (NSString *)name;
// 提供快速创建方法
+ (instancetype)proView;
@end
//XYProView.m
#import "XYProView.h"
@interface XYProView ()
//在xib中创建(连线)
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
//注释代码为创建一个label子控件(用代码创建)
//@property (nonatomic, weak) UILabel *label;
//毛玻璃
@property (nonatomic, weak) UIToolbar *toolBar;
@end
@implementation XYProView
/*
如果View从xib中加载,就不会调用init和initWithFrame:方法
View从xib中加载时,会调用initWithCoder:方法
注意: 如果子控件是从xib中创建,是处于未唤醒状态
*/
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder]) {
//创建子控件
/*
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor grayColor];
label.text = @“text”;
[self addSubview:label];
self.label = label;
*/
}
return self;
}
//布局子控件
- (void)layoutSubviews{
[super layoutSubviews];
//self.label.frame = self.bounds;
self.toolBar.frame = self.iconView.bounds;
}
//从xib中唤醒,添加xib中创建的子控件的子控件
- (void)awakeFromNib{
//往imageView上加毛玻璃
UIToolbar *toolBar = [[UIToolbar alloc] init];
[self.iconView addSubview:toolBar];
self.toolBar = toolBar;
}
//快速构造方法
+ (instancetype)proView{
return [[[NSBundle mainBundle] loadNibNamed:@"XYproView" owner:nil options:nil] firstObject];
}
//设置数据
- (void)setIcon:(NSString *)icon{
self.iconView.image = [UIImage imageNamed:icon];
}
- (void)setName:(NSString *)name{
self.titleLabel.text = name;
}
@end
使用xib
XYProView *proView = [XYProView shopView];
proView.frame = CGRectMake(100, 100, 80, 100);
//给子控件设置属性
[proView setName:@“name”];
[proView setIcon:@“icon”];
[self.view addSubview:proView];
xib的加载原理
- xib的加载原理(伪代码)
- (UIView *)loadFormNib{
XYproView *proView = [[XYProView alloc] initWithCoder:nil];
proView.frame = CGRectMake(0, 0, 80, 100);
UIImageView *iconView = [[UIImageView alloc] initWithCoder:nil];
iconView.backgroundColor = [UIColor greenColor];
iconView.frame = CGRectMake(0, 0, 80, 80);
iconView.tag = 100;
[proView addSubview:iconView];
self.iconView = iconView;
UILabel *label = [[UILabel alloc] initWithCoder:nil];
label.backgroundColor = [UIColor orangeColor];
label.tag = 200;
[proView addSubview:label];
self.titleLabel = label;
return proView;
}
渐变动画
- 平移
方式一:
//点击按钮开始动画
- (IBAction)translate {
//开始动画
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
//动画代码
CGRect frame = self.animationView.frame;
frame.origin.y -= 50;
self.animationView.frame = frame;
//提交动画
[UIView commitAnimations];
}
方式二(三种方法):
- (IBAction)translate {
//1 动画代码
[UIView animateWithDuration:2.0 animations:^{
CGRect frame = self.animationView.frame;
frame.origin.y -= 50;
self.animationView.frame = frame;
}];
//2 动画代码
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.animationView.frame;
frame.origin.y -= 50;
self.animationView.frame = frame;
} completion:^(BOOL finished) {
//动画完成后做什么事情
self.animationView.backgroundColor = [UIColor blackColor];
}];
//3 动画代码
[UIView animateWithDuration:1.0 delay:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
/*
UIViewAnimationOptionCurveEaseInOut 动画开始/结束比较缓慢,中间相对较快
UIViewAnimationOptionCurveEaseIn 动画开始延时
UIViewAnimationOptionCurveEaseOut 动画完成后延时
UIViewAnimationOptionCurveLinear 匀速
*/
CGRect frame = self.animationView.frame;
frame.origin.y += 50;
self.animationView.frame = frame;
} completion:^(BOOL finished) {
//动画完成后做什么事情
self.animationView.backgroundColor = [UIColor greenColor];
}];
}
- 缩放
- (IBAction)scale {
[UIView animateWithDuration:1.0 delay:1.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect frame = self.animationView.frame;
frame.size = CGSizeMake(10, 15);
self.animationView.frame = frame;
} completion:^(BOOL finished) {
//动画完成
}];
}
- 透明度动画(嵌套)
- (IBAction)alpha {
[UIView animateWithDuration:1.0 delay:0.5 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.animationView.alpha -= 0.9;
} completion:^(BOOL finished) {
[UIView animateWithDuration:2.0 animations:^{
self.animationView.alpha += 0.9;
}];
}];
}
调整UIButton内部子控件的位置
- 方式一:重写两个方法
//重写两个方法: 不要调用super,就是要重写掉
//contentRect: 内容的尺寸,内容包括(imageView和label)
- (CGRect)titleRectForContentRect:(CGRect)contentRect{
return CGRectMake(0, 0, 100, 70);
}
- (CGRect)imageRectForContentRect:(CGRect)contentRect{
return CGRectMake(100, 0, 70, 70);
}
- 方式二:重写layoutSubviews方法
- (void)layoutSubviews{
[super layoutSubviews];
// 设置子控件的位置
self.titleLabel.frame = CGRectMake(0, 0, 100, 70);
self.imageView.frame = CGRectMake(100, 0, 70, 70);
}
- 调整子控件
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
// 文本居中
self.titleLabel.textAlignment = NSTextAlignmentCenter;
// 改变图片的内容模式
self.imageView.contentMode = UIViewContentModeCenter;
}
return self;
}
调整UIButton内边距
- 设置整体内边距
self.button.contentEdgeInsets = UIEdgeInsetsMake(-20, 0, 0, 0);
- 设置图片内边距
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
- 设置标题内边距
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -10);
UIButton图片拉伸
- 方式一:
//默认为平铺
UIImage *resizableImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5 -1, imageWidth * 0.5 - 1)];
//UIImageResizingModeTile, 平铺
//UIImageResizingModeStretch, 拉伸(伸缩)
UIImage *resizableImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5 -1, imageWidth * 0.5 - 1) resizingMode:UIImageResizingModeTile];
- 方式二:
//stretchableImageWithLeftCapWidth 图片宽度 - 左边受保护区域 - 1
//topCapHeight 图片高度 - 上方受保护区域 - 1
UIImage *resizableImage = [image stretchableImageWithLeftCapWidth:imageWidth * 0.5 topCapHeight:imageHeight * 0.5];
- 一般我们将拉伸方法写在UIImage的分类中
#import "UIImage+XMGExtention.h"
@implementation UIImage (XMGExtention)
+ (instancetype)resizableImageWithLocalImageName:(NSString *)localImageName{
// 创建图片对象
UIImage *image = [UIImage imageNamed:localImageName];
// 获取图片的尺寸
CGFloat imageWidth = image.size.width;
CGFloat imageHeiht = image.size.height;
// 返回一张拉伸且受保护的图片
return [image stretchableImageWithLeftCapWidth:imageWidth * 0.5 topCapHeight:imageHeiht * 0.5 ];
}
@end
KVC
- KVC:Key Value Coding,即键值编码
- 使用KVC进行赋值
[person setValue:@"王五" forKey:@"name"];
//forKeyPath可以进行自动类型转换
[person setValue:@"19" forKeyPath:@"money"];
[person.dog setValue:@"阿黄" forKey:@"name"];
[person setValue:@"旺财" forKeyPath:@"dog.name"];
//KVC可以修改类的私有成员变量(_age可以改为age)
[person setValue:@"88" forKeyPath:@"_age"] ;
forKey和forKeyPath的区别:
1 forKeyPath 包含了所有 forKey 的功能
2 forKeyPath 进行内部的点语法,层层访问内部的属性
3 注意: key值一定要在属性中找到
- 利用KVC取值
XMGPerson *person = [[XMGPerson alloc] init];
person.name = @“name”;
person.money = 12332;
NSLog(@"%@ --- %.2f", [person valueForKeyPath:@"name"], [[person valueForKey:@"money"] floatValue]);
- 字典转模型
开发中不建议使用setValuesForKeysWithDictionary:
1 字典中的key必须在模型的属性中找到,否则会报错
2 如果模型中带有模型,setValuesForKeysWithDictionary无法使用
应用场景: 简单的字典转模型
- (instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
//self.name = dict[@"name"];
//self.money = [dict[@"money"] floatValue];
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
- 模型转字典
NSDictionary *dict = [person dictionaryWithValuesForKeys:@[@"name", @"money"]];
- 取出数组中所有模型的某个属性值
XYPerson *person1 = [[XYPerson alloc] init];
person1.name = @“name1”;
person1.money = 22.99;
XYPerson *person2 = [[XYPerson alloc] init];
person2.name = @“name2”;
person2.money = 122.99;
NSArray *allPersons = @[person1, person2];
NSArray *allPersonName = [allPersons valueForKeyPath:@"name"];
KVO
- KVO: Key Value Observing 键值监听,当某个对象的属性值发生改变的时候,用KVO监听
XYPerson *person = [[XYPerson alloc] init];
person.name = @“aaa”;
/*
作用:给对象绑定一个监听器(观察者)
- Observer 观察者
- KeyPath 要监听的属性
- options 选项(方法方法中拿到属性值)
*/
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
person.name = @“bbb”;
// 移除监听
[person removeObserver:self forKeyPath:@"name"];
/*
当监听的属性值发生改变
keyPath 要改变的属性
object 要改变的属性所属的对象
change 改变的内容
context 上下文
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
NSLog(@“%@, %@, %@“, keyPath, object, change); //改变的属性,所属对象,改变后的值
}