首页 > 学院 > 开发设计 > 正文

[iOS基础控件-4.4]进一步封装"APP列表”,初见MVC模式

2019-11-14 19:49:44
字体:
来源:转载
供稿:网友


A.从ViewController分离View

     之前的代码中,View的数据加载逻辑放在了总的ViewController中,增加了耦合性,应该对控制器ViewController隐藏数据加载到View的细节。
     封装View的创建逻辑
     封装View的数据加载逻辑到自定义的UIView中

 
B.思路
使用xib封装自定义view的步骤:
1.新建一个继承UIView的自定义view,这里的名字是“AppView”,用来封装独立控件组
每个AppView封装了如下图的控件组
Image(5)
 
2.新建一个xib文件来描述控件结构,就是上图的控件组
3.在Controller中使用AppView作为每个独立控件组的类型单位
4.将控件和View “AppView” 进行连线
5.View “AppView” 提供一个模型属性
6.重写模型属性的setter,解析模型数据
7.设置模型数据到控件中
8.自定义View “AppView”的构造方法,屏蔽读取xib文件的细节
 
其实这就是一种简单的MVC模式
Model: App.h, App.m
View: AppView.h, AppView.m
Controller: ViewController.h, ViewController.m
 
Controller连接了View和Model,取得数据后加载到Model,然后传给View进行解析并显示
 
 
C.实现
1.新建UIView类”AppView",继承自UIView
new file ==>
创建声明文件”AppView.h”和“AppView.m”
a.
Image(6)
 
b.
Image(7)
 
c.
Image(8)
 
2.设置xib的class (默认是UIView) 为新建的”AppView"
Image(9)
 
 
3.在新建的UIView中编写View的数据加载逻辑
(1)在”AppView.h”中创建Model成员
1 // 在Controller和View之间传输的Model数据2 @PRoperty(nonatomic, strong) App *appData;
 
(2)连接控件和”AppView",创建私有控件成员
Image(10)
 
(3)在”AppView.m”中解析加载数据
1 - (void)setAppData:(App *)appData {2     _appData = appData;3    4     // 1.设置图片5     self.iconView.image = [UIImage imageNamed:appData.icon];6     // 2.设置名字7     self.nameLabel.text = appData.name;8 }
 
(4)自定义构造方法
AppView.h:
1 // 自定义将Model数据加载到View的构造方法2 - (instancetype) initWithApp:(App *) appData;3 // 自定义构造的类方法4 + (instancetype) appViewWithApp:(App *) appData;5 // 返回一个不带Model数据的类构造方法6 + (instancetype) appView;
 
AppView.m:
 1 // 自定义将Model数据加载到View的构造方法 2 - (instancetype) initWithApp:(App *) appData { 3     // 1.从NIB取得控件 4     UINib *nib = [UINib nibWithNibName:@"app" bundle:[NSBundle mainBundle]]; 5     NSArray *viewArray = [nib instantiateWithOwner:nil options:nil]; 6     AppView *appView = [viewArray lastObject]; 7     8     // 2.加载Model 9     appView.appData = appData;10    11     return appView;12 }13 14 // 自定义构造的类方法15 + (instancetype) appViewWithApp:(App *) appData {16     return [[self alloc] initWithApp:appData];17 }18 19 // 返回一个不带Model数据的类构造方法20 + (instancetype) appView {21     return [self appViewWithApp:nil];22 }

 

 
(5)在Controller中创建”AppView”并加载数据
 1         // 1.创建View 2         AppView *appView = [AppView appViewWithApp:appData]; 3         4         // 2.定义每个app的位置、尺寸 5         CGFloat appX = marginX + column * (marginX + APP_WIDTH); 6         CGFloat appY = marginY + row * (marginY + APP_HEIGHT); 7         appView.frame = CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT); 8  9        10         // 3.加入此app信息到总view11         [self.view addSubview:appView];
 
 
主要代码
  1 ViewController.m  2 #import "ViewController.h"  3 #import "App.h"  4 #import "AppView.h"  5   6 #define ICON_KEY @"icon"  7 #define NAME_KEY @"name"  8 #define APP_WIDTH 85  9 #define APP_HEIGHT 90 10 #define MARGIN_HEAD 20 11 #define ICON_WIDTH 50 12 #define ICON_HEIGHT 50 13 #define NAME_WIDTH APP_WIDTH 14 #define NAME_HEIGHT 20 15 #define DOWNLOAD_WIDTH (APP_WIDTH - 20) 16 #define DOWNLOAD_HEIGHT 20 17  18 @interface ViewController () 19  20 /** 存放应用信息 */ 21 @property(nonatomic, strong) NSArray *apps; // 应用列表 22  23 @end 24  25 @implementation ViewController 26  27 - (void)viewDidLoad { 28     [super viewDidLoad]; 29     // Do any additional setup after loading the view, typically from a nib. 30     31     [self loadApps]; 32 } 33  34 - (void)didReceiveMemoryWarning { 35     [super didReceiveMemoryWarning]; 36     // Dispose of any resources that can be recreated. 37 } 38  39 #pragma mark 取得应用列表 40 - (NSArray *) apps { 41     if (nil == _apps) { 42         // 1.获得plist的全路径 43         NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil]; 44         45         // 2.加载数据 46         NSArray *dictArray  = [NSArray arrayWithContentsOfFile:path]; 47         48         // 3.将dictArray里面的所有字典转成模型,放到新数组中 49         NSMutableArray *appArray = [NSMutableArray array]; 50         for (NSDictionary *dict in dictArray) { 51             // 3.1创建模型对象 52             App *app = [App appWithDictionary:dict]; 53             54             // 3.2 添加到app数组中 55             [appArray addObject:app]; 56         } 57         58         _apps = appArray; 59     } 60  61     return _apps; 62 } 63  64 #pragma mark 加载全部应用列表 65 - (void) loadApps { 66     int appColumnCount = [self appColumnCount]; 67     int appRowCount = [self appRowCount]; 68     69     CGFloat marginX = (self.view.frame.size.width - APP_WIDTH * appColumnCount) / (appColumnCount + 1); 70     CGFloat marginY = (self.view.frame.size.height - APP_HEIGHT * appRowCount) / (appRowCount + 1) + MARGIN_HEAD; 71     72     int column = 0; 73     int row = 0; 74     for (int index=0; index<self.apps.count; index++) { 75         App *appData = self.apps[index]; 76  77         // 1.创建View 78         AppView *appView = [AppView appViewWithApp:appData]; 79         80         // 2.定义每个app的位置、尺寸 81         CGFloat appX = marginX + column * (marginX + APP_WIDTH); 82         CGFloat appY = marginY + row * (marginY + APP_HEIGHT); 83         appView.frame = CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT); 84  85         86         // 3.加入此app信息到总view 87         [self.view addSubview:appView]; 88         89         column++; 90         if (column == appColumnCount) { 91             column = 0; 92             row++; 93         } 94     } 95 } 96  97  98 #pragma mark 计算列数 99 - (int) appColumnCount {100     int count = 0;101     count = self.view.frame.size.width / APP_WIDTH;102    103     if ((int)self.view.frame.size.width % (int)APP_WIDTH == 0) {104         count--;105     }106    107     return count;108 }109 110 #pragma mark 计算行数111 - (int) appRowCount {112     int count = 0;113     count = (self.view.frame.size.height - MARGIN_HEAD) / APP_HEIGHT;114    115     if ((int)(self.view.frame.size.height - MARGIN_HEAD) % (int)APP_HEIGHT == 0) {116         count--;117     }118    119     return count;120 }121 122 @end

 

AppView.m:

 1 #import "AppView.h" 2 #import "App.h" 3  4 // 封装私有属性 5 @interface AppView() 6  7 // 封装View中的控件,只允许自己访问 8 @property (weak, nonatomic) IBOutlet UIImageView *iconView; 9 @property (weak, nonatomic) IBOutlet UILabel *nameLabel;10 11 @end12 13 @implementation AppView14 15 - (void)setAppData:(App *)appData {16     // 1.赋值Medel成员17     _appData = appData;18    19     // 2.设置图片20     self.iconView.image = [UIImage imageNamed:appData.icon];21     // 3.设置名字22     self.nameLabel.text = appData.name;23 }24 25 // 自定义将Model数据加载到View的构造方法26 - (instancetype) initWithApp:(App *) appData {27     // 1.从NIB取得控件28     UINib *nib = [UINib nibWithNibName:@"app" bundle:[NSBundle mainBundle]];29     NSArray *viewArray = [nib instantiateWithOwner:nil options:nil];30     AppView *appView = [viewArray lastObject];31    32     // 2.加载Model33     appView.appData = appData;34    35     return appView;36 }37 38 // 自定义构造的类方法39 + (instancetype) appViewWithApp:(App *) appData {40     return [[self alloc] initWithApp:appData];41 }42 43 // 返回一个不带Model数据的类构造方法44 + (instancetype) appView {45     return [self appViewWithApp:nil];46 }47 48 @end

 

App.m
 1 #import "App.h" 2  3 #define ICON_KEY @"icon" 4 #define NAME_KEY @"name" 5  6 @implementation App 7  8 - (instancetype) initWithDictionary:(NSDictionary *) dictionary { 9     if (self = [super init]) {10         self.name = dictionary[NAME_KEY];11         self.icon = dictionary[ICON_KEY];12     }13    14     return self;15 }16 17 18 + (instancetype) appWithDictionary:(NSDictionary *) dictionary {19     // 使用self代表类名代替真实类名,防止子类调用出错20     return [[self alloc] initWithDictionary:dictionary];21 }22 23 @end
 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表