A.概述
在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果、功能
1.按钮点击后,显示为“已下载”,并且不可以再按
2.在屏幕中间弹出一个消息框,通知消息“xx已经被安装”,慢慢消失
3.消息框样式为圆角半透明
B.不使用代理模式,使用app空间组和主View之间的父子View关系
1.在主View中创建一个消息框
主View控制器:ViewController.m
1//创建下载成功消息框2CGFloat labelWidth =200;3CGFloat labelHeight =50;4CGFloat labelX = (self.view.frame.size.width - labelWidth) /2;5CGFloat labelY = (self.view.frame.size.height - labelHeight) /2;6UILabel *successMsgLabel =[[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelWidth, labelHeight)];78//设置圆角矩形样式9successMsgLabel.layer.cornerRadius =10.0;10successMsgLabel.layer.masksToBounds =YES;1112//设置全透明隐藏13successMsgLabel.alpha =0;1415successMsgLabel.textColor =[UIColor whiteColor];16successMsgLabel.backgroundColor =[UIColor grayColor];17[successMsgLabel setTextAlignment:NSTextAlignmentCenter];18successMsgLabel.tag =10;1920[self.view addSubview:successMsgLabel];
2.直接在app空间组的控制器中操作消息框,加入到父控件(主View)
app控件组View:AppView.m
1//点击下载按钮2-(IBAction)onDownloadButtonClick {3//更改“下载”按钮样式4[self.downloadButton setTitle:@"已下载"forState:UIControlStateDisabled];5self.downloadButton.enabled =NO;67//拿到消息框8UILabel *successMsgLabel = [self.superview viewWithTag:10];9successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", self.appData.name];10successMsgLabel.alpha =0.7;1112//使用动画13[UIView beginAnimations:nil context:nil];14[UIView setAnimationDuration:2];15successMsgLabel.alpha =0;16[UIView commitAnimations];17}
缺点:view的父子关系规定了这两个view的层次关系,依赖性、耦合性太强,导致各个view都不能自由修改
C.不使用代理模式,在app控件组的view中将主View作为一个成员
1.在控件组AppView中创建主View的引用
控件组 AppView.h
1//存储主View的引用2@PRoperty (nonatomic, weak) UIView *vcView;
2.在主View逐个加载控件组的时候,设置主View的引用
ViewController.m
1for(intindex=0; index<self.apps.count; index++) {2App *appData =self.apps[index];34//1.创建View5AppView *appView =[AppView appViewWithApp:appData];67//2.定义每个app的位置、尺寸8CGFloat appX = marginX + column * (marginX +APP_WIDTH);9CGFloat appY = marginY + row * (marginY +APP_HEIGHT);10appView.frame =CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT);1112//设置每个app控件view的主view引用13appView.vcView =self.view;1415//3.加入此app信息到总view16[self.view addSubview:appView];1718column++;19if(column ==appColumnCount) {20column =0;21row++;22}
3.控件组AppView使用主View引用代替父控件引用
AppView.m
1//点击下载按钮2-(IBAction)onDownloadButtonClick {3//更改“下载”按钮样式4[self.downloadButton setTitle:@"已下载"forState:UIControlStateDisabled];5self.downloadButton.enabled =NO;67//创建消息框8UILabel *successMsgLabel = [self.vcView viewWithTag:10];9successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", self.appData.name];10successMsgLabel.alpha =0.7;1112//使用动画13[UIView beginAnimations:nil context:nil];14[UIView setAnimationDuration:2];15successMsgLabel.alpha =0;16[UIView commitAnimations];17}
缺点:控件组AppView的下载事件中取得控制器来弹出消息框,还是依赖于主View,耦合性强
D.暴露控件组AppView的“下载”按钮,在主控制器中编写“下载”事件方法,绑定方法
1.AppView暴露“下载”按钮控件给外部
AppView.h
1//将“下载”按钮控件移到 .h 文件中暴露2@property (weak, nonatomic) IBOutlet UIButton *downloadButton;
2.在控制器中编写“下载”单击事件方法
ViewController.m
1//控制器创建“下载”按钮点击事件2- (IBAction)onAppViewDownloadButtonClick:(UIButton *) downloadButton {3//更改“下载”按钮样式4[downloadButton setTitle:@"已下载"forState:UIControlStateDisabled];5downloadButton.enabled =NO;67//创建消息框8UILabel *successMsgLabel = [self.view viewWithTag:99];910App *app =self.apps[downloadButton.tag];11successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", app.name];12successMsgLabel.alpha =0.7;1314//使用动画15[UIView beginAnimations:nil context:nil];16[UIView setAnimationDuration:2];17successMsgLabel.alpha =0;18[UIView commitAnimations];19}2021@end
3.给每个AppView的“下载”按钮绑定方法
1for(intindex=0; index<self.apps.count; index++) {2App *appData =self.apps[index];34//1.创建View5AppView *appView =[AppView appViewWithApp:appData];67//2.定义每个app的位置、尺寸8CGFloat appX = marginX + column * (marginX +APP_WIDTH);9CGFloat appY = marginY + row * (marginY +APP_HEIGHT);10appView.frame =CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT);1112//存储每个AppView对应的AppData数据索引在tag中13appView.downloadButton.tag =index;1415//绑定每个AppView中的“下载”按钮点击事件16[appView.downloadButton addTarget:self action:@selector(onAppViewDownloadButtonClick:) forControlEvents:UIControlEventTouchUpInside];1718//3.加入此app信息到总view19[self.view addSubview:appView];2021column++;22if(column ==appColumnCount) {23column =0;24row++;25}26}
缺点:依赖于AppView暴露的“下载”按钮,不能被修改
E.代理模式
1.原则:谁拥有资源,谁调用
添加label到控制器的逻辑:控制器来做
当点击“下载”按钮的时候,控件组AppView的按钮点击事件应该通知控制器,要执行添加label到控制器view的操作
控制器监听控件组AppView的下载按钮的点击
1.声明代理
AppView.h
1//定义代理的协议2@protocolAppViewDelegate <NSObject>3//“下载”按钮被点击事件4@optional5- (void) appViewClickedDownloadButton:(AppView *) appView;6@end
2.在AppView中创建代理引用
AppView.h
1@interfaceAppView : UIView2//代理3@property(nonatomic, weak)id<AppViewDelegate>delegate;4...5@end
3.控制器遵守AppViewDelegate,使其拥有称为代理的资格
1ViewController.m2@interfaceViewController () <AppViewDelegate>3...4@end
4.实现代理方法
ViewController.m
1//“下载”按钮点击的代理方法2- (void)appViewClickedDownloadButton:(AppView *)appView {3//创建下载成功消息框4CGFloat labelWidth =200;5CGFloat labelHeight =50;6CGFloat labelX = (self.view.frame.size.width - labelWidth) /2;7CGFloat labelY = (self.view.frame.size.height - labelHeight) /2;8UILabel *successMsgLabel =[[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelWidth, labelHeight)];910//设置圆角矩形样式11successMsgLabel.layer.cornerRadius =10.0;12successMsgLabel.layer.masksToBounds =YES;1314//设置全透明隐藏15successMsgLabel.alpha =0;1617successMsgLabel.textColor =[UIColor whiteColor];18successMsgLabel.backgroundColor =[UIColor grayColor];19[successMsgLabel setTextAlignment:NSTextAlignmentCenter];2021successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", appView.appData.name];22successMsgLabel.alpha =0.7;2324//使用动画25[UIView beginAnimations:nil context:nil];26[UIView setAnimationDuration:2];27successMsgLabel.alpha =0;28[UIView commitAnimations];2930[self.view addSubview:successMsgLabel];31}
5.给每一个AppView设置代理
ViewController.m
1for(intindex=0; index<self.apps.count; index++) {2App *appData =self.apps[index];34//1.创建View5AppView *appView =[AppView appViewWithApp:appData];67//2.定义每个app的位置、尺寸8CGFloat appX = marginX + column * (marginX +APP_WIDTH);9CGFloat appY = marginY + row * (marginY +APP_HEIGHT);10appView.frame =CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT);1112//设置代理13appView.delegate=self;1415//3.加入此app信息到总view16[self.view addSubview:appView];1718column++;19if(column ==appColumnCount) {20column =0;21row++;22}23}
6.点击“下载”按钮的时候,通知代理
AppView.m
1//点击下载按钮2-(IBAction)onDownloadButtonClick {3//更改“下载”按钮样式4[self.downloadButton setTitle:@"已下载"forState:UIControlStateDisabled];5self.downloadButton.enabled =NO;67//通知代理8//检查是否实现了代理方法9if([self.delegaterespondsToSelector:@selector(appViewClickedDownloadButton:)]) {10[self.delegateappViewClickedDownloadButton:self];11}12}
主要代码:
Model:
1App.h2//3//App.h4//01-应用管理5//6//Created by hellovoidworld on 14/11/25.7//Copyright (c) 2014年 hellovoidworld. All rights reserved.8//910#import<Foundation/Foundation.h>1112@interfaceApp : NSObject1314/**15copy : NSString16strong: 一般对象17weak: UI控件18assign: 基本数据类型19*/2021/**22名称23*/24@property(nonatomic, copy) NSString *name;2526/**27图标28*/29@property(nonatomic, copy) NSString *icon;3031/**32自定义构造方法33通过字典来初始化模型对象34*/35- (instancetype) initWithDictionary:(NSDictionary *) dictionary;3637+ (instancetype) appWithDictionary:(NSDictionary *) dictionary;3839@end
App.m
1//2//App.m3//01-应用管理4//5//Created by hellovoidworld on 14/11/25.6//Copyright (c) 2014年 hellovoidworld. All rights reserved.7//89#import"App.h"1011#defineICON_KEY @"icon"12#defineNAME_KEY @"name"1314@implementationApp1516- (instancetype) initWithDictionary:(NSDictionary *) dictionary {17if(self =[super init]) {18self.name =dictionary[NAME_KEY];19self.icon =dictionary[ICON_KEY];20}2122returnself;23}242526+ (instancetype) appWithDictionary:(NSDictionary *) dictionary {27//使用self代表类名代替真实类名,防止子类调用出错28return[[self alloc] initWithDictionary:dictionary];29}3031@end
View:
1AppView.h2//3//AppView.h4//01-应用管理5//6//Created by hellovoidworld on 14/11/25.7//Copyright (c) 2014年 hellovoidworld. All rights reserved.8//910#import<UIKit/UIKit.h>1112@classApp, AppView;1314//定义代理的协议15@protocolAppViewDelegate <NSObject>16//“下载”按钮被点击事件17@optional18- (void) appViewClickedDownloadButton:(AppView *) appView;19@end2021@interfaceAppView : UIView2223//代理24@property(nonatomic, weak)id<AppViewDelegate>delegate;2526//在Controller和View之间传输的Model数据27@property(nonatomic, strong) App *appData;282930//自定义将Model数据加载到View的构造方法31- (instancetype) initWithApp:(App *) appData;32//自定义构造的类方法33+ (instancetype) appViewWithApp:(App *) appData;34//返回一个不带Model数据的类构造方法35+(instancetype) appView;363738@end
AppView.m
1//2//AppView.m3//01-应用管理4//5//Created by hellovoidworld on 14/11/25.6//Copyright (c) 2014年 hellovoidworld. All rights reserved.7//89#import"AppView.h"10#import"App.h"1112//封装私有属性13@interfaceAppView()1415//封装View中的控件,只允许自己访问16@property (weak, nonatomic) IBOutlet UIImageView *iconView;17@property (weak, nonatomic) IBOutlet UILabel *nameLabel;18@property (weak, nonatomic) IBOutlet UIButton *downloadButton;19202122-(IBAction)onDownloadButtonClick;2324@end2526@implementationAppView2728- (void)setAppData:(App *)appData {29//1.赋值Medel成员30_appData =appData;3132//2.设置图片33self.iconView.image =[UIImage imageNamed:appData.icon];34//3.设置名字35self.nameLabel.text =appData.name;36}3738//自定义将Model数据加载到View的构造方法39- (instancetype) initWithApp:(App *) appData {40//1.从NIB取得控件41UINib *nib = [UINib nibWithNibName:@"app"bundle:[NSBundle mainBundle]];42NSArray *viewArray =[nib instantiateWithOwner:nil options:nil];43AppView *appView =[viewArray lastObject];4445//2.加载Model46appView.appData =appData;4748returnappView;49}5051//自定义构造的类方法52+ (instancetype) appViewWithApp:(App *) appData {53return[[self alloc] initWithApp:appData];54}5556//返回一个不带Model数据的类构造方法57+(instancetype) appView {58return[self appViewWithApp:nil];59}6061//点击下载按钮62-(IBAction)onDownloadButtonClick {63//更改“下载”按钮样式64[self.downloadButton setTitle:@"已下载"forState:UIControlStateDisabled];65self.downloadButton.enabled =NO;6667//通知代理68//检查是否实现了代理方法69if([self.delegaterespondsToSelector:@selector(appViewClickedDownloadButton:)]) {70[self.delegateappViewClickedDownloadButton:self];71}72}7374@end
Controller:
ViewController.m
1//2//ViewController.m3//01-应用管理4//5//Created by hellovoidworld on 14/11/24.6//Copyright (c) 2014年 hellovoidworld. All rights reserved.7//89#import"ViewController.h"10#import"App.h"11#import"AppView.h"1213#defineICON_KEY @"icon"14#defineNAME_KEY @"name"15#defineAPP_WIDTH 8516#defineAPP_HEIGHT 9017#defineMARGIN_HEAD 2018#defineICON_WIDTH 5019#defineICON_HEIGHT 5020#defineNAME_WIDTH APP_WIDTH21#defineNAME_HEIGHT 2022#defineDOWNLOAD_WIDTH (APP_WIDTH - 20)23#defineDOWNLOAD_HEIGHT 202425@interfaceViewController () <AppViewDelegate>2627/** 存放应用信息*/28@property(nonatomic, strong) NSArray *apps;//应用列表2930@end3132@implementationViewController3334- (void)viewDidLoad {35[super viewDidLoad];36//Do any additional setup after loading the view, typically from a nib.3738[self loadApps];39}4041- (void)didReceiveMemoryWarning {42[super didReceiveMemoryWarning];43//Dispose of any resources that can be recreated.44}4546#pragmamark 取得应用列表47- (NSArray *) apps {48if(nil ==_apps) {49//1.获得plist的全路径50NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist"ofType:nil];5152//2.加载数据53NSArray *dictArray =[NSArray arrayWithContentsOfFile:path];5455//3.将dictArray里面的所有字典转成模型,放到新数组中56NSMutableArray *appArray =[NSMutableArray array];57for(NSDictionary *dictindictArray) {58//3.1创建模型对象59App *app =[App appWithDictionary:dict];6061//3.2 添加到app数组中62[appArray addObject:app];63}6465_apps =appArray;66}6768return_apps;69}7071#pragmamark 加载全部应用列表72- (void) loadApps {73intappColumnCount =[self appColumnCount];74intappRowCount =[self appRowCount];7576CGFloat marginX = (self.view.frame.size.width - APP_WIDTH * appColumnCount) / (appColumnCount +1);77CGFloat marginY = (self.view.frame.size.height - APP_HEIGHT * appRowCount) / (appRowCount +1) +MARGIN_HEAD;7879intcolumn =0;80introw =0;81for(intindex=0; index<self.apps.count; index++) {82App *appData =self.apps[index];8384//1.创建View85AppView *appView =[AppView appViewWithApp:appData];8687//2.定义每个app的位置、尺寸88CGFloat appX = marginX + column * (marginX +APP_WIDTH);89CGFloat appY = marginY + row * (marginY +APP_HEIGHT);90appView.frame =CGRectMake(appX, appY, APP_WIDTH, APP_HEIGHT);9192//设置代理93appView.delegate=self;9495//3.加入此app信息到总view96[self.view addSubview:appView];9798column++;99if(column ==appColumnCount) {100column =0;101row++;102}103}104105}106107108#pragmamark 计算列数109- (int) appColumnCount {110intcount =0;111count = self.view.frame.size.width /APP_WIDTH;112113if((int)self.view.frame.size.width % (int)APP_WIDTH ==0) {114count--;115}116117returncount;118}119120#pragmamark 计算行数121- (int) appRowCount {122intcount =0;123count = (self.view.frame.size.height - MARGIN_HEAD) /APP_HEIGHT;124125if((int)(self.view.frame.size.height - MARGIN_HEAD) % (int)APP_HEIGHT ==0) {126count--;127}128129returncount;130}131132//“下载”按钮点击的代理方法133- (void)appViewClickedDownloadButton:(AppView *)appView {134//创建下载成功消息框135CGFloat labelWidth =200;136CGFloat labelHeight =50;137CGFloat labelX = (self.view.frame.size.width - labelWidth) /2;138CGFloat labelY = (self.view.frame.size.height - labelHeight) /2;139UILabel *successMsgLabel =[[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelWidth, labelHeight)];140141//设置圆角矩形样式142successMsgLabel.layer.cornerRadius =10.0;143successMsgLabel.layer.masksToBounds =YES;144145//设置全透明隐藏146successMsgLabel.alpha =0;147148successMsgLabel.textColor =[UIColor whiteColor];149successMsgLabel.backgroundColor =[UIColor grayColor];150[successMsgLabel setTextAlignment:NSTextAlignmentCenter];151152successMsgLabel.text = [NSString stringWithFormat:@"成功安装了%@", appView.appData.name];153successMsgLabel.alpha =0.7;154155//使用动画156[UIView beginAnimations:nil context:nil];157[UIView setAnimationDuration:2];158successMsgLabel.alpha =0;159[UIView commitAnimations];160161[self.view addSubview:successMsgLabel];162}163164@end