掌握
UIView的常見屬性和方法
九宮格計算方法
字典轉模型
Xib的使用
自定義view(view的封裝)
簡單的MVC
搭建九宮格的步驟
明確每一塊用的是什么view
明確每個view之間的父子關系
先嘗試逐個逐個添加格子,最后考慮使用for循環
加載app數據,根據數據長度創建對應個數的格子
添加格子內部的子控件
給格子內部的子控件裝配數據
用模型取代字典的好處
使用字典的壞處
一般情況下,設置數據和取出數據都使用“字符串類型的key”,編寫這些key時,編輯器沒有智能提示,需要手敲
dict[@"name"] = @"Jack";
NSString *name = dict[@"name"];
手敲字符串key,key容易寫錯
Key如果寫錯了,編譯器不會有任何警告和報錯,造成設錯數據或者取錯數據
使用模型的好處
所謂模型,其實就是數據模型,專門用來存放數據的對象,用它來表示數據會更加專業
模型設置數據和取出數據都是通過它的屬性,屬性名如果寫錯了,編譯器會馬上報錯,因此,保證了數據的正確性
使用模型訪問屬性時,編譯器會提供一系列的提示,提高編碼效率
app.name = @"Jack";
NSString *name = app.name;
字典轉模型
字典轉模型的過程最好封裝在模型內部
模型應該提供一個可以傳入字典參數的構造方法
-(instancetype)initWithDict:(NSDictionary *)dict;
- (instancetype)xxxWithDict:(NSDictionary
*)dict;
Instancetype
instancetype在類型表示上,跟id一樣,可以表示任何對象類型
instancetype只能用在返回值類型上,不能像id一樣用在參數類型上
instancetype比id多一個好處:編譯器會檢測instancetype的真實類型
注意點
一個控件有2種創建方式
通過代碼創建
初始化時一定會調用initWithFrame:方法
通過xib\storyboard創建
初始化時不會調用initWithFrame:方法,只會調用initWithCoder:方法
初始化完畢后會調用awakeFromNib方法
有時候希望在控件初始化時做一些初始化操作,比如添加子控件、設置基本屬性
這時需要根據控件的創建方式,來選擇在initWithFrame:(給控件設置位置)、initWithCoder:、awakeFromNib(初始化控件)的哪個方法中操作
Xib和storyboard對比
共同點:
都用來描述軟件界面
都用Interface
Builder工具來編輯
不同點
Xib是輕量級的,用來描述局部的UI界面
Storyboard是重量級的,用來描述整個軟件的多個界面,并且能展示多個界面之間的跳轉關系
view的封裝
如果一個view內部的子控件比較多,一般會考慮自定義一個view,把它內部子控件的創建屏蔽起來,不讓外界關心
外界可以傳入對應的模型數據給view,view拿到模型數據后給內部的子控件設置對應的數據
UILabel的常見設置
@property(nonatomic,copy) NSString *text; // 顯示的文字
@property(nonatomic,retain) UIFont *font; // 字體
@property(nonatomic,retain) UIColor *textColor; // 文字顏色
@property(nonatomic) NSTextAlignment textAlignment; // 對齊模式(比如左對齊、居中對齊、右對齊)
UIFont
UIFont代表字體,常見創建方法有以下幾個:
(UIFont*)systemFontOfSize:(CGFloat)fontSize; // 系統默認字體
(UIFont*)boldSystemFontOfSize:(CGFloat)fontSize; // 粗體
(UIFont *)italicSystemFontOfSize:(CGFloat)fontSize; // 斜體
UIButton的常見設置
-(void)setTitle:(NSString *)title forState:(UIControlState)state; // 設置按鈕的文字
-(void)setTitleColor:(UIColor *)color forState:(UIControlState)state; // 設置按鈕的文字顏色
-(void)setImage:(UIImage *)image forState:(UIControlState)state; // 設置按鈕內部的小圖片
-(void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state; // 設置按鈕的背景圖片
// 設置按鈕的文字字體(需要拿到按鈕內部的label來設置)
btn.titleLabel.font= [UIFont systemFontOfSize:13];
-(NSString *)titleForState:(UIControlState)state; // 獲得按鈕的文字
-(UIColor *)titleColorForState:(UIControlState)state; // 獲得按鈕的文字顏色
-(UIImage *)imageForState:(UIControlState)state; // 獲得按鈕內部的小圖片
-(UIImage *)backgroundImageForState:(UIControlState)state; //獲得按鈕的背景圖片
獲取plist的全路徑方法:
當NSString*path = [[NSBundle mainBundle]
pathForrResource:@"shop" ofType:@"plist"];
當解析Plist文件
接下來通過代碼來解析Plist文件中的數據
獲得Plist文件的全路徑NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle pathForResource:@"shops" ofType:@"plist"];
用代碼的方式去自定義控件的注意點:
Plist的使用注意:
- Plist的文件名不能叫做"info"/"Info"之類(會出現不可預計的錯誤)
2.添加plist等文件資源的時候,一定要勾選下面的選項(黏貼等選項)
1.layoutSubvies 布局內部的自控件(子控件frame發生變化的時候才會調用)
一定要調用[superlayouSubvies]記住了是一定會調用這個方法
只要當前的view的frame發生改變就會調用這個方法
view一初始化完也會調用這個方法,嘗試著給自己的子控件賦值
步驟1. 初始化自定義的view (只是調用init方法)
2. 設置frame
3. 在init方法中給子控件設置frame, 但是self的frame是沒有值的
4. 只要是自定義的控件,那么必須得在layoutSubvies中賦值
2.initWithFrame的使用(介意以后自定義控件的時候去實現initWithFrame的方法)盡量別使用init方法
在initWithFrame方法中初始化子控件(不管外界是使用init 還是initWithFrame 都會調用initWithFrame 方法)
property的使用策略
strong 一般是使用在OC對象上(也可以使用在UI控件上(會有問題的))
NSSArray NSDictionary 模型...
weak 一般是使用在UI控件上 也可以使用在OC對象(也是有問題的)
UITextFeild UIButton.....
copy 一般使用在NSString Block
assign 一般是使用基本數據類型上, 枚舉 結構體
思路
1. 創建一個類 自定義的控件什么樣的控件(就直接繼承什么樣的類)
自定義一個按鈕 那么繼承自UIButton
2. 在initWithFrame 中初始化子控件做一次性的操作
3. layoutSubvies 中設置子控件的frame
4. 暴露一個模型屬性給外界傳值(傳值的方法有很多 想到什么就使用什么方式)
重寫init方法的使用和注意
一定要調用super的init方法:因為初始化父類中會聲明一些成員變量和其他屬性
就是調用super的init方法 最后返回的就是一個id也就是self
有時候調用[super init]方法返回的不一定是一個self,但是為了保證它返回的是一個self就要進行一個賦值操作;
注意:調用super初始化完畢 就一定要賦值給self
返回一個self意思是:返回一個已經初始化完畢的一個對象
構造方法的注意點:
先調用父類的構造方法[super init];
再進行子類內部成員變量的初始化
*********************筆記***********************
plist root : 選擇的類型是神馬(NSArray)樣的 返回的就是神馬(NSArray)(需要使用神馬(NSArray)接收)
步驟1. 獲取plist文件的全路徑
2. 根據路徑加載plist中所有數據-
模型:(就是把字典里面的數據通過創建類來轉化成模型,便于自己使用)
- 使用一個臨時數組裝從plist 中加載的數組(裝的都是字典)
- 遍歷臨時數組, 取出每一個字典
- 將字典賦值給模型
- 將模型存放到數組(可變數組)中
plist 用來存儲一些經常變動的數據,或者多處需要使用的
模型 將字典轉換成可讀性比較高的代碼
而且不容易出錯-
類前綴
ios
ns(next step)stringShopModel
ShopModel包 java
com.biz.xj.ShopModel
-
instancetype && id
- id 任意對象 可以使用任何對象接收 沒有任何警告和提示
- instancetype 會檢測你的真實返回類型 , 那么如果類型不匹配直接警告
-
layoutSubvies 布局內部的自控件
只要當前的view的frame發生改變就會調用這個方法(只要一改變子控件的位置,它就會自動調用這個方法)
view一初始化完也會調用這個方法,嘗試著給自己的子控件賦值步驟1. 初始化自定義的view (只是調用init方法)
2. 設置frame
3. 在init方法中給子控件設置frame, 但是self的frame是沒有值的
4. 只要是自定義的控件,那么必須得在layoutSubvies中賦值 注意:(最好使用initWithFrame系統提供的這個方法)(initWithFrame方法中初始化子控件(不管外界是使用init 還是initWithFrame 都會調用initWithFrame方法))
-
property的使用策略
strong 一般是使用在OC對象上 (也可以使用在UI控件上(會有問題的))
NSSArray NSDictionary 模型...
weak 一般是使用在UI控件上 也可以使用在OC對象(也是有問題的)
UITextFeild UIButton.....
copy 一般使用在NSString Block
assign 一般是使用基本數據類型上, 枚舉 結構體 -
自定義控件設置數據
- tag 給自己的子控件添加一個tag,在控制器立獲取tag對應的子控件賦值
- 使用方法
- 使用屬性
- 控件暴露在.h文件
- 使用模型屬性
- Block (不做沒關系)
- 代理
- 思路
- 創建一個類 自定義的控件什么樣的控件(就直接繼承什么樣的類)
自定義一個按鈕 那么繼承自UIButton - 在initWithFrame 中初始化子控件 做一次性的操作
- layoutSubvies 中設置子控件的frame
- 暴露一個模型屬性給外界傳值(傳值的方法有很多 想到什么就使用什么方式)
- 創建一個類 自定義的控件什么樣的控件(就直接繼承什么樣的類)
*********************總結***********************
*********************NO4***********************
plist root : 選擇的類型是神馬(NSArray)樣的 返回的就是神馬(NSArray)(需要使用神馬(NSArray)接收)
步驟1. 獲取plist文件的全路徑
2. 根據路徑加載plist中所有數據-
模型:
- 使用一個臨時數組裝從plist 中加載的數組(裝的都是字典)
- 遍歷臨時數組, 取出每一個字典
- 將字典賦值給模型
- 將模型存放到數組(可變數組)中
plist 用來存儲一些經常變動的數據,或者多處需要使用的
模型 將字典轉換成可讀性比較高的代碼
而且不容易出錯-
類前綴
ios
ns(next step)stringShopModel
ShopModel包 java
com.biz.xj.ShopModel
-
instancetype && id
- id 任意對象 可以使用任何對象接收 沒有任何警告和提示
- instancetype 會檢測你的真實返回類型 , 那么如果類型不匹配直接警告
-
layoutSubvies 布局內部的自控件
只要當前的view的frame發生改變就會調用這個方法
view一初始化完也會調用這個方法,嘗試著給自己的子控件賦值步驟1. 初始化自定義的view (只是調用init方法)
2. 設置frame
3. 在init方法中給子控件設置frame, 但是self的frame是沒有值的
4. 只要是自定義的控件,那么必須得在layoutSubvies中賦值 在initWithFrame方法中初始化子控件(不管外界是使用init 還是initWithFrame 都會調用initWithFrame 方法)
在layoutSubvies 中給子控件設置frame
-
property的使用策略
strong 一般是使用在OC對象上 (也可以使用在UI控件上(會有問題的))
NSSArray NSDictionary 模型...
weak 一般是使用在UI控件上 也可以使用在OC對象(也是有問題的)
UITextFeild UIButton.....
copy 一般使用在NSString Block
assign 一般是使用基本數據類型上, 枚舉 結構體 -
自定義控件設置數據
- tag 給自己的子控件添加一個tag
在控制器立獲取tag對應的子控件賦值 - 使用方法
- 使用屬性
- 控件暴露在.h文件
- 使用模型屬性
- Block (不做沒關系)
- 代理
- tag 給自己的子控件添加一個tag
- 思路
- 創建一個類 自定義的控件什么樣的控件(就直接繼承什么樣的類)
自定義一個按鈕 那么繼承自UIButton - 在initWithFrame 中初始化子控件 做一次性的操作
- layoutSubvies 中設置子控件的frame
- 暴露一個模型屬性給外界傳值(傳值的方法有很多 想到什么就使用什么方式)
- 創建一個類 自定義的控件什么樣的控件(就直接繼承什么樣的類)
*********************總結***********************
*********************NO4***********************
-
總結
plist: 創建方式
加載 mianbundle中查找路徑
根據 root 接收一個數組或者字典類型
NSArray(NSDictionary) array(dictionary)WithContentOfFile:懶加載
1. 用到的時候再加載
2. 一般是寫在get方法中
3. 只要你去使用,那么肯定是調用get方法layoutSubviews
1. 一般都是設置子控件的frame
2. 只要父控件的frame發生改變就會調用
3. 在initWithFrame之后也會默認調用一次這個方法(嘗試著給子控件賦值)封裝view
1. 在initWithFrame中初始化子控件,并且做一次性操作
2. 在layoutSubviews 中給子控件frame賦值
3. 提供一個模型屬性供外界賦值
4. 在模型屬性的set方法中給子控件賦值(參數)封裝的好處
1. 任意在任何項目中使用
2. 改變數據不會影響控制器
3. 改變內部的空間也不會影響到控制器 -
MVC
m model 模型 數據層
v view 視圖(自定義控件)表示層
c controller 管理層(控制器)- 控制器創建視圖(view)
- 控制器創建模型 (控制器要顯示什么樣的數據應該是控制器決定)
- 控制器負責將模型數據賦值給視圖
// ------------------------以上是代碼封裝-------------------------
xib
創建 new file - > 選擇user interface - > view (empty)
加載 使用mainbundle加載
nsbundle mainbundle]loadNibName:(xib名字) nil nil
[UINib nibWithName:xib名字 nil nil]
nib對象 instantiateWithOwner nil nil
mianbundle 如果mainbundle 只有是參數 那么就可以直接傳nil-
自定義控件
- 創建一個xib
- 往xib中添加子控件
- 修改xib的類型
- 提供一個類方法
在類方法中直接返回從mainbundle中加載的控件數組,拿到最后一個
xib 一個xib數組中一般情況下只有一個控件
直接返回 - 提供一個模型屬性
在set方法中給子控件賦值
- 在通過nib 加載view的話 那么只會調用 initWithCoder awakeFromNib
通過代碼的方法我們必須使用initWithFrame那么就會調用 init/ initWithFrame
其實很重要的
只要是生命周期方法 都是很重要- init 初始化子控件,做一些一次性的操作
- initWithFrame 初始化子控件,做一次性操作. 調用了init也會調用這個方法
一般情況使用代碼自定義控件那么必須得這里初始化子控件 - initWithCoder 在子控件加載完畢之前可以做的操作,
比如 在子控件加載玩之前,需要再添加一個控件
不能給子控件賦值 因為子控件沒有值(空的) - awakeFromNib 子控件加載完畢之后需要做的操作
比如, 給子控件賦值,設置frame
http://www.easyicon.net/iconsearch 圖標大全
***************************NO5******************************
***************************NO5******************************
-
hud
江湖人稱為: 蒙版/遮蓋/hud
UIAlertView
UIAlertView *alert = [UIAlertView alloc]initWithTitle:<#(NSString *)#> message:<#(NSString *)#> delegate:<#(id)#> cancelButtonTitle:<#(NSString *)#> otherButtonTitles:<#(NSString *), ...#>, nil;[alert show];
hidden 隱藏控件 YES 隱藏 NO 不隱藏(是否顯示或者不顯示)
alpha 0.0完全透明 1.0 沒有透明度(別搞反了,0.0是完全透明)
-
漸變動畫
幀動畫 一幀一幀的播放動畫(一張一張圖片的切換)
漸變動畫 (alpha 0.0 ~ 1.0) hidden (yes NO)
frame x y width height
0
1
2
...
10
20
...
180
190
1). 頭尾式
開始動畫
[UIView beginAnimations:nil context:nil];
動畫時間
[UIView setAnimationDuration:2.0f];
self.hudLabel.alpha = 1.0;
self.hudLabel.text = @"感覺滿滿的";
提交動畫
[UIView commitAnimations];2). block 式 [UIView animateWithDuration:2.0f animations:^{ 需要執行的代碼 self.hudLabel.alpha = 1.0; self.hudLabel.text = @"感覺滿滿的"; 延遲 4 s 調用 self 的 hideHud方法 [self performSelector:@selector(hideHud) withObject:nil afterDelay:4.0]; }]; 3) block 式 "帶完成的block" [UIView animateWithDuration:2.0f animations:^{ 需要執行的代碼 self.hudLabel.alpha = 1.0; self.hudLabel.text = @"感覺滿滿的"; } completion:^(BOOL finished) { [UIView animateWithDuration:2.0f animations:^{ 需要執行的代碼 self.hudLabel.alpha = 0.0f; }]; }]; 4). block 式 "帶完成的block 延遲的時間" [UIView animateWithDuration:1.0f animations:^{ 需要執行的代碼 self.hudLabel.alpha = 1.0f; } completion:^(BOOL finished) { 延遲十秒 執行動畫的代碼 執行時間 是 2.0f [UIView animateWithDuration:1.0f delay:1.0f options:kNilOptions animations:^{ 需要執行的代碼 self.hudLabel.alpha = 0.0f; } completion:^(BOOL finished) { }]; }];
-
按鈕的內部結構
圖片 和 標題 間距
self.titleEdgeInsets; 改變標題在按鈕中的位置
self.imageEdgeInsets 改變圖片在按鈕中的位置
self.contentEdgeInsets 改變按鈕中所有內容的位置
設置內間距
圖片 和 標題 位置布局
直接影響按鈕內部的子控件
缺陷 不知道先調用的是哪個方法(不推薦使用)
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
self.titleH = contentRect.size.height * 0.4;
return CGRectMake(0, 0, contentRect.size.width,self.titleH);
}- (CGRect)imageRectForContentRect:(CGRect)contentRect { return CGRectMake(0, contentRect.size.height * 0.4, contentRect.size.width, contentRect.size.height * 0.6); } 一般情況下 都是使用layoutSubviews 布局子控件 layoutSubviews 準確性??高
-
圖片的拉伸的三種方式:
http://blog.csdn.net/q199109106q/article/details/8615661"默認是平鋪的方式"
UIImage *resizeImg = [image resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];"需要選擇拉伸或者平鋪的模式"
UIImage *resizeImg = [image resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10) resizingMode:UIImageResizingModeTile];// 系統會根據你傳入的左邊的寬度 算出右邊的寬度
// 1 = width - leftCapWidth - right
// 系統會根據你傳入的頂部的高度算出底部的高度
// 1 = height - topCapWidth - bottom
// 拉伸的是1x1 的區域
UIImage *resizeImg = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height *0.5]; -
copy
- 深拷貝 對象拷貝 產生一個新對象
- 淺拷貝 指針拷貝 指向同一個地址
- strong / copy
strong 兩個會跟著發生改變
copy 拷貝一個副本,改變副本不會影響源文件, 改變源文件不會影響到副本 - property copy 在set方法中寫 _str = [str copy];
- 調用copy的時候, 返回的是一個不可變對象
- 調用mutableCopy 返回一個可變對象
- kvc key value coding
賦值
setValue:forKey 只能給當前對象的屬性賦值
setValue: forKeyPath: 可以給當前對象的屬性賦值 還能當前對象的屬性的屬性賦值
setValuesForKeysWithDictionary 傳第一個字典給自己的所有屬性賦值 必須屬性名字和字典中key一致
forUndefinedKey 這個方法當找不到這個某個key就會調用 系統自己調用取值
valueForKey 獲取當前對象的屬性的值
valueForKeyPath 獲取當前對象的屬性的屬性的....值 也能獲取當前對象的屬性的值
- kvo key value observer
添加監聽者
監聽屬性值的改變
self監聽 p對象的 name這個屬性發生改變,
只要這個屬性發生改變 系統調用下面的監聽方法
[p addObserver:self forKeyPath:@"sex" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"他是傻逼"];移除
只要監聽完之后就可以移除
[p removeObserver:self forKeyPath:@"sex"];-
重寫監聽方法
-
(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"keypath =%@,object = %@,change = %@,context = %@",keyPath,object,change,context);NSString *str = change[@"new"]; if ([str isEqualToString:@"xiaojian"]) { NSLog(@"-=----%@",context); }
}
-
執行動畫 2秒以后執行這里的代碼
[UIView animateWithDuration:2.0f animations:^{
需要執行動畫的代碼
self.hud.alpha = 0.5f;
} completion:^(BOOL finished) {
動畫執行完畢的時候調用
需要動畫結束操作的代碼
animateWithDuration : 時間
delay : 延遲
options : 動畫的選項
animations : 需要執行的動畫代碼
completion : 動畫完成
延遲 2.0s 后執行 隱藏hud的動畫,動畫執行時間為1.0s
[UIView animateWithDuration:1.0f delay:2.0f options:kNilOptions animations:^{
self.hud.alpha = 0.0f;
} completion:nil];
當點擊self.view的時候就會調用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
打印內部的子控件
NSLog(@"-----%@",self.myBtn.subviews);
}