iOS学习22之视图控制器
1.自定义视图
1> 概述
定义视图:系统标准UI之外,自己组合而出的新的视图。
定义视图的优点:
iOS提供了很多UI组件,借助它们我们可以实现不同的功能。尽管如此,实际开发中,我们还需要自定义视图。积累自己的代码库,方便开发。自己封装的视图,能像系统UI控件一样,用于别的项目中,能大大降低开发成本,提高开发效率。
高质量代码的特点:可复用,可移植,精炼等。(高内聚,低耦合)
2> 自定义视图步骤(以登录框为例(LTView))
根据需求的不同,自定义视图继承的类也有所不同。一般自定义的视图会继承于UIView。以下是自定义视图的要点:
① 创建一个UIView子类: @interface LTView : UIView
② 在类的初始化方法中添加子视图。
1 // 添加视图 2 - (void)addAllViews 3 { 4 // leftLabel 5 self.leftLabel = [[UILabel alloc] initWithFrame:CGRectMake(kLabelX, kLabelY, 80, 30)]; 6 // 文本对齐 7 self.leftLabel.textAlignment = NSTextAlignmentCenter; 8 // 添加到自定义视图 9 [self addSubview:self.leftLabel]; 10 11 12 // rightTextField 13 self.rightTextField = [[UITextField alloc] initWithFrame: 14 CGRectMake(CGRectGetMaxX(self.leftLabel.frame) + kSpace, 15 CGRectGetMinY(self.leftLabel.frame), 16 self.frame.size.width - CGRectGetWidth(self.leftLabel.frame) - kSpace - kLabelX * 2, 17 CGRectGetHeight(self.leftLabel.frame))]; 18 // 设置边框样式 19 self.rightTextField.borderStyle = UITextBorderStyleRoundedRect; 20 // 添加到自定义视图 21 [self addSubview:self.rightTextField]; 22 }
③ 类的.h文件提供一些接口(方法),便于外界操作子视图。
1 #import <UIKit/UIKit.h> 2 3 @interface LTView : UIView 4 5 // .h文件声明属性,为了方便和外界通信 6 @property (nonatomic, strong) UILabel *leftLabel; 7 @property (nonatomic, strong) UITextField *rightTextField; 8 9 @end
④ 此时的 LTView 就变成了一个具有 label 和 textField 的视图了。
3> LTView在AppDelegate.m中的具体使用
1 // 用户名 2 LTView *userLTView = [[LTView alloc] initWithFrame:CGRectMake(10, 100, self.window.frame.size.width - 20, 50)]; 3 4 // 设置属性 5 userLTView.backgroundColor = [UIColor lightGrayColor]; 6 userLTView.leftLabel.text = @"用户名"; 7 userLTView.leftLabel.backgroundColor = [UIColor redColor]; 8 userLTView.rightTextField.placeholder = @"请输入用户名"; 9 userLTView.rightTextField.backgroundColor = [UIColor redColor]; 10 11 // 设置代理 12 userLTView.rightTextField.delegate = self; 13 14 // 添加父视图 15 [self.window addSubview:userLTView]; 16 17 // 密码 18 ZF_LTView *pwLTview = [[ZF_LTView alloc] initWithFrame: 19 CGRectMake(CGRectGetMinX(userLTView.frame), 20 CGRectGetMaxY(userLTView.frame) + 20, 21 CGRectGetWidth(userLTView.frame), 22 CGRectGetHeight(userLTView.frame))]; 23 24 // 设置属性 25 pwLTview.backgroundColor = [UIColor lightGrayColor]; 26 pwLTview.leftLabel.text = @"密码"; 27 pwLTview.rightTextField.placeholder = @"请输入密码"; 28 pwLTview.rightTextField.secureTextEntry = YES; 29 30 // 添加到父视图 31 [self.window addSubview:pwLTview];
效果图
2.视图控制器
1> 概述
视图控制器是应用程序数据和视图之间的重要桥梁,每个iOS应用程序只显示一个用户界面,显示的内容是由控制器或一组视图控制器协调管理。所以,视图控制器提供了一个基本的框架来构建应用程序。
UIViewController是所有视图控制器的父类。
iOS提供了许多内置的视图控制器,以支持标准的用户界面部分,比如导航控制器(UINavigationController),标签控制器 (UITabBarController), 表视图控制器(UITableViewController)等。
2> 视图控制器的功能
- 控制视图大小变换、布局视图、响应事件。
- 检测以及处理内存警告。
- 检测以及处理屏幕旋转。
- 检测视图的切换。
- 实现模块独立,提高复用性。
3> 视图控制器的使用
① 定义UIViewController的子类:
@interface LoginViewController:UIViewController
② 在APPDelegate里创建视图控制器对象,作为window的根视图控制器:
1 // 创建window 2 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 3 self.window.backgroundColor = [UIColor redColor]; 4 [self.window makeKeyAndVisible]; 5 // 设置根视图控制器 6 self.window.rootViewController = [[LoginViewController alloc] init];
③ 在viewDidLoad方法中使用默认创建好的视图对象view:
1 #pragma mark 视图加载完毕 2 - (void)viewDidLoad { 3 [super viewDidLoad]; 4 self.view.backgroundColor = [UIColor grayColor]; 5 NSLog(@"%s %d", __FUNCTION__, __LINE__); 6 // Do any additional setup after loading the view. 7 }
4> 视图控制器生命周期
viewDidLoad --> viewWillAppear --> viewDidAppear --> viewWillDisappear --> viewDidDisappear
1 @implementation ViewController 2 3 // 视图已经加载 4 - (void)viewDidLoad { 5 [super viewDidLoad]; 6 // Do any additional setup after loading the view, typically from a nib. 7 8 NSLog(@"1 %s__%d", __FUNCTION__, __LINE__); 9 } 10 11 // 视图将要出现 12 - (void)viewWillAppear:(BOOL)animated { 13 NSLog(@"2 %s__%d", __FUNCTION__, __LINE__); 14 } 15 // 视图将要消失 16 - (void)viewWillDisappear:(BOOL)animated { 17 NSLog(@"3 %s__%d", __FUNCTION__, __LINE__); 18 } 19 // 视图已经出现 20 - (void)viewDidAppear:(BOOL)animated { 21 NSLog(@"4 %s__%d", __FUNCTION__, __LINE__); 22 } 23 // 视图已经消失 24 - (void)viewDidDisappear:(BOOL)animated { 25 NSLog(@"5 %s__%d", __FUNCTION__, __LINE__); 26 } 27 28 - (void)didReceiveMemoryWarning { 29 [super didReceiveMemoryWarning]; 30 // Dispose of any resources that can be recreated. 31 } 32 33 @end
3.视图控制器指示视图
设置步骤
自定义视图类继承UIView。在初始化方法中添加子视图控件。
1 // 重写initWithFrame 2 - (instancetype)initWithFrame:(CGRect)frame 3 { 4 self = [super initWithFrame:frame]; 5 if (self) { 6 self.backgroundColor = [UIColor yellowColor]; 7 8 [self addAllViews]; 9 } 10 return self; 11 } 12 13 // 添加视图 14 - (void)addAllViews 15 { 16 /** 17 * 布局: userLabel userTextField loginButton 18 * 事件: 代理事件 按钮点击事件 (controller实现) 19 * @return nil 20 */ 21 22 // 布局userLabel 23 self.userLabel = [[UILabel alloc] initWithFrame:CGRectMake(40, 60, 100, 40)]; 24 self.userLabel.text = @"用户名"; 25 self.userLabel.textAlignment = NSTextAlignmentCenter; 26 [self addSubview:self.userLabel]; 27 28 // 布局userTextField 29 self.userTextField = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.userLabel.frame) + 20, CGRectGetMinY(self.userLabel.frame), 200, 40)]; 30 self.userTextField.borderStyle = UITextBorderStyleRoundedRect; 31 self.userTextField.placeholder = @"请输入用户名"; 32 [self addSubview:self.userTextField]; 33 34 // 布局loginButton 35 self.loginButton = [UIButton buttonWithType:UIButtonTypeSystem]; 36 self.loginButton.backgroundColor = [UIColor cyanColor]; 37 self.loginButton.frame = CGRectMake(50, CGRectGetMaxY(self.userTextField.frame) + kSpace, CGRectGetWidth(self.frame) - 100, 50); 38 [self.loginButton setTitle:@"登 录" forState:UIControlStateNormal]; 39 40 self.loginButton.tintColor = [UIColor whiteColor]; 41 self.loginButton.layer.cornerRadius = 10; 42 43 [self addSubview:self.loginButton]; 44 }
重写controller的loadView方法。创建自定义视图对象,并指定为controller的view。(注:loadView方法在控制器的view为nil的时候被调用,用于以编程的方式创建view的时候用到。loadView是使用代码生成视图的时候,当视图第一次载入的时候调用的方法,用于使用(写)代码来实现控件。)
1 // 加载视图 2 // 使用控制器指定自定义view(也就是替换控制器的view) 3 // self.view没有被创建对象,节省内存 4 - (void)loadView 5 { 6 // 初始化自定义视图 7 self.loginView = [[LoginView alloc] initWithFrame:[UIScreen mainScreen].bounds]; 8 // 使用自定义视图替换控制器视图 9 self.view = self.loginView; 10 }
将子视图控件对象设置为自定义视图类的属性,在viewDidLoad方法中进行设置:添加action、设置delegate等等。
1 // 处理事件一般都是在这个函数中实现 2 - (void)viewDidLoad { 3 [super viewDidLoad]; 4 // Do any additional setup after loading the view. 5 6 // 处理事件 7 8 // 1. 代理事件 9 self.loginView.userTextField.delegate = self; 10 11 // 2.按钮点击事件 12 [self.loginView.loginButton addTarget:self action:@selector(loginButtonClick) forControlEvents:UIControlEventTouchUpInside]; 13 }
在controller中添加按钮点击事件实现和代理方法的实现。
1 #pragma mark loginButtonClick Method (实现按钮点击方法) 2 3 - (void)loginButtonClick 4 { 5 NSLog(@"别点我..."); 6 SecondViewController *secondVC = [[SecondViewController alloc] init]; 7 8 [self presentViewController:secondVC animated:YES completion:nil]; 9 10 } 11 12 #pragma mark UITextFieldDelegate Method (代理方法实现) 13 14 // 点击return回收键盘 15 - (BOOL)textFieldShouldReturn:(UITextField *)textField 16 { 17 [textField resignFirstResponder]; 18 return YES; 19 } 20 21 // 触摸屏幕回收键盘 22 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 23 { 24 [self.view endEditing:YES]; 25 }
4.MVC
1> 概述
UIViewController是MVC设计模式的核心。
MVC是一个框架级的设计模式。
M是Model,主要用于建立数据模型(即数据的结构)。
V是View,我们能看到的所有控件都是view,view主要的功能是展示数据
C是控制器,主要是控制M和V的通信。
2> iOS中的MVC
5.屏幕旋转
1> 检测屏幕旋转
视图控制器本身能检测到屏幕的旋转,如果要处理屏幕旋转,需要重写几个方法:
supportedInterfaceOrientations(设置设备支持旋转的方向,如果不添加,视图控制器将无法检测屏幕的旋转)。
willRotateToInterfaceOrientation:duration:(暂停音乐、关闭视图交互等)。
willAnimateRotationToInterfaceOrientation:duration:(添加自定义动画等)。
didRotateFromInterfaceOrientation:(播放音乐、打开视图交互等)。
1 #pragma mark 检测屏幕旋转 2 // 屏幕所支持的样式 3 - (UIInterfaceOrientationMask)supportedInterfaceOrientations 4 { 5 // 支持所有的方向 6 return UIInterfaceOrientationMaskAll; 7 }
2> 视图处理
注意视图控制器会自动调整view的大小以适应屏幕旋转,bounds被修改,触发view的layoutSubviews方法。
view重写layoutSubviews方法,根据设备方向,重新布局。
[UIApplication sharedApplication].statusBarOrientation提供设备当前方向。
1 // 布局子视图:当屏幕旋转的时候,可以重新布局子视图的位置 2 - (void)layoutSubviews 3 { 4 // 如果是竖屏(UIInterfaceOrientationPortrait)的话,保持原来的尺寸 5 if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait) { 6 self.loginButton.frame = CGRectMake(50, CGRectGetMaxY(self.userTextField.frame) + kSpace, CGRectGetWidth(self.frame) - 100, 50); 7 } else { // 否则横屏改变位置 8 self.loginButton.frame = CGRectMake(50, CGRectGetMaxY(self.userTextField.frame) + kSpace, 636, 50); 9 } 10 }
6.内存警告
1> 概述
内存警告来源:手机内存80M,程序运行过程中内存接近80M时程序会为每一个视图控制器发送内存警告消息。
如何处理:
① 控制器能监测内存警告,以便我们避免内存不够引起的crash。
② 在定义的controller子类中重写didReceiveMemoryWarning方法。
③ 释放暂时不使用的资源(self.view及view的子视图例如数据对象、图 像)。
2> 代码
1 // 当接收内存警告的时候都会走这个方法 2 - (void)didReceiveMemoryWarning { 3 [super didReceiveMemoryWarning]; 4 // Dispose of any resources that can be recreated. 5 NSLog(@"%s__%d", __FUNCTION__, __LINE__); 6 }