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

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 ==> iOS ==> Source ==> Cocoa Touch Class
创建声明文件”AppView.h”和“AppView.m”
a.
b.
c.
2.设置xib的class (默认是UIView) 为新建的”AppView"
3.在新建的UIView中编写View的数据加载逻辑
(1)在”AppView.h”中创建Model成员
// 在Controller和View之间传输的Model数据
@property(nonatomic, strong) App *appData;
(2)连接控件和”AppView",创建私有控件成员
(3)在”AppView.m”中解析加载数据
- (void)setAppData:(App *)appData {
_appData = appData;
// 1.设置图片
self.iconView.image = [UIImage imageNamed:appData.icon];
// 2.设置名字
self.nameLabel.text = appData.name;
}
(4)自定义构造方法
AppView.h:
// 自定义将Model数据加载到View的构造方法
- (instancetype) initWithApp:(App *) appData;
// 自定义构造的类方法
+ (instancetype) appViewWithApp:(App *) appData;
// 返回一个不带Model数据的类构造方法
+ (instancetype) appView;
AppView.m:
// 自定义将Model数据加载到View的构造方法
- (instancetype) initWithApp:(App *) appData {
// 1.从NIB取得控件
UINib *nib = [UINib nibWithNibName:@"app" bundle:[NSBundle mainBundle]];
NSArray *viewArray = [nib instantiateWithOwner:nil options:nil];
AppView *appView = [viewArray lastObject];
// 2.加载Model
    appView.appData = appData;
return appView;
}
// 自定义构造的类方法
+ (instancetype) appViewWithApp:(App *) appData {
return [[self alloc] initWithApp:appData];
}
// 返回一个不带Model数据的类构造方法
+ (instancetype) appView {
return [self appViewWithApp:nil];
}
(5)在Controller中创建”AppView”并加载数据
// 1.创建View
AppView *appView = [AppView appViewWithApp:appData];
// 2.定义每个app的位置、尺寸
CGFloat appX = marginX + column * (marginX + APP_WIDTH);
CGFloat appY = marginY + row * (marginY + APP_HEIGHT);
        appView.frame = CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT);
// 3.加入此app信息到总view
        [self.view addSubview:appView];
主要代码
ViewController.m
#import "ViewController.h"
#import "App.h"
#import "AppView.h"
#define ICON_KEY @"icon"
#define NAME_KEY @"name"
#define APP_WIDTH 85
#define APP_HEIGHT 90
#define MARGIN_HEAD 20
#define ICON_WIDTH 50
#define ICON_HEIGHT 50
#define NAME_WIDTH APP_WIDTH
#define NAME_HEIGHT 20
#define DOWNLOAD_WIDTH (APP_WIDTH - 20)
#define DOWNLOAD_HEIGHT 20
@interface ViewController ()
/** 存放应用信息 */
@property(nonatomic, strong) NSArray *apps; // 应用列表
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    [self loadApps];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark 取得应用列表
- (NSArray *) apps {
if (nil == _apps) {
// 1.获得plist的全路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
// 2.加载数据
NSArray *dictArray  = [NSArray arrayWithContentsOfFile:path];
// 3.将dictArray里面的所有字典转成模型,放到新数组中
NSMutableArray *appArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
// 3.1创建模型对象
App *app = [App appWithDictionary:dict];
// 3.2 添加到app数组中
            [appArray addObject:app];
        }
_apps = appArray;
    }
return _apps;
}
#pragma mark 加载全部应用列表
- (void) loadApps {
int appColumnCount = [self appColumnCount];
int appRowCount = [self appRowCount];
CGFloat marginX = (self.view.frame.size.width - APP_WIDTH * appColumnCount) / (appColumnCount + 1);
CGFloat marginY = (self.view.frame.size.height - APP_HEIGHT * appRowCount) / (appRowCount + 1) + MARGIN_HEAD;
int column = 0;
int row = 0;
for (int index=0; index<self.apps.count; index++) {
App *appData = self.apps[index];
// 1.创建View
AppView *appView = [AppView appViewWithApp:appData];
// 2.定义每个app的位置、尺寸
CGFloat appX = marginX + column * (marginX + APP_WIDTH);
CGFloat appY = marginY + row * (marginY + APP_HEIGHT);
        appView.frame = CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT);
// 3.加入此app信息到总view
        [self.view addSubview:appView];
        column++;
if (column == appColumnCount) {
            column = 0;
            row++;
        }
    }
}
#pragma mark 计算列数
- (int) appColumnCount {
int count = 0;
    count = self.view.frame.size.width / APP_WIDTH;
if ((int)self.view.frame.size.width % (int)APP_WIDTH == 0) {
        count--;
    }
return count;
}
#pragma mark 计算行数
- (int) appRowCount {
int count = 0;
    count = (self.view.frame.size.height - MARGIN_HEAD) / APP_HEIGHT;
if ((int)(self.view.frame.size.height - MARGIN_HEAD) % (int)APP_HEIGHT == 0) {
        count--;
    }
return count;
}
@end
AppView.m:
#import "AppView.h"
#import "App.h"
// 封装私有属性
@interface AppView()
// 封装View中的控件,只允许自己访问
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@end
@implementation AppView
- (void)setAppData:(App *)appData {
// 1.赋值Medel成员
_appData = appData;
// 2.设置图片
self.iconView.image = [UIImage imageNamed:appData.icon];
// 3.设置名字
self.nameLabel.text = appData.name;
}
// 自定义将Model数据加载到View的构造方法
- (instancetype) initWithApp:(App *) appData {
// 1.从NIB取得控件
UINib *nib = [UINib nibWithNibName:@"app" bundle:[NSBundle mainBundle]];
NSArray *viewArray = [nib instantiateWithOwner:nil options:nil];
AppView *appView = [viewArray lastObject];
// 2.加载Model
    appView.appData = appData;
return appView;
}
// 自定义构造的类方法
+ (instancetype) appViewWithApp:(App *) appData {
return [[self alloc] initWithApp:appData];
}
// 返回一个不带Model数据的类构造方法
+ (instancetype) appView {
return [self appViewWithApp:nil];
}
@end
App.m
#import "App.h"
#define ICON_KEY @"icon"
#define NAME_KEY @"name"
@implementation App
- (instancetype) initWithDictionary:(NSDictionary *) dictionary {
if (self = [super init]) {
self.name = dictionary[NAME_KEY];
self.icon = dictionary[ICON_KEY];
    }
return self;
}
+ (instancetype) appWithDictionary:(NSDictionary *) dictionary {
// 使用self代表类名代替真实类名,防止子类调用出错
return [[self alloc] initWithDictionary:dictionary];
}
@end
时间: 2024-08-07 00:14:16

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

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

A.需求 1.使用plist数据,展示类似QQ好友列表的分组.组内成员显示缩进功能 2.组名使用Header,展示箭头图标.组名.组内人数和上线人数 3.点击组名,伸展.缩回好友组 B.实现步骤 1.编写MVC结构 (1)根据plist文件结构,编写model,使用嵌套型 1 // 2 // FriendGroup.h 3 // FriendsList 4 // 5 // Created by hellovoidworld on 14/12/12. 6 // Copyright (c) 2014

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

A.概述 在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果.功能 1.按钮点击后,显示为“已下载”,并且不可以再按 2.在屏幕中间弹出一个消息框,通知消息“xx已经被安装”,慢慢消失 3.消息框样式为圆角半透明 B.不使用代理模式,使用app空间组和主View之间的父子View关系 1.在主View中创建一个消息框 主View控制器:ViewController.m 1 // 创建下载成功消息框 2 CGFloat labelWid

iOS基础控件UINavigationController中的传值

iOS基础控件UINavigationController中的传值,代理传值,正向传值,反向传值 #import <UIKit/UIKit.h> //声明一个协议 @protocol SendValue<NSObject> //定义一个方法 - (void)sendBtnTitle:(NSString *)title; @end @interface FirstViewController : UIViewController // 定义代理 @property (nonatomi

ios基础控件之开关按钮(UISwitch)

UISwitch控件是iOS开发的基础控件,是非常简单的一个控件,因为它的方法比较少.UISwitch继承于UIControl基类,因此可以当成活动控件使用. 注意:开关状态通过它的on属性进行读取,该属性是一个BOOL属性 创建: UISwitch* mySwitch = [[ UISwitch alloc]initWithFrame:CGRectMake(0.150.0f,100.0f,0.0f,0.0f)]; 可能你会疑问为什么它的大小都设置为0?没错,它的大小你设置是无效的,系统会为你分

ios基础控件 之展示团购数据 UITableViewCell &lt;代理,xib封装view&gt;

1.主控制器: 1 // 2 // ViewController.m 3 // GroupPurchase 4 // 5 // Created by hellovoidworld on 14/12/3. 6 // Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import "GroupPurchase.h" 11 #im

iOS 基础控件(下)

上篇介绍了UIButton.UILabel.UIImageView和UITextField,这篇就简短一点介绍UIScrollView和UIAlertView. UIScrollView 顾名思义也知道这个是和滚动相关的控件,在Android开发时遇到过ScrollView,当内容的尺寸超出了屏幕范围之后,用ScrollView则可以通过滚动的方式使得超出屏幕的那部分内容通过滚动的方式显示出来,在Android里面有水平的ScrollView和垂直的ScrollView,在iOS里面就只有一个S

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

A.需求 做出一个类似于QQ.微信的聊天界面 1.每个cell包含发送时间.发送人(头像).发送信息 2.使用对方头像放在左边,我方头像在右边 3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话框 4.隐藏相同的发送时间 5.底部功能按钮:语音按钮.消息输入框.表情按钮.附加按钮 6.响应键盘事件,呼出键盘.隐藏键盘时对上述的视图作出上移操作 7.键盘的发送事件处理 B.实现点 1.底层视图搭建 上部分聊天信息框:UITableView 下部分功能区:UIButton 信息输入框使用无边框

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

A.需求 1.搭建一个“私人通讯录”Demo 2.模拟登陆界面 账号 密码 记住密码开关 自动登陆开关 登陆按钮 3.退出注销 4.增删改查 5.恢复数据(取消修改) B.基本架构 1. 5个控制器 (1)导航控制器 NavigationController (2)登陆 UIViewController 输入账号密码 记住密码.自动登录开关 登陆跳转按钮 (3)联系人列表 TableViewController 注销功能 添加联系人跳转按钮 (4)添加联系人 UIView (5)查看.编辑 UI

[iOS基础控件 - 6.6.1] 展示团购数据代码[iOS基础控件 - 6.7] 微博展示 使用代码自定义TableCell(动态尺寸)

A.需求 1.类似于微博内容的展示 2.头像 3.名字 4.会员标志 5.内容 6.分割线 7.配图(可选,可有可无) B.思路.步骤 1.Controller:UITableViewController 改变控制器继承自UITableViewController,storyboard中也同时使用新的TableViewController,其TableView作为启动入口. 2.View:代码自定义cell 使用代码组装每个cell,动态改变控件的位置.尺寸 cell含有一个WeiboFrame