自定义视图
自定义视图:系统标准UI之外,自己组合而出的新的视图。
iOS提供了很多UI组件,借助它们,我们可以做各种程序。
尽管如此,实际开发中,我们还需自定义视图。积累自己的代码库。 方便开发。自己封装的视图,能像系统UI控件一样,用于别的项目中,能大大降低开发成本,提高开发效率。
自定义视图创建步骤:
1.创建一个继承自UIView类
2.重写新类的初始化方法
3.把想添加的视图 封装到新类中(初始化到新类中)
4.为了方便外部进行赋值或者取值 把添加的视图写成属性(别忘了dealloc释放)
5.测试一下
label-textField视图
假设我们使用LTView类代表label-textfield视图。
我们创建一个LTView类继承于UIView。
我们将LTView作为一个容器,在LTView的初始化方法中创建并添加 label和textField。
此时的LTView就变成了一个具有label和textField的视图了。
创建方法:
1.新建一个LTView
在LTView.h中将label和textField定义成属性,方便外部取出
2.在LTView.m中重写初始化方法
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 动态获取宽度
CGFloat width = frame.size.width;
// 动态获取高度
CGFloat height = frame.size.height;
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, width / 3, height)];
// 添加到自己身上
[self addSubview:self.label];
// 释放
[_label release];
self.textField = [[UITextField alloc] initWithFrame:
CGRectMake(width / 3 + 20, 0, width *2/3 - 20, height)];
self.textField.borderStyle = UITextBorderStyleRoundedRect;
[self addSubview:self.textField];
[_textField release];
}
return self;
}
把Label和Textfield封装到LTView中,在一定程度上简化了我们的代 码。
往往我们需要对LTView中的Label或者Textfield进⾏行一定的控制,比如:设置Label的text,获取Textfield的text,给Textfield指定 delegate,设置textColor等。
为了方便外界操作Label和Textfield,因此我们要为外界提供一些方法。
3.新建一个LoginView
- 在LoginView.h中,声明需要使用的控件属性
在LoginView.m中,重写初始化方法
- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.userNameLTView = [[LTView alloc] initWithFrame:CGRectMake((kScreenWidth - 300) /2, 100, 300, 50)]; self.userNameLTView.label.text = @"账 号:"; self.userNameLTView.textField.placeholder = @"请输入账号"; [self addSubview:self.userNameLTView]; [self.userNameLTView release]; self.passwordLTView = [[LTView alloc] initWithFrame:CGRectMake(self.userNameLTView.frame.origin.x, self.userNameLTView.frame.origin.y + self.userNameLTView.frame.size.height + kRowHeight, self.userNameLTView.frame.size.width, self.userNameLTView.frame.size.height)]; self.passwordLTView.label.text = @"密 码:"; self.passwordLTView.textField.placeholder = @"请输入密码"; [self addSubview:self.passwordLTView]; [self.passwordLTView release]; // 利用循环创建button NSArray *arr = @[@"登录", @"注册", @"找回密码"]; for (int i = 0; i < 3; i++) { UIButton *button = [UIButton buttonWithType:(UIButtonTypeCustom)]; button.frame = CGRectMake(30 + (100 * i), 300, 90, 50); [button setTitle:arr[i] forState:(UIControlStateNormal)]; [button setTitleColor:[UIColor orangeColor] forState:(UIControlStateNormal)]; // 加标签 方便取出button 与属性的button 相对应 button.tag = 100 + i; [self addSubview:button]; } // 属性与循环的button 进行关联 self.loginButton = (UIButton *)[self viewWithTag:100]; self.registButton = (UIButton *)[self viewWithTag:101]; self.findPasswordButton = (UIButton *)[self viewWithTag:102]; } return self; }
在Application中导入LoginView头文件
创建LoginViewLoginView *loginView = [[LoginView alloc] initWithFrame:[UIScreen mainScreen].bounds];
// 添加button标题(或者直接在LoginView.m中利用数组进行赋值)
[loginView.loginButton setTitle:@”登录” forState:(UIControlStateNormal)];
[loginView.registButton setTitle:@”注册” forState:(UIControlStateNormal)];
[loginView.findPasswordButton setTitle:@”找回密码” forState:(UIControlStateNormal)];
[self.window addSubview:loginView];
[loginView release];
自定义LTView使用了一种设计模式:复合设计模式。
复合设计模式:A类中,使用B类(或者更多类)作为自己的成员(实例变量)。
iOS中复合是特别常见的设计模式。iOS新控件往往都是用已有控件组合而成的。
注意:动态获取尺寸可使用宏定义(提高代码质量)
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
// 行间距
#define kRowHeight 30
视图控制器
概述:
UIViewController:视图控制器。
控制视图显示,响应事件。
分担AppDelegate的工作。
实现模块独立,提高复用性。
功能:
控制视图大小变换、布局视图、响应事件。
检测以及处理内存警告。
检测以及处理屏幕旋转。
检测视图的切换。
MVC概述:
UIViewController是MVC设计模式的核心。
MVC是一个框架级的设计模式。
M是Model,主要用于建立数据模型(即数据的结构)
V是View,我们能看到的所有控件都是view,view主要的功能是展示数据。
C是控制器,主要是控制M和V的通信。
视图控制器的使用
步骤:
定义UIViewController的子类
创建视图控制器对象,作为window的根视图控制器
在viewDidLoad中使⽤用默认创建好的视图对象view
1.新建一个RootViewController继承于UIViewController 将其设置为根视图控制器 重写loadView方法
// 每一个视图控制器 都自带一个 view
// 并且这个view 跟屏幕一样大小
// 这个方法是加载视图的
// 并且 加载的 自己自带的那个view
- (void)loadView
{
// 调用父类的方法 去加载自身的视图
[super loadView];
// 用上午的loginView 替换 控制器自带的view
LoginView *loginView = [[LoginView alloc] initWithFrame:[UIScreen mainScreen].bounds];
loginView.tag = 1000;
// 帮系统给self.view 赋值
self.view = loginView;
// 释放
[loginView release];
}
2.使用创建好的LoginView 指定为controller的view(见上述代码)
视图控制器指定自定义View
为什么使用自定义视图类:
UIViewController自带一个空的view,与需求不符合。
视图控制器只负责控制视图显示,响应事件。
3.在viewDidLoad方法中进行设置:添加action、设置delegate和代理方法的实现等等。
// 视图已经加载完成
- (void)viewDidLoad {
[super viewDidLoad];
// 更改一下自身view的颜色
// self.view.backgroundColor = [UIColor orangeColor];
// 控制器中写逻辑部分
// 给button添加一个点击方法
LoginView *loginView = (LoginView *)self.view;
// button添加方法
[loginView.loginButton addTarget:self action:@selector(buttonClick:) forControlEvents:(UIControlEventTouchUpInside)];
// 给textField设置代理
loginView.userNameLTView.textField.delegate = self;
loginView.passwordLTView.textField.delegate = self;
}
// button添加方法
- (void)buttonClick:(UIButton *)button
{
NSLog(@"lalala.....");
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
检测屏幕旋转
屏幕横屏时 改变原来的布局(横屏)
屏幕竖屏时 变回原来的布局 (竖屏)
1.允许屏幕旋转
2.指定屏幕旋转的方向
3.找到旋转触发的方法
4.判断屏幕方法 更改布局
5.测试一下
将工程General下的Deployment Info中的Device Orientation都打勾
根视图的.m文件中 添加方法
// 1.允许屏幕旋转- (BOOL)shouldAutorotate
{
return YES;
}
// 2.指定屏幕旋转的方向
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
// 3.找到旋转触发的方法
- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator: (id)coordinator
{
NSLog(@”%@”,NSStringFromCGSize(size));
}
- (BOOL)shouldAutorotate
在自定义视图类中重新布局子视图
// frame发生变化的时候会触发layoutSubviews方法 - (void)layoutSubviews { // 因为不知道父类这个方法做了什么 // 所以需要再重写的 先调用一下父类的方法 // 然后再写自己的 [super layoutSubviews]; // frame发生变化 相当于 横屏了 // 这时 咱们需要重新布局视图 // 判断横屏还是竖屏 // 1、把应用程序取出来 // 2、判断一下当前应用程序 屏幕的朝向 // 取出应用程序 单例方法的命名规范share什么的 UIApplication *app = [UIApplication sharedApplication]; // 判断方向 if (app.statusBarOrientation == UIInterfaceOrientationPortrait || app.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) { NSLog(@"竖着"); self.passwordLTView.frame = CGRectMake(self.userNameLTView.frame.origin.x, self.userNameLTView.frame.origin.y + self.userNameLTView.frame.size.height + kRowHeight, self.userNameLTView.frame.size.width, self.userNameLTView.frame.size.height); } else { NSLog(@"横着"); self.passwordLTView.frame = CGRectMake(self.userNameLTView.frame.origin.x + self.userNameLTView.frame.size.width + 10, self.userNameLTView.frame.origin.y, self.userNameLTView.frame.size.width, self.userNameLTView.frame.size.height); for (int i = 0; i < 3; i++) { UIButton *button = [UIButton buttonWithType:(UIButtonTypeCustom)]; button.frame = CGRectMake(60 + (100 * i), 100, 90, 50); [button setTitleColor:[UIColor orangeColor] forState:(UIControlStateNormal)]; // 加标签 方便取出button 与属性的button 相对应 button.tag = 100 + i; [self addSubview:button]; } }
处理内存警告
根视图中的内存警告方法:
// 接到内存警告触发的方法
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
NSLog(@”hahahaha”);
// 内存警告了 要干点什么?
// 释放已经显示过的视图 并且 不是当前显示的视图
// 如果这个视图 正在被显示 那么 这个视图的window属性不是空的
if ([self isViewLoaded] == YES && self.view.window == nil) {
// 把当前视图 释放
self.view = nil;
}
}
模拟内存警告:模拟器 -> 硬件 -> 模拟内存警告。查看方法执⾏行
容器视图控制器
常用方法:
self.view显示:viewWillAppear: 和 viewDidAppear:
self.view消失:viewWillDisappear: 和 viewDidDisappear:
当self.view添加到父视图上时,执行appear方法: 当self.view从父视 图上移除时,执行disappear方法。
顺序:
1.定义FirstViewController、SecondViewController类,first作为window 的根视图控制器。
// 创建控制器
RootViewController *rootVC = [[RootViewController alloc] init];
// 创建根视图控制器
self.window.rootViewController = rootVC;
// 释放
[rootVC release];
2.将SecondViewController的view添加到FirstViewController的view上。
3. 将SecondViewController的view移除。
rootViewController中:
- (void)viewDidLoad {
[super viewDidLoad];
// 如果你不想替换self.view 一般都写在viewDidLoad方法中
self.secondVC = [[SecondViewController alloc] init];
// 把secondVC添加成子控制器 让rootVC去管理
[self addChildViewController:self.secondVC];
// 把secondVC.view 添加到rootVC.view 上
[self.view addSubview:self.secondVC.view];
// 释放
[self.secondVC release];
self.view.backgroundColor = [UIColor yellowColor];
// 添加一个按钮 移除视图 移除子控制器
UIButton *button = [UIButton buttonWithType:(UIButtonTypeCustom)];
button.frame = CGRectMake(100, 100, 100, 50);
button.backgroundColor = [UIColor blackColor];
// button.layer.cornerRadius = 15;
// 添加到rootVC.view上
[button addTarget:self action:@selector(buttonClick:) forControlEvents:(UIControlEventTouchUpInside)];
[self.view addSubview:button];
}
- (void)buttonClick:(UIButton *)button
{
// 删除视图
[self.secondVC.view removeFromSuperview];
// 移除子控制器
[self.secondVC removeFromParentViewController];
}
4. 查看SecondViewController中4个方法的执行顺序。
// 视图生命周期
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"视图将要出现");
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"视图已经出现");
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
NSLog(@"视图将要消失");
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSLog(@"视图已经消失");
}