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

  // 创建下载成功消息框
CGFloat labelWidth = ;
CGFloat labelHeight = ;
CGFloat labelX = (self.view.frame.size.width - labelWidth) / ;
CGFloat labelY = (self.view.frame.size.height - labelHeight) / ;
UILabel *successMsgLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelWidth, labelHeight)]; // 设置圆角矩形样式
successMsgLabel.layer.cornerRadius = 10.0;
successMsgLabel.layer.masksToBounds = YES; // 设置全透明隐藏
successMsgLabel.alpha = ; successMsgLabel.textColor = [UIColor whiteColor];
successMsgLabel.backgroundColor = [UIColor grayColor];
[successMsgLabel setTextAlignment:NSTextAlignmentCenter];
successMsgLabel.tag = ; [self.view addSubview:successMsgLabel];
 
2.直接在app空间组的控制器中操作消息框,加入到父控件(主View)
 
app控件组View:AppView.m
 // 点击下载按钮
- (IBAction)onDownloadButtonClick {
// 更改“下载”按钮样式
[self.downloadButton setTitle:@"已下载" forState:UIControlStateDisabled];
self.downloadButton.enabled = NO; // 拿到消息框
UILabel *successMsgLabel = [self.superview viewWithTag:];
successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", self.appData.name];
successMsgLabel.alpha = 0.7; // 使用动画
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:];
successMsgLabel.alpha = ;
[UIView commitAnimations];
}
 
缺点:view的父子关系规定了这两个view的层次关系,依赖性、耦合性太强,导致各个view都不能自由修改
 
C.不使用代理模式,在app控件组的view中将主View作为一个成员
1.在控件组AppView中创建主View的引用
控件组 AppView.h
 // 存储主View的引用
@property (nonatomic, weak) UIView *vcView;
 
2.在主View逐个加载控件组的时候,设置主View的引用
ViewController.m
  for (int index=; 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); // 设置每个app控件view的主view引用
appView.vcView = self.view; // 3.加入此app信息到总view
[self.view addSubview:appView]; column++;
if (column == appColumnCount) {
column = ;
row++;
}
 
3.控件组AppView使用主View引用代替父控件引用
AppView.m
 // 点击下载按钮
- (IBAction)onDownloadButtonClick {
// 更改“下载”按钮样式
[self.downloadButton setTitle:@"已下载" forState:UIControlStateDisabled];
self.downloadButton.enabled = NO; // 创建消息框
UILabel *successMsgLabel = [self.vcView viewWithTag:];
successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", self.appData.name];
successMsgLabel.alpha = 0.7; // 使用动画
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:];
successMsgLabel.alpha = ;
[UIView commitAnimations];
}
 
缺点:控件组AppView的下载事件中取得控制器来弹出消息框,还是依赖于主View,耦合性强
 
 
D.暴露控件组AppView的“下载”按钮,在主控制器中编写“下载”事件方法,绑定方法
1.AppView暴露“下载”按钮控件给外部
AppView.h
 // 将“下载”按钮控件移到 .h 文件中暴露
@property (weak, nonatomic) IBOutlet UIButton *downloadButton;
 
2.在控制器中编写“下载”单击事件方法
ViewController.m
 // 控制器创建“下载”按钮点击事件
- (IBAction)onAppViewDownloadButtonClick:(UIButton *) downloadButton {
// 更改“下载”按钮样式
[downloadButton setTitle:@"已下载" forState:UIControlStateDisabled];
downloadButton.enabled = NO; // 创建消息框
UILabel *successMsgLabel = [self.view viewWithTag:]; App *app = self.apps[downloadButton.tag];
successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", app.name];
successMsgLabel.alpha = 0.7; // 使用动画
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:];
successMsgLabel.alpha = ;
[UIView commitAnimations];
} @end
 
3.给每个AppView的“下载”按钮绑定方法

  for (int index=; 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); // 存储每个AppView对应的AppData数据索引在tag中
appView.downloadButton.tag = index; // 绑定每个AppView中的“下载”按钮点击事件
[appView.downloadButton addTarget:self action:@selector(onAppViewDownloadButtonClick:) forControlEvents:UIControlEventTouchUpInside]; // 3.加入此app信息到总view
[self.view addSubview:appView]; column++;
if (column == appColumnCount) {
column = ;
row++;
}
}
 
缺点:依赖于AppView暴露的“下载”按钮,不能被修改
 
 
E.代理模式
1.原则:谁拥有资源,谁调用
     添加label到控制器的逻辑:控制器来做
     当点击“下载”按钮的时候,控件组AppView的按钮点击事件应该通知控制器,要执行添加label到控制器view的操作
     控制器监听控件组AppView的下载按钮的点击
 
1.声明代理
AppView.h
 // 定义代理的协议
@protocol AppViewDelegate <NSObject>
// “下载”按钮被点击事件
@optional
- (void) appViewClickedDownloadButton:(AppView *) appView;
@end
 
2.在AppView中创建代理引用
AppView.h
 @interface AppView : UIView
// 代理
@property(nonatomic, weak) id<AppViewDelegate> delegate;
...
@end
 
3.控制器遵守AppViewDelegate,使其拥有称为代理的资格
 ViewController.m
@interface ViewController () <AppViewDelegate>
...
@end
 
4.实现代理方法
ViewController.m
 // “下载”按钮点击的代理方法
- (void)appViewClickedDownloadButton:(AppView *)appView {
// 创建下载成功消息框
CGFloat labelWidth = ;
CGFloat labelHeight = ;
CGFloat labelX = (self.view.frame.size.width - labelWidth) / ;
CGFloat labelY = (self.view.frame.size.height - labelHeight) / ;
UILabel *successMsgLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelWidth, labelHeight)]; // 设置圆角矩形样式
successMsgLabel.layer.cornerRadius = 10.0;
successMsgLabel.layer.masksToBounds = YES; // 设置全透明隐藏
successMsgLabel.alpha = ; successMsgLabel.textColor = [UIColor whiteColor];
successMsgLabel.backgroundColor = [UIColor grayColor];
[successMsgLabel setTextAlignment:NSTextAlignmentCenter]; successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", appView.appData.name];
successMsgLabel.alpha = 0.7; // 使用动画
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:];
successMsgLabel.alpha = ;
[UIView commitAnimations]; [self.view addSubview:successMsgLabel];
}
 
5.给每一个AppView设置代理
ViewController.m

   for (int index=; 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); // 设置代理
appView.delegate = self; // 3.加入此app信息到总view
[self.view addSubview:appView]; column++;
if (column == appColumnCount) {
column = ;
row++;
}
}
 
6.点击“下载”按钮的时候,通知代理
AppView.m
 // 点击下载按钮
- (IBAction)onDownloadButtonClick {
// 更改“下载”按钮样式
[self.downloadButton setTitle:@"已下载" forState:UIControlStateDisabled];
self.downloadButton.enabled = NO; // 通知代理
// 检查是否实现了代理方法
if ([self.delegate respondsToSelector:@selector(appViewClickedDownloadButton:)]) {
[self.delegate appViewClickedDownloadButton:self];
}
}
 
主要代码:
Model:
 App.h
//
// App.h
// 01-应用管理
//
// Created by hellovoidworld on 14/11/25.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import <Foundation/Foundation.h> @interface App : NSObject /**
copy : NSString
strong: 一般对象
weak: UI控件
assign: 基本数据类型
*/ /**
名称
*/
@property(nonatomic, copy) NSString *name; /**
图标
*/
@property(nonatomic, copy) NSString *icon; /**
自定义构造方法
通过字典来初始化模型对象
*/
- (instancetype) initWithDictionary:(NSDictionary *) dictionary; + (instancetype) appWithDictionary:(NSDictionary *) dictionary; @end
 
App.m
 //
// App.m
// 01-应用管理
//
// Created by hellovoidworld on 14/11/25.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #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
 
View:
 AppView.h
//
// AppView.h
// 01-应用管理
//
// Created by hellovoidworld on 14/11/25.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import <UIKit/UIKit.h> @class App, AppView; // 定义代理的协议
@protocol AppViewDelegate <NSObject>
// “下载”按钮被点击事件
@optional
- (void) appViewClickedDownloadButton:(AppView *) appView;
@end @interface AppView : UIView // 代理
@property(nonatomic, weak) id<AppViewDelegate> delegate; // 在Controller和View之间传输的Model数据
@property(nonatomic, strong) App *appData; // 自定义将Model数据加载到View的构造方法
- (instancetype) initWithApp:(App *) appData;
// 自定义构造的类方法
+ (instancetype) appViewWithApp:(App *) appData;
// 返回一个不带Model数据的类构造方法
+ (instancetype) appView; @end
 
AppView.m
 //
// AppView.m
// 01-应用管理
//
// Created by hellovoidworld on 14/11/25.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import "AppView.h"
#import "App.h" // 封装私有属性
@interface AppView() // 封装View中的控件,只允许自己访问
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UIButton *downloadButton; - (IBAction)onDownloadButtonClick; @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];
} // 点击下载按钮
- (IBAction)onDownloadButtonClick {
// 更改“下载”按钮样式
[self.downloadButton setTitle:@"已下载" forState:UIControlStateDisabled];
self.downloadButton.enabled = NO; // 通知代理
// 检查是否实现了代理方法
if ([self.delegate respondsToSelector:@selector(appViewClickedDownloadButton:)]) {
[self.delegate appViewClickedDownloadButton:self];
}
} @end
 
Controller:
ViewController.m
 //
// ViewController.m
// 01-应用管理
//
// Created by hellovoidworld on 14/11/24.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #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 () <AppViewDelegate> /** 存放应用信息 */
@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 + );
CGFloat marginY = (self.view.frame.size.height - APP_HEIGHT * appRowCount) / (appRowCount + ) + MARGIN_HEAD; int column = ;
int row = ;
for (int index=; 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); // 设置代理
appView.delegate = self; // 3.加入此app信息到总view
[self.view addSubview:appView]; column++;
if (column == appColumnCount) {
column = ;
row++;
}
} } #pragma mark 计算列数
- (int) appColumnCount {
int count = ;
count = self.view.frame.size.width / APP_WIDTH; if ((int)self.view.frame.size.width % (int)APP_WIDTH == ) {
count--;
} return count;
} #pragma mark 计算行数
- (int) appRowCount {
int count = ;
count = (self.view.frame.size.height - MARGIN_HEAD) / APP_HEIGHT; if ((int)(self.view.frame.size.height - MARGIN_HEAD) % (int)APP_HEIGHT == ) {
count--;
} return count;
} // “下载”按钮点击的代理方法
- (void)appViewClickedDownloadButton:(AppView *)appView {
// 创建下载成功消息框
CGFloat labelWidth = ;
CGFloat labelHeight = ;
CGFloat labelX = (self.view.frame.size.width - labelWidth) / ;
CGFloat labelY = (self.view.frame.size.height - labelHeight) / ;
UILabel *successMsgLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelWidth, labelHeight)]; // 设置圆角矩形样式
successMsgLabel.layer.cornerRadius = 10.0;
successMsgLabel.layer.masksToBounds = YES; // 设置全透明隐藏
successMsgLabel.alpha = ; successMsgLabel.textColor = [UIColor whiteColor];
successMsgLabel.backgroundColor = [UIColor grayColor];
[successMsgLabel setTextAlignment:NSTextAlignmentCenter]; successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", appView.appData.name];
successMsgLabel.alpha = 0.7; // 使用动画
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:];
successMsgLabel.alpha = ;
[UIView commitAnimations]; [self.view addSubview:successMsgLabel];
} @end
 

[iOS基础控件 - 5.5] 代理设计模式 (基于”APP列表"练习)的更多相关文章

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

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

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

    A.从ViewController分离View 之前的代码中,View的数据加载逻辑放在了总的ViewController中,增加了耦合性,应该对控制器ViewController隐藏数据加载到Vie ...

  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.9] 聊天界面Demo

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

  7. [iOS基础控件 - 6.12.3] @property属性 strong weak copy

    A.概念 @property 的修饰词   strong: 强指针/强引用(iOS6及之前是retain) weak: 弱智真/弱引用(iOS6及之前是assign)   默认情况所有指针都是强指针 ...

  8. [iOS基础控件 - 6.11.4] storyboard 的 Segue

    A.概念 storyboard中的跳转事件连线,都是一个UIStoryboardSegue对象(Segue)   来源控制器      触发控制器 目标控制器      跳转到的控制器     Seg ...

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

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

随机推荐

  1. linux 深入检测io详情的工具iopp

    1.为什么推荐iopp iotop对内核及python版本都有一定要求,有时候无法用上,这时候就可以使用iopp作为替代方案.在有些情况下可能无法顺利使用iotop,这时候就可以选择iopp了.它的作 ...

  2. QT中16进制字符串转汉字

    最经在研究AT指令接受短信,短信是unicode编码,接受后需要根据系统的编码方案进行相关的转码比如接受到了一串字符4F60597D,它是“你好”的unicode编码,一个unicode编码占两个字节 ...

  3. html元素elem.style.top.left始终为空

    有如下元素: <div id="div1"   >div1</div> #div1{ width:100px; height:100px; position ...

  4. Java 关于中文乱码处理的经验总结【转载】

    为什么说乱码是中国程序员无法避免的话题呢?这个首先要从编码机制上说起,大家都是中文和英文的编码格式不是一样,解码也是不一样的!如果中国的程序员不会遇到乱码,那么只有使用汉语编程.汉语编程是怎么回事我也 ...

  5. Managed C++中使用Nullable<T>

    非null值表示和C#的用法一样. Nullable<int> a = 1; null值的表示: Nullable<int> a = Nullable<int>() ...

  6. SQL列数据转换为字符串

    行列转换,将列数据转换为字符串输出 ) SET @center_JZHW = ( SELECT DISTINCT STUFF( ( SELECT ',' + ce_code FROM ap_cente ...

  7. 安装nging,php

    http://www.zihou.me/html/2010/11/14/2658.html http://www.linuxidc.com/Linux/2011-04/34964p4.htm http ...

  8. poj3275

    比较笨啊,一直在想,到底问几次绝对能知道所有的关系呢? 后来看了题解才知道,问一次最少确定一对关系………… 这就好办le,n头牛有C(2,n)个关系 现在给出m条边,以确定的关系有多少呢?直接dfs啊 ...

  9. 【App FrameWork】页面之间的参数传递

    若应用中有多个页面,这时2个页面之间可能需要进行参数传递.那么如何来实现呢? 首先想到的就是URL参数传递的方式,如:在panel里设置属性 data-defer="Pages/Shake. ...

  10. SQL Server AlwaysOn 和 ILB

    Narayan Annamalai 网络高级项目经理 自 2013 年 8 月起,Azure 基础结构服务开始支持 SQL ServerAlwaysOn 可用性组.Azure 服务的内部负载平衡 (I ...