A.从ViewController分离View

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

 
B.思路
使用xib封装自定义view的步骤:
1.新建一个继承UIView的自定义view,这里的名字是“AppView”,用来封装独立控件组
每个AppView封装了如下图的控件组
 
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.
 
b.
 
c.
 
2.设置xib的class (默认是UIView) 为新建的”AppView"
 
 
3.在新建的UIView中编写View的数据加载逻辑
(1)在”AppView.h”中创建Model成员
1 // 在Controller和View之间传输的Model数据
2 @property(nonatomic, strong) App *appData;
 
(2)连接控件和”AppView",创建私有控件成员
 
(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信息到总view
11 [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 @end
12
13 @implementation AppView
14
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.加载Model
33 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
 

[iOS基础控件 - 4.4] 进一步封装"APP列表”,初见MVC模式的更多相关文章

  1. [iOS基础控件 - 6.9.3] QQ好友列表Demo TableView

    A.需求 1.使用plist数据,展示类似QQ好友列表的分组.组内成员显示缩进功能 2.组名使用Header,展示箭头图标.组名.组内人数和上线人数 3.点击组名,伸展.缩回好友组   code so ...

  2. [iOS基础控件 - 5.5] 代理设计模式 (基于”APP列表"练习)

    A.概述      在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果.功能      1.按钮点击后,显示为“已下载”,并且不 ...

  3. iOS 基础控件(下)

    上篇介绍了UIButton.UILabel.UIImageView和UITextField,这篇就简短一点介绍UIScrollView和UIAlertView. UIScrollView 顾名思义也知 ...

  4. [iOS基础控件 - 7.0] UIWebView

    A.基本使用 1.概念 iOS内置的浏览器控件 Safari浏览器就是通过UIWebView实现的   2.用途:制作简易浏览器 (1)基本请求 创建请求 加载请求 (2)代理监听webView加载, ...

  5. [iOS基础控件 - 6.11.3] 私人通讯录Demo 控制器的数据传递、存储

    A.需求 1.搭建一个"私人通讯录"Demo 2.模拟登陆界面 账号 密码 记住密码开关 自动登陆开关 登陆按钮 3.退出注销 4.增删改查 5.恢复数据(取消修改)   这个代码 ...

  6. [iOS基础控件 - 6.10.2] PickerView 自定义row内容 国家选择Demo

    A.需求 1.自定义一个UIView和xib,包含国家名和国旗显示 2.学习row的重用   B.实现步骤 1.准备plist文件和国旗图片     2.创建模型 // // Flag.h // Co ...

  7. [iOS基础控件 - 6.9] 聊天界面Demo

    A.需求 做出一个类似于QQ.微信的聊天界面 1.每个cell包含发送时间.发送人(头像).发送信息 2.使用对方头像放在左边,我方头像在右边 3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话 ...

  8. [iOS基础控件 - 6.7] 微博展示 使用代码自定义TableCell(动态尺寸)

    A.需求 1.类似于微博内容的展示 2.头像 3.名字 4.会员标志 5.内容 6.分割线 7.配图(可选,可有可无)   code source: https://github.com/hellov ...

  9. [iOS基础控件 - 6.6] 展示团购数据 自定义TableViewCell

    A.需求 1.头部广告 2.自定义cell:含有图片.名称.购买数量.价格 3.使用xib设计自定义cell,自定义cell继承自UITableViewCell 4.尾部“加载更多按钮”,以及其被点击 ...

随机推荐

  1. OSharp框架总体设计

    OSharp框架解说系列(1):总体设计 〇.前言 哈,距离前一个系列<MVC实用构架设计>的烂尾篇(2013年9月1日)已经跨了两个年头了,今天是2015年1月9日,日期已经相映,让我们 ...

  2. IOS 系统API---NSJSONSerialization四个枚举什么意思

    IOS 系统API---NSJSONSerialization四个枚举什么意思 NSJSONReadingMutableContainers:返回可变容器,NSMutableDictionary或NS ...

  3. java中存在的内存泄漏

    大家都知道JAVA有着自己的优点---垃圾回收器的机制,这个开发人员带来了很大的方便,不用我们编程人员去 控制内存回收等问题,有效的解决了内存泄露的问题,不至于导致系统因内存问题崩溃.为了精确的回收内 ...

  4. SaaS系列介绍之八: SaaS的运营模式

    1 引言 软件的核心是它为用户解决领域相关问题的能力.               ________Eric Evans,<领域驱动设计> 传统的软件生命周期中,软件的维护占整个过程的70 ...

  5. iOS开发--绘图教程

    本文是<Programming iOS5>中Drawing一章的翻译,考虑到主题完整性,翻译版本中加入了一些书中未涉及到的内容.希望本文能够对你有所帮助. 本文由海水的味道翻译整理,转载请 ...

  6. A过的题目

    1.TreeMap和TreeSet类:A - Language of FatMouse ZOJ1109B - For Fans of Statistics URAL 1613 C - Hardwood ...

  7. No ongoing transaction. Did you forget to call multi?

    2016-10-21 14:41:47,551 [ERROR] [http-nio-8032-exec-2] TransactionSynchronizationUtils:171 - Transac ...

  8. bzoj1426

    偷个懒,转自hzwer [“这种煞笔题怎么总有人问”,被吧主D了... 用f[i]表示已经拥有了i张邮票,则期望还需要购买的邮票数 则f[n]=0 f[i]=f[i]*(i/n)+f[i+1]*((n ...

  9. 读取Excel任务列表并显示在Outlook日历上

    前几天,公司发了一个任务安排,时间不固定,但要求准时到,为了给自己加一个提醒,也为了回顾一下以前的技术,特做了一个Demo. 读取Excel就不多说了,代码很简单,但支持老版本Excel和的版本Exc ...

  10. [swustoj 856] Huge Tree

    Huge Tree(0856) 问题描述 There are N trees in a forest. At first, each tree contains only one node as it ...