IOSday04 UIButton使用
UIButton
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
千万不要这样写:
btn.titleLabel.text = @"我是按钮";
- 一般情况下给按钮设置内容都是setXXX
- [btn setTitle:@"我是按钮"
forState:UIControlStateNormal];
- [btn setTitle:@"哥是高亮"
forState:UIControlStateHighlighted];
2.设置标题颜色
btn.backgroundColor = [UIColor redColor];
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
```
#### 设置图标
```objc
[btn setImage:[UIImage imageNamed:@"common_icon_check"] forState:UIControlStateNormal];
```
####设置背景图片
```objc
[btn setBackgroundImage:[UIImage imageNamed:@"common_button_big_blue_highlighted"] forState:UIControlStateDisabled];
```
####监听按钮的点击
Target:让谁监听按钮
action:监听到之后需要执行的方法
Events:事件的类型
- 规律:
- 只要是继承于UIControl的控件, 都可以通过addTarget来添加监听
```objc
[btn addTarget:self action:@selector(customBtnClick) forControlEvents:UIControlEventTouchUpInside];
```
---
######UISwitch sw = nil;
```objc
[sw addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>]
```
###### UISegmentedControl *sc = nil;
```objc
[sc addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>]
```
###### UITextField *tf = nil;
```objc
[tf addTarget:<#(nullable id)#> action:<#(nonnull SEL)#> forControlEvents:<#(UIControlEvents)#>]
```
####设置字体
```objc
btn.titleLabel.font = [UIFont systemFontOfSize:30];
```
####设置frame
```objc
btn.frame = CGRectMake(100, 100, 100, 100); ```
``` [self.view addSubview:btn]; ```
---
###UIButton图片拉伸
---
- iOS5以前
- LeftCapWidth: 左边多少不能拉伸
- 右边多少不能拉伸 = 控件的宽度 - 左边多少不能拉伸 - 1
- right = width - leftCapWidth - 1
- 1 = width - leftCapWidth - right
- topCapHeight: 顶部多少不能拉伸
- 底部有多少不能拉伸 = 控件的高度 - 顶部多少不能拉伸 - 1
- bottom = height - topCapWidth - 1
- 1 = height - topCapWidth - bottom
```UIImage *newImage = [image stretchableImageWithLeftCapWidth:5 topCapHeight:5]; ```
----
- iOS5开始
- UIEdgeInsets是告诉系统哪些地方需要受保护, 也就是不可以拉伸
- resizableImageWithCapInsets默认拉伸方式是平铺
```UIEdgeInsets insets = UIEdgeInsetsMake(image.size.height * 0.5, image.size.width * 0.5, image.size.height * 0.5, image.size.width * 0.5); ```
- UIImage *newImage = [image resizableImageWithCapInsets:insets];
---
- iOS6开始
- resizingMode指定拉伸模式
- 平铺
- 拉伸
```UIEdgeInsets insets = UIEdgeInsetsMake(5, 5, 5, 5); ```
```objc
UIImage *newImage = [image resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch];
```
#currentTitle和btn.titlelabel.text 区别
UIButton *btn = [UIButtonbuttonWithType:UIButtonTypeCustom];
1、[btn setTitle:@"测试一下" forState:UIControlStateNormal];
输出:CurrentTitleLabel:测试一下,currentTitle:测试一下。模拟器button上显示:测试一下
2、btn.titlelabel.text = @"测试一下";
输出:CurrentTitleLabel:测试一下,currentTitle:(null)。模拟器button上无显示
3、[btn setTitle:@"测试一下" forState:UIControlStateNormal];
btn.titlelabel.text = @"测试二下";
输出:CurrentTitleLabel:测试二下,currentTitle:测试一下。模拟器button上显示:测试二下
4、btn.titlelabel.text = @"测试二下";
[btn setTitle:@"测试一下" forState:UIControlStateNormal];
输出:CurrentTitleLabel:测试一下,currentTitle:测试一下。模拟器button上显示:测试一下
currentTitle 和titlelabel 不一样。按钮上显示的是CurrnetTitle,而不是titlelabel。
---
#KVC
Person *p = [Person new];```
p.name = @"lmj";
p.money = 998;
p.dog = [Dog new];
p.dog.name = @"wangcai";
p.dog.price = 110;
获取单个值
NSString *name = [p valueForKey:@"name"];
double money = [[p valueForKey:@"money"] doubleValue];
获取多层值
NSString *dogName = [p valueForKey:@"dog.name"];
NSString *dogName = [p valueForKeyPath:@"dog.name"];
模型转字典
NSDictionary *dict = [p dictionaryWithValuesForKeys:@[@"name", @"money"]];
获取数组中对象的值
Person *p1 = [Person new];
p1.name = @"zs";
p1.money = 111;
Person *p2 = [Person new];
p2.name = @"ls";
p2.money = 222;
Person *p3 = [Person new];
p3.name = @"ww";
p3.money = 666;
NSArray *arr = @[p1, p2, p3];
- 如果数组中的元素都是同一种类型的数据, 可以使用KVC获取数组中所有对象的某个属性的值
NSArray *res = [arr valueForKeyPath:@"name"];
运算符
id res1 = [arr valueForKeyPath:@"@avg.money"];
单个值
- KVC == KEY VALUE CODING
- Value : 值, 只能传对象
- forKey: 需要给谁(哪个属性)赋值
- setValue:forKey:方法, 只能给对象的直接属性赋值
- [p setValue:@"lmj" forKey:@"name"];
- @(998.0) == [NSNumber numberWithDouble:(double)]
- [p setValue:@(668.0) forKey:@"money"];
多层赋值
p.dog = [Dog new];
p.dog.name == [[p dog] setName:]
p.dog.name = @"wangwang";
p.dog.price = 110.0;
-
setValue:forKeyPath: 可以给对象的间接属性赋值. 多层赋值
- 建议: 以后在开发中都使用
setValue:forKeyPath:
[p setValue:@"xiaoqiang" forKeyPath:@"dog.name"];
- 建议: 以后在开发中都使用
[p setValue:@(110) forKeyPath:@"dog.price"];
给私有成员变量赋值
[p setValue:@" ydz " forKey:@"_name"];
[p setValue:@(30) forKey:@"_age"];
-
用sel可以调用私有方法
SEL sel = @selector(say);
[p performSelector:sel];
[p say];
字典转模型
NSDictionary *dict = @{
@"name":@"xxx",
@"money": @(998.1),
@"score":@(100)
@"dog":@{
@"name":@"wangcai",
@"price":@(110)
}
};
p.name = dict[@"name"];
p.money = [dict[@"money"] doubleValue];
-
注意点:
- 1.如果想使用KVC进行字典转模型, 那么字典中的key必须和模型中的属性一模一样(个数 + 名称)``` this class is not key value coding-compliant for the key score.'```
- 2.如果使用KVC进行字典转模型, 只能对当前调用KVC方法的对象进行转换, 不能对它的属性的对象进行转换
setValuesForKeysWithDictionary:方法内部的实现原理
-
1.会拿到字典中的key, 然后根据这个key取出字典中的值, 然后再根据这个key赋值给对象
[p setValue:@"xxx" forKey:@"name"];
[p setValuesForKeysWithDictionary:dict];
KVO
KVO == Key Value Observing
-
作用: 可以监听某个对象属性的改变
Person *p = [Person new]; p.name = @"ydz"; p.age = 30;
-
第一个参数: 告诉系统哪个对象监听
-
第二个参数: 监听当前对象的哪个属性
-
第三个参数: 监听到属性改变之后, 传递什么值
-
第四个参数: 需要传递的参数 (这个参数不是传递给属性的)
-
给p这个对象添加一个监听 , 监听p对象的age属性的改变, 只要age属性改变就通知self
[p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
p.age = 50;
NSLog(@"-------------------");
p.age = 100;
-
-
注意: 如果使用KVO监听某个对象的属性, 当对象释放之前一定要移除监听
reason: 'An instance 0x7f9483516610 of class Person was deallocated while key value observers were still registered with it.
-
注意: KVO只能监听通过set方法修改的值
KVO的原理:
只要给一个对象注册一个监听, 那么在运行时, 系统就会自动给该对象生成一个子类对象,
并且重写自动生成的子类对象的被监听属性的set方法, 然后在set方法中通知监听者
NSKVONotifying_Person
p->_age = 998;
-
从p对象上移除self对它的age属性的监听
[p removeObserver:self forKeyPath:@"age"];
-
只要监听到属性的改变就会调用
-
keyPath: 被监听的属性名称
-
object : 被监听的对象
-
context: 注册监听的时候传入的值
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context: (nullable void *)context { NSLog(@"keyPath = %@, object = %@ , change = %@, context = %@", keyPath, object, change, context); }
-
提示框(HUD)
1.创建一个AlertController
- (void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
{
UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:@"标题" message:@"正文" preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * __nonnull action) {
NSLog(@"点击了确定");
}];
UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * __nonnull action) {
NSLog(@"点击了取消");
}];
[alertVc addAction:action1];
[alertVc addAction:action2];
注意: 如果UIAlertController的样式是ActionSheet, 就不能添加输入框
reason: 'Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert'
[alertVc addTextFieldWithConfigurationHandler:^(UITextField * __nonnull textField) {
}];
2.显示
[self presentViewController:alertVc animated:YES completion:nil];
}
====
1.创建alert控制器
- (void)useAlertControllerAlert
{
UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:@"哥是标题" message:@"姐是正文..." preferredStyle:UIAlertControllerStyleAlert];
// 2.添加一个按钮
// Title : 按钮上显示的文字
// style: 按钮的样式
// handler: 点击按钮之后的回调
UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * __nonnull action) {
NSLog(@"点击了确定按钮");
}];
UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * __nonnull action) {
NSLog(@"点击了取消按钮");
}];
[alertVc addAction:action1];
[alertVc addAction:action2];
// 3.添加一个输入框
[alertVc addTextFieldWithConfigurationHandler:^(UITextField * __nonnull textField) {
textField.text = @"用户名";
NSLog(@"textField");
}];
[alertVc addTextFieldWithConfigurationHandler:^(UITextField * __nonnull textField) {
textField.secureTextEntry = YES;
NSLog(@"textField");
}];
[alertVc addTextFieldWithConfigurationHandler:^(UITextField * __nonnull textField) {
NSLog(@"textField");
}];
// 4.presentViewController弹出一个控制器
[self presentViewController:alertVc animated:YES completion:nil];
}
===
1.创建UIActionSheet
- (void)useActionSheet
{
// 2.UIActionSheet
//
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"哥是标题" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:@"其它", @"Other", nil];
// 2.显示UIActionSheet
[sheet showInView:self.view];
}
UIActionSheetDelegate
-
只要UIActionSheet上的按钮被点击就会调用
-
actionSheet:谁触发事件就会把谁传递进来
-
clickedButtonAtIndex:当前被点击按钮的索引
{ NSLog(@"%ld", buttonIndex); }``` ===
1.UIAlerView
- 如果看到iOS提供的方法中有... 就代表是一个可变参数
- 可以传一个或者多个
代理的应用场景:
A对象向监听B对象的变化, A对象就可以成为B对象的代理
B对象发生一些变化想通知A对象, 那么A对象就可以成为B对象的代理
监听
规律:
1.以后但凡看到iOS中需要传递对象成为某个对象的代理, 那么直接写上某个对象的类名 + Delegate即可
2.一般情况下, 代理中的方法都是以控件的名称去掉前缀开头
例如: 要成为UIAlertView的代理 , 写上 UIAlertViewDelegate
- (void)useAlert
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"哥是标题" message:@"姐是正文..." delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
}
UIAlertViewDelegate
- 只要UIAlertView上的按钮被点击, 就会调用
- alertView:谁触发事件就会把谁传递进来
- ButtonAtIndex: 当前被点击按钮的索引
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonInde