zoukankan      html  css  js  c++  java
  • 【iOS开发-48】九宫格布局案例:自己主动布局、字典转模型运用、id和instancetype差别、xib反复视图运用及与nib关系

    本次九宫格案例:


    (1)导入app.plist和各种图片素材,方便兴许开发。实际开发中,也是如此。


    (2)把plist中数组导入进来。

    ——由于本案例中app.plist终于是一个数组,数组里面是字典。所以我们须要一个数组类型来接受这个plist文件。

    ——我们利用之前掌握的在变量的getter中进行延迟载入数据。

    #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 = "U5929U5929U9177U8dd1";
        },
            {
            icon = "icon_01";
            name = "U5168U6c11U98deU673aU5927U6218";
        },
      ……


    icon后面就是icon的名称,name后面也是name的名称,仅仅只是中文被转换成了Unicode形式,一个汉字就是一个U****。

    (3)九宫格计算

    ——关键在于利用 / 和 % 运算得到元素所在的行和列,注意%符号运算前后不能有CGFloat,都换成int类型较好。

    ——CGFloat事实上就是float和double的集合。全部用float和double的地方差点儿都能够用CGFloat。会依据当前系统自己主动解析,假设是32位系统,则用float,假设是64位系统,则解析成double。

    - (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.
    }

    (4)往每一个appView里面加入一个UIImageView、UIlabel和UIButton。直接在for循环中加入,即创建UIView *appView的时候顺便把它里面的东西也创建了。

    ——当中,UIImageView里的图片用到取得图片的名称,这个能够存放在plist里面,我们把_arr1里相应的字典取出来使用就可以。

    ——重点是,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];
        }

    (5)最重要的:字典转模型

    使用字典的坏处:须要用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

    在JiuGongGe.m中实现(注意写法,记忆):

    #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

    事实上,我们的小标题是“字典转模型”,也就是说仅仅是把字典转换成模型(对象),原先字典存放在数组中的,然后通过数组[index]一个个调用字典,如今模型(对象)依旧存放在数组中。所以我们须要对数组的那个getter方法进行改进:(注意:须要在ViewController.m中#import "JiuGongGe.h",由于要实例化对象)

    -(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;
    }

    在ViewDidLoad的那个for循环中,用到的地方都能够用对象.属性来调用数据了:

            //依据索引拿到每一个对象,此处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];
        }

    (9)xib文件和nib文件是什么关系?

    ——xib文件是我们开发人员在开发的时候看到的东西;

    ——而执行在用户手机里时,xib文件会被转化为nib文件。

    我们能够在iOS Simulator产生的沙盒中查看。

    ——找不到资源库路径,直接用NSLog(@"%@",[NSBundle mainBundle);把路径打印出来。

    查找发现,这个资源库中确实有个ourXib.nib文件,xib文件确实转化成nib文件了。



  • 相关阅读:
    git 命令速查及使用
    Centos6.5 LAMP环境源码包安装与配置,附安装包百度网盘地址 (转做笔记)
    不再为Apache进程淤积、耗尽内存而困扰((转))
    centos6.5 安装linux 环境
    window 配置wnmp(转下整理 ,全)
    mac下安装 xampp 无法启动apache (转,留用)
    Git命令行(转用于学习和记录)
    apache 局域网访问
    华为云GaussDB(for opengauss)如何绑定公网,实现putty的远程访问gaussdb数据库。
    Day9 打卡acwing.429 奖学金
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4281925.html
Copyright © 2011-2022 走看看