掌握
UIView的常见属性和方法
九宫格计算方法
字典转模型
Xib的使用
自定义view(view的封装)
简单的MVC
搭建九宫格的步骤
明确每一块用的是什么view
明确每个view之间的父子关系
先尝试逐个逐个添加格子,最后考虑使用for循环
加载app数据,根据数据长度创建对应个数的格子
添加格子内部的子控件
给格子内部的子控件装配数据
用模型取代字典的好处
使用字典的坏处
一般情况下,设置数据和取出数据都使用“字符串类型的key”,编写这些key时,编辑器没有智能提示,需要手敲
dict[@"name"] = @"Jack";
NSString *name = dict[@"name"];
手敲字符串key,key容易写错
Key如果写错了,编译器不会有任何警告和报错,造成设错数据或者取错数据
使用模型的好处
所谓模型,其实就是数据模型,专门用来存放数据的对象,用它来表示数据会更加专业
模型设置数据和取出数据都是通过它的属性,属性名如果写错了,编译器会马上报错,因此,保证了数据的正确性
使用模型访问属性时,编译器会提供一系列的提示,提高编码效率
app.name = @"Jack";
NSString *name = app.name;
字典转模型
字典转模型的过程最好封装在模型内部
模型应该提供一个可以传入字典参数的构造方法
-(instancetype)initWithDict:(NSDictionary *)dict;
- (instancetype)xxxWithDict:(NSDictionary
*)dict;
Instancetype
instancetype在类型表示上,跟id一样,可以表示任何对象类型
instancetype只能用在返回值类型上,不能像id一样用在参数类型上
instancetype比id多一个好处:编译器会检测instancetype的真实类型
注意点
一个控件有2种创建方式
通过代码创建
初始化时一定会调用initWithFrame:方法
通过xib\storyboard创建
初始化时不会调用initWithFrame:方法,只会调用initWithCoder:方法
初始化完毕后会调用awakeFromNib方法
有时候希望在控件初始化时做一些初始化操作,比如添加子控件、设置基本属性
这时需要根据控件的创建方式,来选择在initWithFrame:(给控件设置位置)、initWithCoder:、awakeFromNib(初始化控件)的哪个方法中操作
Xib和storyboard对比
共同点:
都用来描述软件界面
都用Interface
Builder工具来编辑
不同点
Xib是轻量级的,用来描述局部的UI界面
Storyboard是重量级的,用来描述整个软件的多个界面,并且能展示多个界面之间的跳转关系
view的封装
如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部子控件的创建屏蔽起来,不让外界关心
外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应的数据
UILabel的常见设置
@property(nonatomic,copy) NSString *text; // 显示的文字
@property(nonatomic,retain) UIFont *font; // 字体
@property(nonatomic,retain) UIColor *textColor; // 文字颜色
@property(nonatomic) NSTextAlignment textAlignment; // 对齐模式(比如左对齐、居中对齐、右对齐)
UIFont
UIFont代表字体,常见创建方法有以下几个:
(UIFont*)systemFontOfSize:(CGFloat)fontSize; // 系统默认字体
(UIFont*)boldSystemFontOfSize:(CGFloat)fontSize; // 粗体
(UIFont *)italicSystemFontOfSize:(CGFloat)fontSize; // 斜体
UIButton的常见设置
-(void)setTitle:(NSString *)title forState:(UIControlState)state; // 设置按钮的文字
-(void)setTitleColor:(UIColor *)color forState:(UIControlState)state; // 设置按钮的文字颜色
-(void)setImage:(UIImage *)image forState:(UIControlState)state; // 设置按钮内部的小图片
-(void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state; // 设置按钮的背景图片
// 设置按钮的文字字体(需要拿到按钮内部的label来设置)
btn.titleLabel.font= [UIFont systemFontOfSize:13];
-(NSString *)titleForState:(UIControlState)state; // 获得按钮的文字
-(UIColor *)titleColorForState:(UIControlState)state; // 获得按钮的文字颜色
-(UIImage *)imageForState:(UIControlState)state; // 获得按钮内部的小图片
-(UIImage *)backgroundImageForState:(UIControlState)state; //获得按钮的背景图片
获取plist的全路径方法:
当NSString*path = [[NSBundle mainBundle]
pathForrResource:@"shop" ofType:@"plist"];
当解析Plist文件
接下来通过代码来解析Plist文件中的数据
获得Plist文件的全路径NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle pathForResource:@"shops" ofType:@"plist"];
用代码的方式去自定义控件的注意点:
Plist的使用注意:
- Plist的文件名不能叫做"info"/"Info"之类(会出现不可预计的错误)
2.添加plist等文件资源的时候,一定要勾选下面的选项(黏贴等选项)
1.layoutSubvies 布局内部的自控件(子控件frame发生变化的时候才会调用)
一定要调用[superlayouSubvies]记住了是一定会调用这个方法
只要当前的view的frame发生改变就会调用这个方法
view一初始化完也会调用这个方法,尝试着给自己的子控件赋值
步骤1. 初始化自定义的view (只是调用init方法)
2. 设置frame
3. 在init方法中给子控件设置frame, 但是self的frame是没有值的
4. 只要是自定义的控件,那么必须得在layoutSubvies中赋值
2.initWithFrame的使用(介意以后自定义控件的时候去实现initWithFrame的方法)尽量别使用init方法
在initWithFrame方法中初始化子控件(不管外界是使用init 还是initWithFrame 都会调用initWithFrame 方法)
property的使用策略
strong 一般是使用在OC对象上(也可以使用在UI控件上(会有问题的))
NSSArray NSDictionary 模型...
weak 一般是使用在UI控件上 也可以使用在OC对象(也是有问题的)
UITextFeild UIButton.....
copy 一般使用在NSString Block
assign 一般是使用基本数据类型上, 枚举 结构体
思路
1. 创建一个类 自定义的控件什么样的控件(就直接继承什么样的类)
自定义一个按钮 那么继承自UIButton
2. 在initWithFrame 中初始化子控件做一次性的操作
3. layoutSubvies 中设置子控件的frame
4. 暴露一个模型属性给外界传值(传值的方法有很多 想到什么就使用什么方式)
重写init方法的使用和注意
一定要调用super的init方法:因为初始化父类中会声明一些成员变量和其他属性
就是调用super的init方法 最后返回的就是一个id也就是self
有时候调用[super init]方法返回的不一定是一个self,但是为了保证它返回的是一个self就要进行一个赋值操作;
注意:调用super初始化完毕 就一定要赋值给self
返回一个self意思是:返回一个已经初始化完毕的一个对象
构造方法的注意点:
先调用父类的构造方法[super init];
再进行子类内部成员变量的初始化
*********************笔记***********************
plist root : 选择的类型是神马(NSArray)样的 返回的就是神马(NSArray)(需要使用神马(NSArray)接收)
步骤1. 获取plist文件的全路径
2. 根据路径加载plist中所有数据-
模型:(就是把字典里面的数据通过创建类来转化成模型,便于自己使用)
- 使用一个临时数组装从plist 中加载的数组(装的都是字典)
- 遍历临时数组, 取出每一个字典
- 将字典赋值给模型
- 将模型存放到数组(可变数组)中
plist 用来存储一些经常变动的数据,或者多处需要使用的
模型 将字典转换成可读性比较高的代码
而且不容易出错-
类前缀
ios
ns(next step)stringShopModel
ShopModel包 java
com.biz.xj.ShopModel
-
instancetype && id
- id 任意对象 可以使用任何对象接收 没有任何警告和提示
- instancetype 会检测你的真实返回类型 , 那么如果类型不匹配直接警告
-
layoutSubvies 布局内部的自控件
只要当前的view的frame发生改变就会调用这个方法(只要一改变子控件的位置,它就会自动调用这个方法)
view一初始化完也会调用这个方法,尝试着给自己的子控件赋值步骤1. 初始化自定义的view (只是调用init方法)
2. 设置frame
3. 在init方法中给子控件设置frame, 但是self的frame是没有值的
4. 只要是自定义的控件,那么必须得在layoutSubvies中赋值 注意:(最好使用initWithFrame系统提供的这个方法)(initWithFrame方法中初始化子控件(不管外界是使用init 还是initWithFrame 都会调用initWithFrame方法))
-
property的使用策略
strong 一般是使用在OC对象上 (也可以使用在UI控件上(会有问题的))
NSSArray NSDictionary 模型...
weak 一般是使用在UI控件上 也可以使用在OC对象(也是有问题的)
UITextFeild UIButton.....
copy 一般使用在NSString Block
assign 一般是使用基本数据类型上, 枚举 结构体 -
自定义控件设置数据
- tag 给自己的子控件添加一个tag,在控制器立获取tag对应的子控件赋值
- 使用方法
- 使用属性
- 控件暴露在.h文件
- 使用模型属性
- Block (不做没关系)
- 代理
- 思路
- 创建一个类 自定义的控件什么样的控件(就直接继承什么样的类)
自定义一个按钮 那么继承自UIButton - 在initWithFrame 中初始化子控件 做一次性的操作
- layoutSubvies 中设置子控件的frame
- 暴露一个模型属性给外界传值(传值的方法有很多 想到什么就使用什么方式)
- 创建一个类 自定义的控件什么样的控件(就直接继承什么样的类)
*********************总结***********************
*********************NO4***********************
plist root : 选择的类型是神马(NSArray)样的 返回的就是神马(NSArray)(需要使用神马(NSArray)接收)
步骤1. 获取plist文件的全路径
2. 根据路径加载plist中所有数据-
模型:
- 使用一个临时数组装从plist 中加载的数组(装的都是字典)
- 遍历临时数组, 取出每一个字典
- 将字典赋值给模型
- 将模型存放到数组(可变数组)中
plist 用来存储一些经常变动的数据,或者多处需要使用的
模型 将字典转换成可读性比较高的代码
而且不容易出错-
类前缀
ios
ns(next step)stringShopModel
ShopModel包 java
com.biz.xj.ShopModel
-
instancetype && id
- id 任意对象 可以使用任何对象接收 没有任何警告和提示
- instancetype 会检测你的真实返回类型 , 那么如果类型不匹配直接警告
-
layoutSubvies 布局内部的自控件
只要当前的view的frame发生改变就会调用这个方法
view一初始化完也会调用这个方法,尝试着给自己的子控件赋值步骤1. 初始化自定义的view (只是调用init方法)
2. 设置frame
3. 在init方法中给子控件设置frame, 但是self的frame是没有值的
4. 只要是自定义的控件,那么必须得在layoutSubvies中赋值 在initWithFrame方法中初始化子控件(不管外界是使用init 还是initWithFrame 都会调用initWithFrame 方法)
在layoutSubvies 中给子控件设置frame
-
property的使用策略
strong 一般是使用在OC对象上 (也可以使用在UI控件上(会有问题的))
NSSArray NSDictionary 模型...
weak 一般是使用在UI控件上 也可以使用在OC对象(也是有问题的)
UITextFeild UIButton.....
copy 一般使用在NSString Block
assign 一般是使用基本数据类型上, 枚举 结构体 -
自定义控件设置数据
- tag 给自己的子控件添加一个tag
在控制器立获取tag对应的子控件赋值 - 使用方法
- 使用属性
- 控件暴露在.h文件
- 使用模型属性
- Block (不做没关系)
- 代理
- tag 给自己的子控件添加一个tag
- 思路
- 创建一个类 自定义的控件什么样的控件(就直接继承什么样的类)
自定义一个按钮 那么继承自UIButton - 在initWithFrame 中初始化子控件 做一次性的操作
- layoutSubvies 中设置子控件的frame
- 暴露一个模型属性给外界传值(传值的方法有很多 想到什么就使用什么方式)
- 创建一个类 自定义的控件什么样的控件(就直接继承什么样的类)
*********************总结***********************
*********************NO4***********************
-
总结
plist: 创建方式
加载 mianbundle中查找路径
根据 root 接收一个数组或者字典类型
NSArray(NSDictionary) array(dictionary)WithContentOfFile:懒加载
1. 用到的时候再加载
2. 一般是写在get方法中
3. 只要你去使用,那么肯定是调用get方法layoutSubviews
1. 一般都是设置子控件的frame
2. 只要父控件的frame发生改变就会调用
3. 在initWithFrame之后也会默认调用一次这个方法(尝试着给子控件赋值)封装view
1. 在initWithFrame中初始化子控件,并且做一次性操作
2. 在layoutSubviews 中给子控件frame赋值
3. 提供一个模型属性供外界赋值
4. 在模型属性的set方法中给子控件赋值(参数)封装的好处
1. 任意在任何项目中使用
2. 改变数据不会影响控制器
3. 改变内部的空间也不会影响到控制器 -
MVC
m model 模型 数据层
v view 视图(自定义控件)表示层
c controller 管理层(控制器)- 控制器创建视图(view)
- 控制器创建模型 (控制器要显示什么样的数据应该是控制器决定)
- 控制器负责将模型数据赋值给视图
// ------------------------以上是代码封装-------------------------
xib
创建 new file - > 选择user interface - > view (empty)
加载 使用mainbundle加载
nsbundle mainbundle]loadNibName:(xib名字) nil nil
[UINib nibWithName:xib名字 nil nil]
nib对象 instantiateWithOwner nil nil
mianbundle 如果mainbundle 只有是参数 那么就可以直接传nil-
自定义控件
- 创建一个xib
- 往xib中添加子控件
- 修改xib的类型
- 提供一个类方法
在类方法中直接返回从mainbundle中加载的控件数组,拿到最后一个
xib 一个xib数组中一般情况下只有一个控件
直接返回 - 提供一个模型属性
在set方法中给子控件赋值
- 在通过nib 加载view的话 那么只会调用 initWithCoder awakeFromNib
通过代码的方法我们必须使用initWithFrame那么就会调用 init/ initWithFrame
其实很重要的
只要是生命周期方法 都是很重要- init 初始化子控件,做一些一次性的操作
- initWithFrame 初始化子控件,做一次性操作. 调用了init也会调用这个方法
一般情况使用代码自定义控件那么必须得这里初始化子控件 - initWithCoder 在子控件加载完毕之前可以做的操作,
比如 在子控件加载玩之前,需要再添加一个控件
不能给子控件赋值 因为子控件没有值(空的) - awakeFromNib 子控件加载完毕之后需要做的操作
比如, 给子控件赋值,设置frame
http://www.easyicon.net/iconsearch 图标大全
***************************NO5******************************
***************************NO5******************************
-
hud
江湖人称为: 蒙版/遮盖/hud
UIAlertView
UIAlertView *alert = [UIAlertView alloc]initWithTitle:<#(NSString *)#> message:<#(NSString *)#> delegate:<#(id)#> cancelButtonTitle:<#(NSString *)#> otherButtonTitles:<#(NSString *), ...#>, nil;[alert show];
hidden 隐藏控件 YES 隐藏 NO 不隐藏(是否显示或者不显示)
alpha 0.0完全透明 1.0 没有透明度(别搞反了,0.0是完全透明)
-
渐变动画
帧动画 一帧一帧的播放动画(一张一张图片的切换)
渐变动画 (alpha 0.0 ~ 1.0) hidden (yes NO)
frame x y width height
0
1
2
...
10
20
...
180
190
1). 头尾式
开始动画
[UIView beginAnimations:nil context:nil];
动画时间
[UIView setAnimationDuration:2.0f];
self.hudLabel.alpha = 1.0;
self.hudLabel.text = @"感觉满满的";
提交动画
[UIView commitAnimations];2). block 式 [UIView animateWithDuration:2.0f animations:^{ 需要执行的代码 self.hudLabel.alpha = 1.0; self.hudLabel.text = @"感觉满满的"; 延迟 4 s 调用 self 的 hideHud方法 [self performSelector:@selector(hideHud) withObject:nil afterDelay:4.0]; }]; 3) block 式 "带完成的block" [UIView animateWithDuration:2.0f animations:^{ 需要执行的代码 self.hudLabel.alpha = 1.0; self.hudLabel.text = @"感觉满满的"; } completion:^(BOOL finished) { [UIView animateWithDuration:2.0f animations:^{ 需要执行的代码 self.hudLabel.alpha = 0.0f; }]; }]; 4). block 式 "带完成的block 延迟的时间" [UIView animateWithDuration:1.0f animations:^{ 需要执行的代码 self.hudLabel.alpha = 1.0f; } completion:^(BOOL finished) { 延迟十秒 执行动画的代码 执行时间 是 2.0f [UIView animateWithDuration:1.0f delay:1.0f options:kNilOptions animations:^{ 需要执行的代码 self.hudLabel.alpha = 0.0f; } completion:^(BOOL finished) { }]; }];
-
按钮的内部结构
图片 和 标题 间距
self.titleEdgeInsets; 改变标题在按钮中的位置
self.imageEdgeInsets 改变图片在按钮中的位置
self.contentEdgeInsets 改变按钮中所有内容的位置
设置内间距
图片 和 标题 位置布局
直接影响按钮内部的子控件
缺陷 不知道先调用的是哪个方法(不推荐使用)
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
self.titleH = contentRect.size.height * 0.4;
return CGRectMake(0, 0, contentRect.size.width,self.titleH);
}- (CGRect)imageRectForContentRect:(CGRect)contentRect { return CGRectMake(0, contentRect.size.height * 0.4, contentRect.size.width, contentRect.size.height * 0.6); } 一般情况下 都是使用layoutSubviews 布局子控件 layoutSubviews 准确性🐔高
-
图片的拉伸的三种方式:
http://blog.csdn.net/q199109106q/article/details/8615661"默认是平铺的方式"
UIImage *resizeImg = [image resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];"需要选择拉伸或者平铺的模式"
UIImage *resizeImg = [image resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10) resizingMode:UIImageResizingModeTile];// 系统会根据你传入的左边的宽度 算出右边的宽度
// 1 = width - leftCapWidth - right
// 系统会根据你传入的顶部的高度算出底部的高度
// 1 = height - topCapWidth - bottom
// 拉伸的是1x1 的区域
UIImage *resizeImg = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height *0.5]; -
copy
- 深拷贝 对象拷贝 产生一个新对象
- 浅拷贝 指针拷贝 指向同一个地址
- strong / copy
strong 两个会跟着发生改变
copy 拷贝一个副本,改变副本不会影响源文件, 改变源文件不会影响到副本 - property copy 在set方法中写 _str = [str copy];
- 调用copy的时候, 返回的是一个不可变对象
- 调用mutableCopy 返回一个可变对象
- kvc key value coding
赋值
setValue:forKey 只能给当前对象的属性赋值
setValue: forKeyPath: 可以给当前对象的属性赋值 还能当前对象的属性的属性赋值
setValuesForKeysWithDictionary 传第一个字典给自己的所有属性赋值 必须属性名字和字典中key一致
forUndefinedKey 这个方法当找不到这个某个key就会调用 系统自己调用取值
valueForKey 获取当前对象的属性的值
valueForKeyPath 获取当前对象的属性的属性的....值 也能获取当前对象的属性的值
- kvo key value observer
添加监听者
监听属性值的改变
self监听 p对象的 name这个属性发生改变,
只要这个属性发生改变 系统调用下面的监听方法
[p addObserver:self forKeyPath:@"sex" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"他是傻逼"];移除
只要监听完之后就可以移除
[p removeObserver:self forKeyPath:@"sex"];-
重写监听方法
-
(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"keypath =%@,object = %@,change = %@,context = %@",keyPath,object,change,context);NSString *str = change[@"new"]; if ([str isEqualToString:@"xiaojian"]) { NSLog(@"-=----%@",context); }
}
-
执行动画 2秒以后执行这里的代码
[UIView animateWithDuration:2.0f animations:^{
需要执行动画的代码
self.hud.alpha = 0.5f;
} completion:^(BOOL finished) {
动画执行完毕的时候调用
需要动画结束操作的代码
animateWithDuration : 时间
delay : 延迟
options : 动画的选项
animations : 需要执行的动画代码
completion : 动画完成
延迟 2.0s 后执行 隐藏hud的动画,动画执行时间为1.0s
[UIView animateWithDuration:1.0f delay:2.0f options:kNilOptions animations:^{
self.hud.alpha = 0.0f;
} completion:nil];
当点击self.view的时候就会调用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
打印内部的子控件
NSLog(@"-----%@",self.myBtn.subviews);
}