定義視圖:系統標準UI以外,本身組合而出的新的視圖。 編程
定義視圖的優勢:設計模式
iOS提供了不少UI組件,藉助它們咱們能夠實現不一樣的功能。儘管如此,實際開發中,咱們還須要自定義視圖。積累本身的代碼庫,方便開發。本身封裝的視圖,能像系統UI控件同樣,用於別的項目中,能大大下降開發成本,提升開發效率。app
高質量代碼的特色:可複用,可移植,精煉等。(高內聚,低耦合)框架
根據需求的不一樣,自定義視圖繼承的類也有所不一樣。通常自定義的視圖會繼承於UIView。如下是自定義視圖的要點:ide
① 建立一個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 的視圖了。atom
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];
效果圖spa
視圖控制器是應用程序數據和視圖之間的重要橋樑,每一個iOS應用程序只顯示一個用戶界面,顯示的內容是由控制器或一組視圖控制器協調管理。因此,視圖控制器提供了一個基本的框架來構建應用程序。
UIViewController是全部視圖控制器的父類。
iOS提供了許多內置的視圖控制器,以支持標準的用戶界面部分,好比導航控制器(UINavigationController),標籤控制器 (UITabBarController), 表視圖控制器(UITableViewController)等。
① 定義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 }
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
自定義視圖類繼承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 }
UIViewController是MVC設計模式的核心。
MVC是一個框架級的設計模式。
M是Model,主要用於創建數據模型(即數據的結構)。
V是View,咱們能看到的全部控件都是view,view主要的功能是展現數據
C是控制器,主要是控制M和V的通訊。
視圖控制器自己能檢測到屏幕的旋轉,若是要處理屏幕旋轉,須要重寫幾個方法:
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 }
內存警告來源:手機內存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 }