iOS UI-九宫格
?
1 第一節課: 2 1.復習 3 2.運行App應用管理,簡單界面分析 4 3.一個應用為一個整體,直接創建一個appView然后計算frame 5 4.說明弊端,應該根據數據的個數來for循環創建 6 7 第二節課: 8 5.加載plist文件字典轉模型 9 6.分析計算frame 寬高固定,x,y動態去計算 10 6.1. 行號 row = i / columnCount 11 6.2 列號 col = i % columnCount 12 leftMargin = (屏幕的寬 - (appW * columnCount) - appColMagrin * (columnCount - 1)) * 0.5; 13 appX = leftMargin + (appW + appColMagrin) * col; 14 appY = topMargin + (appY + appRowMagrin) * row 15 16 第三節: 17 6.3創建appView內部三個字控件,iconView, nameLabel , downloadBtn 18 6.4 先創建設置背景色,計算frame添加到appView中 19 6.5 給子控件設置數據,設置label字體和文字對齊方法 20 注意點:給按鈕設置圖片或文字還有文字顏色時,要用set方法指定不同狀態的文字或圖片,不能直接訪問titleLabel去給按鈕設置文字 21 7.分析懶加載代碼中的問題封裝字典轉模型細節, 22 23 24 instancetype 是和id 25 1、相同點 26 都可以作為方法的返回類型 27 28 2、不同點 29 1> instancetype可以返回和方法所在類相同類型的對象,id只能返回未知類型的對象; 30 31 2> instancetype只能作為返回值,不能像id那樣作為參數,和聲明屬性 32 33 id是個萬能指針編譯時不確定真實類型,只有在運行時才知道真實的類型 34 instancetype在編譯時就可以確定真實類型,類型一般為所在類的對象類型 35 36 下午: 37 38 第一節課: 39 40 7.1 自定義構造方法,并提供一個類方法 41 7.2 自定義構造方法時的方法命名規范,注意點 42 7.3 代碼進一步優化,引出xib 43 8.xib和storyboard的區別及開發中如何去選擇 44 9.MVC概念的引入 45 9.1用xib去封裝appView,并創建一個繼承至UIView的類,和xib的類型關聯 46 9.2把xib中的控件連線到自定義類的.h中可以在外面直接訪問去給子控件設置數據 47 9.3.弊端,把模型變成屬性引入到自定義view類,當控制器為自定義view類的模型屬性賦值時會調用模型屬性的set方法,如果我們重寫了屬性得set方法就會調用我們重寫得set方法,在此方法中給appView中的子控件設置數據 48 49 第二節課: 50 10.添加下載按鈕點擊事件 51 10.1 點擊下載按鈕彈出提示標簽,并加入動畫 52 53 第三節課: 54 11.回顧用xib自定義view的步驟 55 1.創建一個xib文件,在xib文件中布局好子控件,并設置好對應控件的屬性 56 2.創建一個和xib文件相同的類,此類繼承至那個類,取決于xib文件中最頂層控件的類型, 57 3.指定xib文件的類型為我們自定義的類,然后把需要修改的控件拖線到所關聯類的.m文件中 58 4.自定義類,定義模型屬性,并重寫模型屬性的set方法,在此方法給子控件設置數據 59 5.在自定義類提供一個可供外部訪問的類方法,把加載xib創建appView的過程封裝到自定義類中 60 61 62 63 64 65 66 67 68 *********** UIViewAnimationOption(動畫選項,默認為勻速) ******** 69 常規動畫屬性設置(可以同時選擇多個進行設置) 70 71 UIViewAnimationOptionLayoutSubviews:動畫過程中保證子視圖跟隨運動。 72 73 UIViewAnimationOptionAllowUserInteraction:動畫過程中允許用戶交互。 74 75 UIViewAnimationOptionBeginFromCurrentState:所有視圖從當前狀態開始運行。 76 77 UIViewAnimationOptionRepeat:重復運行動畫。 78 79 UIViewAnimationOptionAutoreverse :動畫運行到結束點后仍然以動畫方式回到初始點。 80 81 UIViewAnimationOptionOverrideInheritedDuration:忽略嵌套動畫時間設置。 82 83 UIViewAnimationOptionOverrideInheritedCurve:忽略嵌套動畫速度設置。 84 85 UIViewAnimationOptionAllowAnimatedContent:動畫過程中重繪視圖(注意僅僅適用于轉場動畫)。 86 87 UIViewAnimationOptionShowHideTransitionViews:視圖切換時直接隱藏舊視圖、顯示新視圖,而不是將舊視圖從父視圖移除(僅僅適用于轉場動畫) 88 UIViewAnimationOptionOverrideInheritedOptions :不繼承父動畫設置或動畫類型。 89 90 2.動畫速度控制(可從其中選擇一個設置) 91 92 UIViewAnimationOptionCurveEaseInOut:動畫先緩慢,然后逐漸加速。 93 94 UIViewAnimationOptionCurveEaseIn :動畫逐漸變慢。 95 96 UIViewAnimationOptionCurveEaseOut:動畫逐漸加速。 97 98 UIViewAnimationOptionCurveLinear :動畫勻速執行,默認值。 99 100 3.轉場類型(僅適用于轉場動畫設置,可以從中選擇一個進行設置,基本動畫、關鍵幀動畫不需要設置) 101 102 UIViewAnimationOptionTransitionNone:沒有轉場動畫效果。 103 104 UIViewAnimationOptionTransitionFlipFromLeft :從左側翻轉效果。 105 106 UIViewAnimationOptionTransitionFlipFromRight:從右側翻轉效果。 107 108 UIViewAnimationOptionTransitionCurlUp:向后翻頁的動畫過渡效果。 109 110 UIViewAnimationOptionTransitionCurlDown :向前翻頁的動畫過渡效果。 111 112 UIViewAnimationOptionTransitionCrossDissolve:舊視圖溶解消失顯示下一個新視圖的效果。 113 114 UIViewAnimationOptionTransitionFlipFromTop :從上方翻轉效果。 115 116 UIViewAnimationOptionTransitionFlipFromBottom:從底部翻轉效果。?
一、創建九宮格?
實現思路
(1)明確每一塊用得是什么view
(2)明確每個view之間的父子關系,每個視圖都只有一個父視圖,擁有很多的子視圖。
(3)可以先嘗試逐個的添加格子,最后考慮使用for循環,完成所有uiview的創建
(4)加載app數據,根據數據長度創建對應個數的格子
(5)添加格子內部的子控件
(6)給內部的子控件裝配數據
#import "ViewController.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// 設置每行應用的個數int clumns = 3;// 獲取控制器所管理的view的寬度CGFloat viewWidth = self.view.frame.size.width;// 每個應用的寬和高CGFloat appW = 75;CGFloat appH = 90;CGFloat marginTop = 30;//第一行距頂部的距離CGFloat marginX = (viewWidth - appW*clumns)/(clumns+1);CGFloat marginY = marginX;//設每行之間的間距與marginX相等for (int i=0; i<9; i++) {//1.創建每個應用(UIView)UIView *appView = [[UIView alloc] init];//2.設置appView的屬性//2.1設置appView的背景色appView.backgroundColor = [UIColor orangeColor];//2.2設置appView的frame屬性//計算每個單元格的列索引int colIdx = i%clumns;//計算每個單元格的行索引int rowIdy = i/clumns;CGFloat appX = marginX+(appW+marginX)*colIdx;CGFloat appY = marginTop+(appH+marginY)*rowIdy;appView.frame = CGRectMake(appX, appY, appW, appH);//3.將appView加到self.view [self.view addSubview:appView];} }?
二、向九宮格內加控件
1 #import "ViewController.h" 2 3 @interface ViewController () 4 /** 5 * 用來存放所有數據的數組 6 */ 7 @property (nonatomic, strong) NSArray *appes; 8 @end 9 10 @implementation ViewController 11 12 /** 13 * 控制器的view加載完成之后就會調用此方法 14 */ 15 - (void)viewDidLoad { 16 [super viewDidLoad]; 17 // 格子之間的間距 18 CGFloat margin = 20; 19 // 格子的寬 20 CGFloat appViewW = 100; 21 // 格子的高 22 CGFloat appViewH = 120; 23 // 一行中用三個格子 24 NSInteger column = 3; 25 // 最左邊的間距 = (控制器view的寬 - 一行中所有格子的寬 - 格子間的間距 * (一行中格子的個數 - 1)) * 0.5 26 CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - 1) *margin) * 0.5; 27 CGFloat topMargin = leftMargin; 28 // 根據數據的個數來動畫創建每一個應用 29 for (NSInteger i = 0; i < self.appes.count; i++) { 30 31 // 0> 先取出每一個應該的數據 32 NSDictionary *dict = self.appes[i]; 33 34 // 1.創建appView 用來裝里面的子控件 35 UIView *appView = [[UIView alloc] init]; 36 // 2.設置背景色 37 // appView.backgroundColor = [UIColor blueColor]; 38 39 // 計算列號 40 NSInteger col = i % column; 41 // 計算行號 42 NSInteger row = i / column; 43 // 3.設置frame 44 // 計算appViewX = 左邊間距 + (appView寬 + 格子間距) *當前格子是在當前行中的第幾個 45 CGFloat appViewX = leftMargin + (appViewW + margin) * col; 46 // appViewY = 頂部間距 + (appViewH + margin) * 當前格子在當前列中是第幾個 47 CGFloat appViewY = topMargin + (appViewH + margin) * row; 48 49 appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH); 50 51 // 4.添加到控制器的view中 52 [self.view addSubview:appView]; 53 54 // 5.創建應用圖片 55 UIImageView *iconView = [[UIImageView alloc] init]; 56 // 設置背景色 57 // iconView.backgroundColor = [UIColor purpleColor]; 58 CGFloat iconW = 70; 59 CGFloat iconH = iconW; 60 CGFloat iconX = (appViewW - iconW) * 0.5; 61 CGFloat iconY = 0; 62 iconView.frame = CGRectMake(iconX, iconY, iconW, iconH); 63 [appView addSubview:iconView]; 64 65 // 設置應用圖片 66 iconView.image = [UIImage imageNamed:dict[@"icon"]]; 67 68 // 6.應用的名稱 69 UILabel *nameLabel = [[UILabel alloc] init]; 70 // 設置背景色 71 // nameLabel.backgroundColor = [UIColor yellowColor]; 72 CGFloat nameX = 0; 73 // CGFloat nameY = iconY + iconH; 74 CGFloat nameY = CGRectGetMaxY(iconView.frame); 75 CGFloat nameW = appViewW; 76 CGFloat nameH = 21; 77 // 設置frame 78 nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH); 79 // 把名稱標簽添加到父控件中 80 [appView addSubview:nameLabel]; 81 82 // 設置應用名稱 83 nameLabel.text = dict[@"name"]; 84 // 設置字體大小 85 nameLabel.font = [UIFont systemFontOfSize:13.0]; 86 // 設置文字居中 87 nameLabel.textAlignment = NSTextAlignmentCenter; 88 89 // 7.下載按鈕 90 UIButton *downloadBtn = [[UIButton alloc] init]; 91 // downloadBtn.backgroundColor = [UIColor redColor]; 92 CGFloat downloadX = iconX; 93 CGFloat downloadY = CGRectGetMaxY(nameLabel.frame); 94 CGFloat downlaodW = iconW; 95 CGFloat downlaodH = 30; 96 downloadBtn.frame = CGRectMake(downloadX, downloadY, downlaodW, downlaodH); 97 [appView addSubview:downloadBtn]; 98 99 // 設置按鈕背景圖片 100 [downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal]; 101 [downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateDisabled]; 102 // 設置按鈕的文字 103 [downloadBtn setTitle:@"下載" forState:UIControlStateNormal]; 104 [downloadBtn setTitle:@"已下載" forState:UIControlStateDisabled]; 105 106 downloadBtn.titleLabel.font = [UIFont systemFontOfSize:15]; 107 } 108 } 109 110 111 #pragma mark - 懶加載 112 - (NSArray *)appes { 113 // 1.判斷當前的數組屬性是否為空,如果為空的時候再去加載數據 114 if (_appes == nil) { 115 // 2.獲取plist文件路徑 116 NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil]; 117 // 3.加載plist文件 118 NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; 119 _appes = dictArr; 120 121 } 122 123 return _appes; 124 125 } 126 127 @end三、向九宮格內加數據
1 #import "ViewController.h" 2 3 @interface ViewController () 4 /** 5 * 用來存放所有數據的數組 6 */ 7 @property (nonatomic, strong) NSArray *appes; 8 @end 9 10 @implementation ViewController 11 12 /** 13 * 控制器的view加載完成之后就會調用此方法 14 */ 15 - (void)viewDidLoad { 16 [super viewDidLoad]; 17 // 格子之間的間距 18 CGFloat margin = 20; 19 // 格子的寬 20 CGFloat appViewW = 100; 21 // 格子的高 22 CGFloat appViewH = 120; 23 // 一行中用三個格子 24 NSInteger column = 3; 25 // 最左邊的間距 = (控制器view的寬 - 一行中所有格子的寬 - 格子間的間距 * (一行中格子的個數 - 1)) * 0.5 26 CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - 1) *margin) * 0.5; 27 CGFloat topMargin = leftMargin; 28 // 根據數據的個數來動畫創建每一個應用 29 for (NSInteger i = 0; i < self.appes.count; i++) { 30 31 // 0> 先取出每一個應該的數據 32 NSDictionary *dict = self.appes[i]; 33 34 // 1.創建appView 用來裝里面的子控件 35 UIView *appView = [[UIView alloc] init]; 36 // 2.設置背景色 37 // appView.backgroundColor = [UIColor blueColor]; 38 39 // 計算列號 40 NSInteger col = i % column; 41 // 計算行號 42 NSInteger row = i / column; 43 // 3.設置frame 44 // 計算appViewX = 左邊間距 + (appView寬 + 格子間距) *當前格子是在當前行中的第幾個 45 CGFloat appViewX = leftMargin + (appViewW + margin) * col; 46 // appViewY = 頂部間距 + (appViewH + margin) * 當前格子在當前列中是第幾個 47 CGFloat appViewY = topMargin + (appViewH + margin) * row; 48 49 appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH); 50 51 // 4.添加到控制器的view中 52 [self.view addSubview:appView]; 53 54 // 5.創建應用圖片 55 UIImageView *iconView = [[UIImageView alloc] init]; 56 // 設置背景色 57 // iconView.backgroundColor = [UIColor purpleColor]; 58 CGFloat iconW = 70; 59 CGFloat iconH = iconW; 60 CGFloat iconX = (appViewW - iconW) * 0.5; 61 CGFloat iconY = 0; 62 iconView.frame = CGRectMake(iconX, iconY, iconW, iconH); 63 [appView addSubview:iconView]; 64 65 // 設置應用圖片 66 iconView.image = [UIImage imageNamed:dict[@"icon"]]; 67 68 // 6.應用的名稱 69 UILabel *nameLabel = [[UILabel alloc] init]; 70 // 設置背景色 71 // nameLabel.backgroundColor = [UIColor yellowColor]; 72 CGFloat nameX = 0; 73 // CGFloat nameY = iconY + iconH; 74 CGFloat nameY = CGRectGetMaxY(iconView.frame); 75 CGFloat nameW = appViewW; 76 CGFloat nameH = 21; 77 // 設置frame 78 nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH); 79 // 把名稱標簽添加到父控件中 80 [appView addSubview:nameLabel]; 81 82 // 設置應用名稱 83 nameLabel.text = dict[@"name"]; 84 // 設置字體大小 85 nameLabel.font = [UIFont systemFontOfSize:13.0]; 86 // 設置文字居中 87 nameLabel.textAlignment = NSTextAlignmentCenter; 88 89 // 7.下載按鈕 90 UIButton *downloadBtn = [[UIButton alloc] init]; 91 // downloadBtn.backgroundColor = [UIColor redColor]; 92 CGFloat downloadX = iconX; 93 CGFloat downloadY = CGRectGetMaxY(nameLabel.frame); 94 CGFloat downlaodW = iconW; 95 CGFloat downlaodH = 30; 96 downloadBtn.frame = CGRectMake(downloadX, downloadY, downlaodW, downlaodH); 97 [appView addSubview:downloadBtn]; 98 99 // 設置按鈕背景圖片 100 [downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal]; 101 [downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateDisabled]; 102 // 設置按鈕的文字 103 [downloadBtn setTitle:@"下載" forState:UIControlStateNormal]; 104 [downloadBtn setTitle:@"已下載" forState:UIControlStateDisabled]; 105 106 downloadBtn.titleLabel.font = [UIFont systemFontOfSize:15]; 107 } 108 } 109 110 111 #pragma mark - 懶加載 112 - (NSArray *)appes { 113 // 1.判斷當前的數組屬性是否為空,如果為空的時候再去加載數據 114 if (_appes == nil) { 115 // 2.獲取plist文件路徑 116 NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil]; 117 // 3.加載plist文件 118 NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; 119 _appes = dictArr; 120 121 } 122 123 return _appes; 124 125 }代碼問題
我們是直接通過字典的鍵名獲取plist中的數據信息,在viewController中需要直接和數據打交道,如果需要多次使用可能會因為不小心把鍵名寫錯,而程序并不報錯。鑒于此,可以考慮把字典數據轉換成一個模型,把數據封裝到一個模型中去,讓viewController不再直接和數據打交道,而是和模型交互。
一般情況下,設置數據和取出數據都使用“字符串類型的key”,編寫這些key時,編輯器沒有智能提示,需要手敲。如:
dict[@"name"] =?@"Jack";
NSString?*name = dict[@"name"];
手敲字符串key,key容易寫錯
Key如果寫錯了,編譯器不會有任何警告和報錯,造成設錯數據或者取錯數據
?
?
四、字典轉模型
字典轉模型的好處:
(1)降低代碼的耦合度
(2)所有字典轉模型部分的代碼統一集中在一處處理,降低代碼出錯的幾率
(3)在程序中直接使用模型的屬性操作,提高編碼效率?
(4)調用方不用關心模型內部的任何處理細節
字典轉模型的注意點:
模型應該提供一個可以傳入字典參數的構造方法
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)xxxWithDict:(NSDictionary *)dict;
提示:在模型中合理地使用只讀屬性,可以進一步降低代碼的耦合度。
#import <Foundation/Foundation.h> /** NSString block用copy除了字符串和 block 控件 其它基本OC對象都用strongweak 控件最好都用assgin 基本數據類型*/ @interface HMApp : NSObject /** 應用圖片 */ @property (nonatomic, copy) NSString *icon; /** 應用名稱 */ @property (nonatomic, copy) NSString *name;// id他instancetype有什么區別 // 1.相同點:他們都可以當方法的返回值 // 2.不同點:id可以來聲明變量,id可以當參數類型,\ // id是一個萬能指針,他在編譯的時候不會確定真實的類型,只有在運行時候才知道真實類型 // instancetype在編譯的時候就能確定他的返回值真實類型,這種更安全 //clang 3.5/** */ - (instancetype)initWithDict:(NSDictionary *)dict;//用字典實例化對象的成員方法 + (instancetype)appWithDict:(NSDictionary *)dict;//用字典實例化對象的類方法,又稱工廠方法 @end#import "HMApp.h"@implementation HMApp - (instancetype)initWithDict:(NSDictionary *)dict {if (self = [super init]) {self.icon = dict[@"icon"];self.name = dict[@"name"];
? ? ? ??[self setValuesForKeysWithDictionary:dict];//加載所有屬性
}return self; }+ (instancetype)appWithDict:(NSDictionary *)dict {return [[self alloc] initWithDict:dict]; } @end/**xib和stroyboard的區別1.相同點:都可以用來我們軟件界面2.不同點:在storyboard可以用來搭建整個應用的所有界面,最少也是一個界面xib可以用來描述一個界面中的某一個部分,或一個應用的一個界面,及整個界面*/ #import "ViewController.h" #import "HMApp.h"@interface ViewController () /*** 用來存放所有數據的數組*/ @property (nonatomic, strong) NSArray *appes; @end@implementation ViewController/*** 控制器的view加載完成之后就會調用此方法*/ - (void)viewDidLoad {[super viewDidLoad];// 格子之間的間距CGFloat margin = 20;// 格子的寬CGFloat appViewW = 100;// 格子的高CGFloat appViewH = 120;// 一行中用三個格子NSInteger column = 3;// 最左邊的間距 = (控制器view的寬 - 一行中所有格子的寬 - 格子間的間距 * (一行中格子的個數 - 1)) * 0.5CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - 1) *margin) * 0.5;CGFloat topMargin = leftMargin;// 根據數據的個數來動畫創建每一個應用for (NSInteger i = 0; i < self.appes.count; i++) {// 0> 先取出每一個應該的數據 // NSDictionary *dict = self.appes[i];// 取數組中每一個用來表示數據的模型對象HMApp *app = self.appes[i];// 1.創建appView 用來裝里面的子控件UIView *appView = [[UIView alloc] init];// 2.設置背景色 // appView.backgroundColor = [UIColor blueColor];// 計算列號NSInteger col = i % column;// 計算行號NSInteger row = i / column;// 3.設置frame// 計算appViewX = 左邊間距 + (appView寬 + 格子間距) *當前格子是在當前行中的第幾個CGFloat appViewX = leftMargin + (appViewW + margin) * col;// appViewY = 頂部間距 + (appViewH + margin) * 當前格子在當前列中是第幾個CGFloat appViewY = topMargin + (appViewH + margin) * row;appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH);// 4.添加到控制器的view中 [self.view addSubview:appView];// 5.創建應用圖片UIImageView *iconView = [[UIImageView alloc] init];// 設置背景色 // iconView.backgroundColor = [UIColor purpleColor];CGFloat iconW = 70;CGFloat iconH = iconW;CGFloat iconX = (appViewW - iconW) * 0.5;CGFloat iconY = 0;iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);[appView addSubview:iconView];// 設置應用圖片iconView.image = [UIImage imageNamed:app.icon];// 6.應用的名稱UILabel *nameLabel = [[UILabel alloc] init];// 設置背景色 // nameLabel.backgroundColor = [UIColor yellowColor];CGFloat nameX = 0;// CGFloat nameY = iconY + iconH;CGFloat nameY = CGRectGetMaxY(iconView.frame);CGFloat nameW = appViewW;CGFloat nameH = 21;// 設置framenameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH);// 把名稱標簽添加到父控件中 [appView addSubview:nameLabel];// 設置應用名稱nameLabel.text = app.name;// 設置字體大小nameLabel.font = [UIFont systemFontOfSize:13.0];// 設置文字居中nameLabel.textAlignment = NSTextAlignmentCenter;// 7.下載按鈕UIButton *downloadBtn = [[UIButton alloc] init]; // downloadBtn.backgroundColor = [UIColor redColor];CGFloat downloadX = iconX;CGFloat downloadY = CGRectGetMaxY(nameLabel.frame);CGFloat downlaodW = iconW;CGFloat downlaodH = 30;downloadBtn.frame = CGRectMake(downloadX, downloadY, downlaodW, downlaodH);[appView addSubview:downloadBtn];// 設置按鈕背景圖片[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateDisabled];// 設置按鈕的文字[downloadBtn setTitle:@"下載" forState:UIControlStateNormal];[downloadBtn setTitle:@"已下載" forState:UIControlStateDisabled];downloadBtn.titleLabel.font = [UIFont systemFontOfSize:15];} }#pragma mark - 懶加載 - (NSArray *)appes {// 1.判斷當前的數組屬性是否為空,如果為空的時候再去加載數據if (_appes == nil) {// 2.獲取plist文件路徑NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];// 3.加載plist文件NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];// 創建一個可變數據用來保存每一個模型對象(創建可變數組時并給其分配好容量)NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:dictArr.count];// 遍歷字典數組把每一個字典轉換成一個模型對象for (NSDictionary *dict in dictArr) {// 創建模型對象 // HMApp *app = [[HMApp alloc] initWithDict:dict];HMApp *app = [HMApp appWithDict:dict];// 給模型對象中的屬性賦值 // app.icon = dict[@"icon"]; // app.name = dict[@"name"];// 把模型添加到數組 [arrM addObject:app];}// 把裝有所有模型的數組賦值給我們的數組屬性_appes = arrM;}return _appes;} @end?
?
五、用xib自定義view
HMAppView.xib文件
1 /*--------------------Model-------------------*/ 2 3 #import <Foundation/Foundation.h> 4 /** NSString block用copy 5 除了字符串和 block 控件 其它基本OC對象都用strong 6 weak 控件最好都用 7 assgin 基本數據類型 8 */ 9 @interface HMApp : NSObject 10 /** 應用圖片 */ 11 @property (nonatomic, copy) NSString *icon; 12 /** 應用名稱 */ 13 @property (nonatomic, copy) NSString *name; 14 15 // id他instancetype有什么區別 16 // 1.相同點:他們都可以當方法的返回值 17 // 2.不同點:id可以來聲明變量,id可以當參數類型,\ 18 // id是一個萬能指針,他在編譯的時候不會確定真實的類型,只有在運行時候才知道真實類型 19 // instancetype在編譯的時候就能確定他的返回值真實類型,這種更安全 20 //clang 3.5 21 - (instancetype)initWithDict:(NSDictionary *)dict; 22 + (instancetype)appWithDict:(NSDictionary *)dict; 23 @end 24 25 26 27 #import "HMApp.h" 28 29 @implementation HMApp 30 - (instancetype)initWithDict:(NSDictionary *)dict { 31 if (self = [super init]) { 32 self.icon = dict[@"icon"]; 33 self.name = dict[@"name"]; 34 } 35 36 return self; 37 } 38 39 + (instancetype)appWithDict:(NSDictionary *)dict { 40 return [[self alloc] initWithDict:dict]; 41 } 42 @end 43 44 /*-----------------View---------------------*/ 45 #import <UIKit/UIKit.h> 46 @class HMApp; 47 @interface HMAppView : UIView 48 // 把模型變成一個屬性引用到自定義視圖中 49 @property (nonatomic, strong) HMApp *app; 50 51 + (instancetype)appView; 52 @end 53 54 55 56 #import "HMAppView.h" 57 #import "HMApp.h" 58 59 @interface HMAppView () 60 /** 應用的圖片 */ 61 @property (weak, nonatomic) IBOutlet UIImageView *iconView; 62 /** 應用的名稱 */ 63 @property (weak, nonatomic) IBOutlet UILabel *nameLabel; 64 @end 65 66 @implementation HMAppView 67 // 當點擊下載按鈕之后調用的方法 68 - (IBAction)downloadBtnClick:(UIButton *)downBtn { 69 NSLog(@"%ld----%@", self.tag ,self); 70 // 1.把按鈕設置為禁用狀態 71 downBtn.enabled = NO; 72 // 2.創建一個label 73 UILabel *downLabel = [[UILabel alloc] init]; 74 downLabel.text = [NSString stringWithFormat:@"%@下載完成", self.app.name]; 75 // 設置字體 76 downLabel.font = [UIFont systemFontOfSize:13.0]; 77 // 設置文字居中 78 downLabel.textAlignment = NSTextAlignmentCenter; 79 // 設置label的文字顏色 80 downLabel.textColor = [UIColor redColor]; 81 // 設置背景色 82 downLabel.backgroundColor = [UIColor blackColor]; 83 // 設置bounds 84 downLabel.bounds = CGRectMake(0, 0, 200, 21); 85 // 設置標簽的位置在屏幕的中心 86 downLabel.center = self.superview.center; 87 // 把提示標簽添加在控制器的view上 88 [self.superview addSubview:downLabel]; 89 // 設置label透明度 90 downLabel.alpha = 0.0; 91 // 設置圓角半徑 92 downLabel.layer.cornerRadius = 5; 93 // 把超出邊界的部分裁剪掉 94 downLabel.clipsToBounds = YES; 95 // downLabel.layer.masksToBounds = YES; 96 97 //執行一個兩秒中的動畫,讓標簽慢慢的顯示 98 [UIView animateWithDuration:2.0 animations:^{ // 表示要執行的動畫代碼 99 // 設置label的透明度 100 downLabel.alpha = 0.7; 101 } completion:^(BOOL finished) { // 表示動畫執行完成之后要做得事情 102 // 上面的動畫執行完成之后推遲2秒之后執行一個2秒的一個動畫 103 [UIView animateWithDuration:2.0 delay:2.0 options:UIViewAnimationOptionCurveLinear animations:^{ 104 // 設置label透明度 105 downLabel.alpha = 0.0; 106 } completion:^(BOOL finished) { // 動畫執行完成之后把label從父控件中移除 107 // 把這個label從它的父控件中移除掉 108 [downLabel removeFromSuperview]; 109 }]; 110 }]; 111 } 112 113 114 + (instancetype)appView { 115 return [[[NSBundle mainBundle] loadNibNamed:@"HMAppView" owner:nil options:nil]lastObject]; 116 } 117 // 重寫模型屬性的set方法,當外部給自定義視圖的模型屬性賦值時就會調用此方法, 118 - (void)setApp:(HMApp *)app { 119 #warning mark - 重寫set方法一定要注意給屬性下劃線的成員變量賦值 120 _app = app; 121 // 1.設置應用圖片 122 self.iconView.image = [UIImage imageNamed:app.icon]; 123 // 2.設置應用名稱 124 self.nameLabel.text = app.name; 125 126 127 } 128 129 130 @end 131 132 /*-------------------Controller--------------*/ 133 /** 134 xib和stroyboard的區別 135 1.相同點:都可以用來我們軟件界面 136 2.不同點:在storyboard可以用來搭建整個應用的所有界面,最少也是一個界面 137 xib可以用來描述一個界面中的某一個部分,或一個應用的一個界面,及整個界面 138 */ 139 #import "ViewController.h" 140 #import "HMApp.h" 141 #import "HMAppView.h" 142 143 @interface ViewController () 144 /** 145 * 用來存放所有數據的數組 146 */ 147 @property (nonatomic, strong) NSArray *appes; 148 @end 149 150 @implementation ViewController 151 152 /** 153 * 控制器的view加載完成之后就會調用此方法 154 */ 155 - (void)viewDidLoad { 156 [super viewDidLoad]; 157 // 格子之間的間距 158 CGFloat margin = 20; 159 // // 格子的寬 160 // CGFloat appViewW = 100; 161 // // 格子的高 162 // CGFloat appViewH = 120; 163 // 一行中用三個格子 164 NSInteger column = 3; 165 // 根據數據的個數來動畫創建每一個應用 166 for (NSInteger i = 0; i < self.appes.count; i++) { 167 168 // 1.創建appView 169 HMAppView *appView = [HMAppView appView]; 170 appView.tag = i; 171 // 2.取數組中每一個用來表示數據的模型對象 172 HMApp *app = self.appes[i]; 173 // 3.給自定義視圖傳遞模型 174 appView.app = app; 175 // 自定義視圖的大小應該根據xib中的視圖的大小來動態的設置而不應該直接固定死 176 // 4.拿到xib中appView的寬 177 CGFloat appViewW = appView.frame.size.width; 178 // xib中appView的高來表示我們一個視圖的高 179 CGFloat appViewH = appView.frame.size.height; 180 // 最左邊的間距 = (控制器view的寬 - 一行中所有格子的寬 - 格子間的間距 * (一行中格子的個數 - 1)) * 0.5 181 CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - 1) *margin) * 0.5; 182 // 頭部間距 183 CGFloat topMargin = leftMargin; 184 // 計算列號 185 NSInteger col = i % column; 186 // 計算行號 187 NSInteger row = i / column; 188 // 3.設置frame 189 // 計算appViewX = 左邊間距 + (appView寬 + 格子間距) *當前格子是在當前行中的第幾個 190 CGFloat appViewX = leftMargin + (appViewW + margin) * col; 191 // appViewY = 頂部間距 + (appViewH + margin) * 當前格子在當前列中是第幾個 192 CGFloat appViewY = topMargin + (appViewH + margin) * row; 193 194 appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH); 195 196 // 4.添加到控制器的view中 197 [self.view addSubview:appView]; 198 199 } 200 } 201 202 203 #pragma mark - 懶加載 204 - (NSArray *)appes { 205 // 1.判斷當前的數組屬性是否為空,如果為空的時候再去加載數據 206 if (_appes == nil) { 207 // 2.獲取plist文件路徑 208 NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil]; 209 // 3.加載plist文件 210 NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; 211 212 // 創建一個可變數據用來保存每一個模型對象(創建可變數組時并給其分配好容量) 213 NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:dictArr.count]; 214 // 遍歷字典數組把每一個字典轉換成一個模型對象 215 for (NSDictionary *dict in dictArr) { 216 // 創建模型對象 217 // HMApp *app = [[HMApp alloc] initWithDict:dict]; 218 HMApp *app = [HMApp appWithDict:dict]; 219 // 給模型對象中的屬性賦值 220 // app.icon = dict[@"icon"]; 221 // app.name = dict[@"name"]; 222 // 把模型添加到數組 223 [arrM addObject:app]; 224 } 225 // 把裝有所有模型的數組賦值給我們的數組屬性 226 _appes = arrM; 227 228 } 229 230 return _appes; 231 232 } 233 234 235 /** 用xib來自定義一個視圖的步驟 236 1.創建一個xib文件用來描述我們局部界面(并在里面擺放好所有的子控件,并設置好它們的屬性) 237 2.創建一個類來和我們的xib文件進行關聯(這個類也是用來管理我們的xib文件,創建的自定義類的類名最好和我們xib的文件名稱一樣)(創建的類它要繼承至什么類,取決于xib文件中最頂層控件的類型) 238 3.指定xib中class類型,如果不指定創建出來的xib和我們的自定義類沒有任何關系 239 4.把需要修改或需要設置的控件連線到我們自定義類.m中 240 5.在自定義view類的.h文件引入模型,就是把模型當成一個屬性定義在我們的自定義view類中 241 6.重寫模型屬性set方法,當外部給這個模型屬性賦值的時候就會調用模型屬性的set方法,我們在重寫的模型屬性的set方法中給自定義視圖的子控件去設置數據 242 243 */ 244 245 @end?
補充說明
?View的封裝思路
(1) 如果一個view內部的子控件比較多,一般會考慮自定義一個view,把它內部子控件的創建屏蔽起來,不讓外界關心
(2) 外界可以傳入對應的模型數據給view,view拿到模型數據后給內部的子控件設置對應的數據
?
mvc機制簡單說明
?
說明:
(1)在開發過程中,作為控制器處理的量級應該很輕,不該操心的不操心。協調好模型和視圖就ok了,要學會當一個好老板。
(2)三個部分各司其職,數據模型只負責數據的處理,視圖部分只負責把拿到的數據進行顯示,兩個部分都是被動的,等待著大管家控制器的調遣。
(3)在OC中,如果視圖和數據模型之間有通道,那控制器是否處于失控狀態呢?
?
1.MVC是一種設計思想,貫穿于整個iOS開發中,需要積累一定的項目經驗,才能深刻體會其中的含義和好處 MVC中的三個角色 M:Model,模型數據 V:View,視圖(界面) C:Control,控制中心 2.MVC的幾個明顯的特征和體現: View上面顯示什么東西,取決于Model 只要Model數據改了,View的顯示狀態會跟著更改 Control負責初始化Model,并將Model傳遞給View去解析展示總結
以上是生活随笔為你收集整理的iOS UI-九宫格的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三 定语从句(2021-11-04)
- 下一篇: 联通烽火HG680-L线刷固件 解决-卡