本次九宮格案例:數組
(1)導入app.plist和各類圖片素材,方便興許開發。實際開發中,也是如此。app
(2)把plist中數組導入進來。佈局
——因爲本案例中app.plist終因而一個數組,數組裏面是字典。因此咱們需要一個數組類型來接受這個plist文件。字體
——咱們利用以前掌握的在變量的getter中進行延遲載入數據。atom
#import "ViewController.h" @interface ViewController () @property(nonatomic,strong) NSArray *arr1; @end @implementation ViewController - (void)viewDidLoad { self.arr1; [super viewDidLoad]; } -(NSArray *)arr1{ if (_arr1==nil) { NSString *path=[[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; _arr1=[NSArray arrayWithContentsOfFile:path]; NSLog(@"%@",_arr1); } return _arr1; } @end輸出結果是:
{ icon = "icon_00"; name = "\U5929\U5929\U9177\U8dd1"; }, { icon = "icon_01"; name = "\U5168\U6c11\U98de\U673a\U5927\U6218"; }, ……
(3)九宮格計算spa
——關鍵在於利用 / 和 % 運算獲得元素所在的行和列,注意%符號運算先後不能有CGFloat,都換成int類型較好。指針
——CGFloat事實上就是float和double的集合。所有用float和double的地方差點兒都可以用CGFloat。會依據當前系統本身主動解析,假設是32位系統,則用float,假設是64位系統,則解析成double。code
- (void)viewDidLoad { //定義總列數、每個九宮格的寬高 int totalColumns=3; CGFloat appW=90; CGFloat appH=100; //定義水平和垂直方面的間距 CGFloat marginX=(self.view.frame.size.width-totalColumns*appW)/(totalColumns+1); CGFloat marginY=20; //依據arr1中數據數量來初始化並載入一個一個的UIVIew for (int index=0; index<self.arr1.count; index++) { //計算這個app在幾行幾列 int row=index/totalColumns; int col=index%totalColumns; //建立UIView UIView *appView=[[UIView alloc]init]; //依據一些計算,肯定不一樣UIView的位置 appView.frame=CGRectMake(marginX+col*(marginX+appW), 30+row*(marginY+appH), appW, appH); appView.backgroundColor=[UIColor redColor]; [self.view addSubview:appView]; } [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. }
——當中,UIImageView裏的圖片用到取得圖片的名稱,這個可以存放在plist裏面,咱們把_arr1裏相應的字典取出來使用就能夠。orm
——重點是,UIButton的字體大小沒法直接設置,而是用到UIbutton裏的子視圖titleLabel來設置。(因爲UIButton裏面事實上封裝了兩個子視圖控件,一個是裝文字的UILabel *titleLabel,一個裝圖片的UIImageView *imageView)對象
for (int index=0; index<self.arr1.count; index++) { //計算這個app在幾行幾列 int row=index/totalColumns; int col=index%totalColumns; //建立UIView UIView *appView=[[UIView alloc]init]; //依據一些計算,肯定不一樣UIView的位置 appView.frame=CGRectMake(marginX+col*(marginX+appW), 30+row*(marginY+appH), appW, appH); // appView.backgroundColor=[UIColor redColor]; [self.view addSubview:appView]; //依據索引拿到plist每個字典的數據 NSDictionary *appDic=_arr1[index]; //往appView裏添加子控件icon //依據字典拿到裏面的icon名稱 UIImageView *appIcon=[[UIImageView alloc]init]; CGFloat iconW=65; CGFloat iconH=65; CGFloat iconX=(appW-iconW)/2; CGFloat iconY=0; appIcon.frame=CGRectMake(iconX, iconY, iconW, iconH); appIcon.image=[UIImage imageNamed:appDic[@"icon"]]; [appView addSubview:appIcon]; //往appView裏添加子控件label UILabel *appLabel=[[UILabel alloc]init]; CGFloat labelW=appW; CGFloat labelH=20; CGFloat labelX=(appW-labelW)/2; CGFloat labelY=iconY+iconH; appLabel.frame=CGRectMake(labelX, labelY, labelW, labelH); appLabel.text=appDic[@"name"]; appLabel.textAlignment=NSTextAlignmentCenter; appLabel.font=[UIFont systemFontOfSize:14]; [appView addSubview:appLabel]; //往appView裏添加子控件button UIButton *appBtn=[[UIButton alloc]init]; CGFloat btnW=65; CGFloat btnH=26; CGFloat btnX=(appW-btnW)/2; CGFloat btnY=labelY+labelH; appBtn.frame=CGRectMake(btnX, btnY, btnW, btnH); [appBtn setTitle:@"下載" forState:UIControlStateNormal]; appBtn.titleLabel.font=[UIFont systemFontOfSize:14]; [appBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal]; [appBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateNormal]; [appView addSubview:appBtn]; }
使用字典的壞處:需要用key值調取和設置數據,有時候會出錯,儘管可以用宏變量改進,但是更要命的寫錯了key值,沒有錯誤提示。
模型:嚴格叫作模型數據。核心就是咱們把字典當成一個對象,字典裏面的幾個數據,咱們分別轉換成對象的幾個屬性,咱們調用和設置數據的時候直接是「對象.屬性」就能夠。
因此,咱們需要建立一個類,這個專門用來存放數據,也就是常說的模型類。
本例中,建立一個JiuGongGe類,在.h中聲明2個變量,和2種初始化方法(規範都是有2種初始化方法,事實上核心是一種,另一種仍是經過第一種來實現的)。
#import <Foundation/Foundation.h> @interface JiuGongGe : NSObject @property(nonatomic,copy) NSString *name; @property(nonatomic,copy) NSString *icon; -(instancetype)initWithJiuGongGe:(NSDictionary *)dic; +(instancetype)jiuGongGeWith:(NSDictionary *)dic; @end
#import "JiuGongGe.h" @implementation JiuGongGe -(instancetype)initWithJiuGongGe:(NSDictionary *)dic{ if (self=[super init]) { self.name=dic[@"name"]; self.icon=dic[@"icon"]; } return self; } +(instancetype)jiuGongGeWith:(NSDictionary *)dic{ return [[JiuGongGe alloc]initWithJiuGongGe:dic]; } @end
-(NSArray *)arr1{ if (_arr1==nil) { NSString *path=[[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; NSArray *tmpArr=[NSArray arrayWithContentsOfFile:path]; NSMutableArray *muArr1=[[NSMutableArray alloc]init]; for (NSDictionary *dict in tmpArr) { JiuGongGe *jiugognge=[JiuGongGe jiuGongGeWith:dict]; [muArr1 addObject:jiugognge]; } _arr1=muArr1; } return _arr1; }
//依據索引拿到每個對象,此處appDic名稱未改,仍是用以前取字典的那個變量,看的不太習慣 JiuGongGe *appDic=_arr1[index]; //往appView裏添加子控件icon …… appIcon.image=[UIImage imageNamed:appDic.icon]; //往appView裏添加子控件label appLabel.text=appDic.name;
(6)jiuGongGeWith:(NSDictionary *)dic;初始化方法的改進
——裏面用到的類名,可以替換成self。因爲防止這個類有子類,假設子類調用jiuGongGeWith:(NSDictionary *)dic;時調用到父類的這種方法,裏面寫得名字仍是父類的名字,初始化結果是一個父類的對象,而不是子類的對象。因此用self,誰調用就初始化誰的對象。
(7)id類型和instancetype的說明
——instancetype和id同樣,都是萬能指針。
——iOS建議咱們使用instancetype取代id。雖然官方很是多init方法的返回值也是id。
——使用id的優勢就是,id是萬能指針,咱們不用操心它的返回值類型不匹配的問題。
——使用id的壞處:也正是因爲它是萬能指針,咱們可以用隨意指針接受這個返回值,比方NSString *str1=****,NSArray *arr1=****,這句代碼寫出來不會報錯。但是有可能不是咱們需要的返回值類型。
——使用instancetype的優勢是,假設咱們返回值是一個對象,那麼你用上面兩個隨意指針接受這個返回值,它會有warning警告,咱們用類對象JiuGongGe *jiugognge=***,就不會警告。
——instancetype僅僅能用在返回值類型上,不能像id同樣用在參數上。
(8)利用xib圖形化佈局下降代碼
xib和storyboard的差異在於,storyboard是描寫敘述整個程序界面的,而xib多用於局部反覆界面的描寫敘述。
比方本例中有12個應用,每個應用的視圖都是同樣的,可以用xib來實現,而後再把xib載入進來就能夠。
xib的建立(用empty):
在ourXib中佈局:
——給UIImageView和UILabel分別設置tag爲10和20,方便調用。
——拖動控件到界面中,改變大小時候,UIImageView需要把size設置成Freeform才幹調整大小。
ourXib設置好後,就可以調用:
——除了圖片以外的資源,都需要用[NSBundle mainBundle]來調用。
——調用xib文件的方法是mainBundle的loadNibNamed方法。
for (int index=0; index<self.arr1.count; index++) { //計算這個app在幾行幾列 int row=index/totalColumns; int col=index%totalColumns; //依據索引拿到每個對象 JiuGongGe *appDic=_arr1[index]; NSArray *xibArr=[[NSBundle mainBundle]loadNibNamed:@"ourXib" owner:nil options:nil]; UIView *xibView=[xibArr lastObject]; xibView.frame=CGRectMake(marginX+col*(marginX+appW), 30+row*(marginY+appH), appW, appH); UIImageView *imgView2=(UIImageView *)[xibView viewWithTag:10]; imgView2.image=[UIImage imageNamed:appDic.icon]; UILabel *label2=(UILabel *)[xibView viewWithTag:20]; label2.text=appDic.name; //加入到主view中 [self.view addSubview:xibView]; }
——xib文件是咱們開發人員在開發的時候看到的東西;
——而執行在用戶手機裏時,xib文件會被轉化爲nib文件。
咱們可以在iOS Simulator產生的沙盒中查看。
——找不到資源庫路徑,直接用NSLog(@"%@",[NSBundle mainBundle);把路徑打印出來。
查找發現,這個資源庫中確實有個ourXib.nib文件,xib文件確實轉化成nib文件了。