第一节课:
.复习
.运行App应用管理,简单界面分析
.一个应用为一个整体,直接创建一个appView然后计算frame
.说明弊端,应该根据数据的个数来for循环创建 第二节课:
.加载plist文件字典转模型
.分析计算frame 宽高固定,x,y动态去计算
6.1. 行号 row = i / columnCount
6.2 列号 col = i % columnCount
leftMargin = (屏幕的宽 - (appW * columnCount) - appColMagrin * (columnCount - )) * 0.5;
appX = leftMargin + (appW + appColMagrin) * col;
appY = topMargin + (appY + appRowMagrin) * row 第三节:
.3创建appView内部三个字控件,iconView, nameLabel , downloadBtn
6.4 先创建设置背景色,计算frame添加到appView中
6.5 给子控件设置数据,设置label字体和文字对齐方法
注意点:给按钮设置图片或文字还有文字颜色时,要用set方法指定不同状态的文字或图片,不能直接访问titleLabel去给按钮设置文字
.分析懒加载代码中的问题封装字典转模型细节, instancetype 是和id
、相同点
都可以作为方法的返回类型 、不同点
> instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象; > instancetype只能作为返回值,不能像id那样作为参数,和声明属性 id是个万能指针编译时不确定真实类型,只有在运行时才知道真实的类型
instancetype在编译时就可以确定真实类型,类型一般为所在类的对象类型 下午: 第一节课: 7.1 自定义构造方法,并提供一个类方法
7.2 自定义构造方法时的方法命名规范,注意点
7.3 代码进一步优化,引出xib
.xib和storyboard的区别及开发中如何去选择
.MVC概念的引入
.1用xib去封装appView,并创建一个继承至UIView的类,和xib的类型关联
.2把xib中的控件连线到自定义类的.h中可以在外面直接访问去给子控件设置数据
9.3.弊端,把模型变成属性引入到自定义view类,当控制器为自定义view类的模型属性赋值时会调用模型属性的set方法,如果我们重写了属性得set方法就会调用我们重写得set方法,在此方法中给appView中的子控件设置数据 第二节课:
.添加下载按钮点击事件
10.1 点击下载按钮弹出提示标签,并加入动画 第三节课:
.回顾用xib自定义view的步骤
.创建一个xib文件,在xib文件中布局好子控件,并设置好对应控件的属性
.创建一个和xib文件相同的类,此类继承至那个类,取决于xib文件中最顶层控件的类型,
.指定xib文件的类型为我们自定义的类,然后把需要修改的控件拖线到所关联类的.m文件中
.自定义类,定义模型属性,并重写模型属性的set方法,在此方法给子控件设置数据
.在自定义类提供一个可供外部访问的类方法,把加载xib创建appView的过程封装到自定义类中 *********** UIViewAnimationOption(动画选项,默认为匀速) ********
常规动画属性设置(可以同时选择多个进行设置) UIViewAnimationOptionLayoutSubviews:动画过程中保证子视图跟随运动。 UIViewAnimationOptionAllowUserInteraction:动画过程中允许用户交互。 UIViewAnimationOptionBeginFromCurrentState:所有视图从当前状态开始运行。 UIViewAnimationOptionRepeat:重复运行动画。 UIViewAnimationOptionAutoreverse :动画运行到结束点后仍然以动画方式回到初始点。 UIViewAnimationOptionOverrideInheritedDuration:忽略嵌套动画时间设置。 UIViewAnimationOptionOverrideInheritedCurve:忽略嵌套动画速度设置。 UIViewAnimationOptionAllowAnimatedContent:动画过程中重绘视图(注意仅仅适用于转场动画)。 UIViewAnimationOptionShowHideTransitionViews:视图切换时直接隐藏旧视图、显示新视图,而不是将旧视图从父视图移除(仅仅适用于转场动画)
UIViewAnimationOptionOverrideInheritedOptions :不继承父动画设置或动画类型。 .动画速度控制(可从其中选择一个设置) UIViewAnimationOptionCurveEaseInOut:动画先缓慢,然后逐渐加速。 UIViewAnimationOptionCurveEaseIn :动画逐渐变慢。 UIViewAnimationOptionCurveEaseOut:动画逐渐加速。 UIViewAnimationOptionCurveLinear :动画匀速执行,默认值。 .转场类型(仅适用于转场动画设置,可以从中选择一个进行设置,基本动画、关键帧动画不需要设置) UIViewAnimationOptionTransitionNone:没有转场动画效果。 UIViewAnimationOptionTransitionFlipFromLeft :从左侧翻转效果。 UIViewAnimationOptionTransitionFlipFromRight:从右侧翻转效果。 UIViewAnimationOptionTransitionCurlUp:向后翻页的动画过渡效果。 UIViewAnimationOptionTransitionCurlDown :向前翻页的动画过渡效果。 UIViewAnimationOptionTransitionCrossDissolve:旧视图溶解消失显示下一个新视图的效果。 UIViewAnimationOptionTransitionFlipFromTop :从上方翻转效果。 UIViewAnimationOptionTransitionFlipFromBottom:从底部翻转效果。

一、创建九宫格

实现思路

(1)明确每一块用得是什么view

(2)明确每个view之间的父子关系,每个视图都只有一个父视图,拥有很多的子视图。

(3)可以先尝试逐个的添加格子,最后考虑使用for循环,完成所有uiview的创建

(4)加载app数据,根据数据长度创建对应个数的格子

(5)添加格子内部的子控件

(6)给内部的子控件装配数据

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad]; // 设置每行应用的个数
int clumns = ;
// 获取控制器所管理的view的宽度
CGFloat viewWidth = self.view.frame.size.width; // 每个应用的宽和高
CGFloat appW = ;
CGFloat appH = ;
CGFloat marginTop = ;//第一行距顶部的距离
CGFloat marginX = (viewWidth - appW*clumns)/(clumns+);
CGFloat marginY = marginX;//设每行之间的间距与marginX相等 for (int i=; i<; i++) {
//1.创建每个应用(UIView)
UIView *appView = [[UIView alloc] init]; //2.设置appView的属性 //2.1设置appView的背景色
appView.backgroundColor = [UIColor orangeColor];
//2.2设置appView的frame属性 //计算每个单元格的列索引
int colIdx = i%clumns;
//计算每个单元格的行索引
int rowIdy = i/clumns; CGFloat appX = marginX+(appW+marginX)*colIdx;
CGFloat appY = marginTop+(appH+marginY)*rowIdy; appView.frame = CGRectMake(appX, appY, appW, appH); //3.将appView加到self.view
[self.view addSubview:appView]; }
}

二、向九宫格内加控件

 #import "ViewController.h"

 @interface ViewController ()
/**
* 用来存放所有数据的数组
*/
@property (nonatomic, strong) NSArray *appes;
@end @implementation ViewController /**
* 控制器的view加载完成之后就会调用此方法
*/
- (void)viewDidLoad {
[super viewDidLoad];
// 格子之间的间距
CGFloat margin = ;
// 格子的宽
CGFloat appViewW = ;
// 格子的高
CGFloat appViewH = ;
// 一行中用三个格子
NSInteger column = ;
// 最左边的间距 = (控制器view的宽 - 一行中所有格子的宽 - 格子间的间距 * (一行中格子的个数 - 1)) * 0.5
CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - ) *margin) * 0.5;
CGFloat topMargin = leftMargin;
// 根据数据的个数来动画创建每一个应用
for (NSInteger i = ; i < self.appes.count; i++) { // 0> 先取出每一个应该的数据
NSDictionary *dict = self.appes[i]; // 1.创建appView 用来装里面的子控件
UIView *appView = [[UIView alloc] init];
// 2.设置背景色
// appView.backgroundColor = [UIColor blueColor]; // 计算列号
NSInteger col = i % column;
// 计算行号
NSInteger row = i / column;
// 3.设置frame
// 计算appViewX = 左边间距 + (appView宽 + 格子间距) *当前格子是在当前行中的第几个
CGFloat appViewX = leftMargin + (appViewW + margin) * col;
// appViewY = 顶部间距 + (appViewH + margin) * 当前格子在当前列中是第几个
CGFloat appViewY = topMargin + (appViewH + margin) * row; appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH); // 4.添加到控制器的view中
[self.view addSubview:appView]; // 5.创建应用图片
UIImageView *iconView = [[UIImageView alloc] init];
// 设置背景色
// iconView.backgroundColor = [UIColor purpleColor];
CGFloat iconW = ;
CGFloat iconH = iconW;
CGFloat iconX = (appViewW - iconW) * 0.5;
CGFloat iconY = ;
iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);
[appView addSubview:iconView]; // 设置应用图片
iconView.image = [UIImage imageNamed:dict[@"icon"]]; // 6.应用的名称
UILabel *nameLabel = [[UILabel alloc] init];
// 设置背景色
// nameLabel.backgroundColor = [UIColor yellowColor];
CGFloat nameX = ;
// CGFloat nameY = iconY + iconH;
CGFloat nameY = CGRectGetMaxY(iconView.frame);
CGFloat nameW = appViewW;
CGFloat nameH = ;
// 设置frame
nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH);
// 把名称标签添加到父控件中
[appView addSubview:nameLabel]; // 设置应用名称
nameLabel.text = dict[@"name"];
// 设置字体大小
nameLabel.font = [UIFont systemFontOfSize:13.0];
// 设置文字居中
nameLabel.textAlignment = NSTextAlignmentCenter; // 7.下载按钮
UIButton *downloadBtn = [[UIButton alloc] init];
// downloadBtn.backgroundColor = [UIColor redColor];
CGFloat downloadX = iconX;
CGFloat downloadY = CGRectGetMaxY(nameLabel.frame);
CGFloat downlaodW = iconW;
CGFloat downlaodH = ;
downloadBtn.frame = CGRectMake(downloadX, downloadY, downlaodW, downlaodH);
[appView addSubview:downloadBtn]; // 设置按钮背景图片
[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateDisabled];
// 设置按钮的文字
[downloadBtn setTitle:@"下载" forState:UIControlStateNormal];
[downloadBtn setTitle:@"已下载" forState:UIControlStateDisabled]; downloadBtn.titleLabel.font = [UIFont systemFontOfSize:];
}
} #pragma mark - 懒加载
- (NSArray *)appes {
// 1.判断当前的数组属性是否为空,如果为空的时候再去加载数据
if (_appes == nil) {
// 2.获取plist文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
// 3.加载plist文件
NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
_appes = dictArr; } return _appes; } @end

三、向九宫格内加数据

 #import "ViewController.h"

 @interface ViewController ()
/**
* 用来存放所有数据的数组
*/
@property (nonatomic, strong) NSArray *appes;
@end @implementation ViewController /**
* 控制器的view加载完成之后就会调用此方法
*/
- (void)viewDidLoad {
[super viewDidLoad];
// 格子之间的间距
CGFloat margin = ;
// 格子的宽
CGFloat appViewW = ;
// 格子的高
CGFloat appViewH = ;
// 一行中用三个格子
NSInteger column = ;
// 最左边的间距 = (控制器view的宽 - 一行中所有格子的宽 - 格子间的间距 * (一行中格子的个数 - 1)) * 0.5
CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - ) *margin) * 0.5;
CGFloat topMargin = leftMargin;
// 根据数据的个数来动画创建每一个应用
for (NSInteger i = ; i < self.appes.count; i++) { // 0> 先取出每一个应该的数据
NSDictionary *dict = self.appes[i]; // 1.创建appView 用来装里面的子控件
UIView *appView = [[UIView alloc] init];
// 2.设置背景色
// appView.backgroundColor = [UIColor blueColor]; // 计算列号
NSInteger col = i % column;
// 计算行号
NSInteger row = i / column;
// 3.设置frame
// 计算appViewX = 左边间距 + (appView宽 + 格子间距) *当前格子是在当前行中的第几个
CGFloat appViewX = leftMargin + (appViewW + margin) * col;
// appViewY = 顶部间距 + (appViewH + margin) * 当前格子在当前列中是第几个
CGFloat appViewY = topMargin + (appViewH + margin) * row; appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH); // 4.添加到控制器的view中
[self.view addSubview:appView]; // 5.创建应用图片
UIImageView *iconView = [[UIImageView alloc] init];
// 设置背景色
// iconView.backgroundColor = [UIColor purpleColor];
CGFloat iconW = ;
CGFloat iconH = iconW;
CGFloat iconX = (appViewW - iconW) * 0.5;
CGFloat iconY = ;
iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);
[appView addSubview:iconView]; // 设置应用图片
iconView.image = [UIImage imageNamed:dict[@"icon"]]; // 6.应用的名称
UILabel *nameLabel = [[UILabel alloc] init];
// 设置背景色
// nameLabel.backgroundColor = [UIColor yellowColor];
CGFloat nameX = ;
// CGFloat nameY = iconY + iconH;
CGFloat nameY = CGRectGetMaxY(iconView.frame);
CGFloat nameW = appViewW;
CGFloat nameH = ;
// 设置frame
nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH);
// 把名称标签添加到父控件中
[appView addSubview:nameLabel]; // 设置应用名称
nameLabel.text = dict[@"name"];
// 设置字体大小
nameLabel.font = [UIFont systemFontOfSize:13.0];
// 设置文字居中
nameLabel.textAlignment = NSTextAlignmentCenter; // 7.下载按钮
UIButton *downloadBtn = [[UIButton alloc] init];
// downloadBtn.backgroundColor = [UIColor redColor];
CGFloat downloadX = iconX;
CGFloat downloadY = CGRectGetMaxY(nameLabel.frame);
CGFloat downlaodW = iconW;
CGFloat downlaodH = ;
downloadBtn.frame = CGRectMake(downloadX, downloadY, downlaodW, downlaodH);
[appView addSubview:downloadBtn]; // 设置按钮背景图片
[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateDisabled];
// 设置按钮的文字
[downloadBtn setTitle:@"下载" forState:UIControlStateNormal];
[downloadBtn setTitle:@"已下载" forState:UIControlStateDisabled]; downloadBtn.titleLabel.font = [UIFont systemFontOfSize:];
}
} #pragma mark - 懒加载
- (NSArray *)appes {
// 1.判断当前的数组属性是否为空,如果为空的时候再去加载数据
if (_appes == nil) {
// 2.获取plist文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
// 3.加载plist文件
NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
_appes = dictArr; } return _appes; }

代码问题

我们是直接通过字典的键名获取plist中的数据信息,在viewController中需要直接和数据打交道,如果需要多次使用可能会因为不小心把键名写错,而程序并不报错。鉴于此,可以考虑把字典数据转换成一个模型,把数据封装到一个模型中去,让viewController不再直接和数据打交道,而是和模型交互。

一般情况下,设置数据和取出数据都使用“字符串类型的key”,编写这些key时,编辑器没有智能提示,需要手敲。如:

dict[@"name"] = @"Jack";

NSString *name = dict[@"name"];

手敲字符串key,key容易写错

Key如果写错了,编译器不会有任何警告和报错,造成设错数据或者取错数据

四、字典转模型

字典转模型的好处:

(1)降低代码的耦合度

(2)所有字典转模型部分的代码统一集中在一处处理,降低代码出错的几率

(3)在程序中直接使用模型的属性操作,提高编码效率

(4)调用方不用关心模型内部的任何处理细节

字典转模型的注意点:

模型应该提供一个可以传入字典参数的构造方法

- (instancetype)initWithDict:(NSDictionary *)dict;

+ (instancetype)xxxWithDict:(NSDictionary *)dict;

提示:在模型中合理地使用只读属性,可以进一步降低代码的耦合度。

#import <Foundation/Foundation.h>
/** NSString block用copy
除了字符串和 block 控件 其它基本OC对象都用strong
weak 控件最好都用
assgin 基本数据类型
*/
@interface HMApp : NSObject
/** 应用图片 */
@property (nonatomic, copy) NSString *icon;
/** 应用名称 */
@property (nonatomic, copy) NSString *name; // id他instancetype有什么区别
// 1.相同点:他们都可以当方法的返回值
// 2.不同点:id可以来声明变量,id可以当参数类型,\
// id是一个万能指针,他在编译的时候不会确定真实的类型,只有在运行时候才知道真实类型
// instancetype在编译的时候就能确定他的返回值真实类型,这种更安全
//clang 3.5
/**  */
- (instancetype)initWithDict:(NSDictionary *)dict;//用字典实例化对象的成员方法
+ (instancetype)appWithDict:(NSDictionary *)dict;//用字典实例化对象的类方法,又称工厂方法
@end #import "HMApp.h" @implementation HMApp
- (instancetype)initWithDict:(NSDictionary *)dict {
if (self = [super init]) {
self.icon = dict[@"icon"];
self.name = dict[@"name"];

[self setValuesForKeysWithDictionary:dict];//加载所有属性

    }

    return self;
} + (instancetype)appWithDict:(NSDictionary *)dict {
return [[self alloc] initWithDict:dict];
}
@end /**
xib和stroyboard的区别
1.相同点:都可以用来我们软件界面
2.不同点:在storyboard可以用来搭建整个应用的所有界面,最少也是一个界面
xib可以用来描述一个界面中的某一个部分,或一个应用的一个界面,及整个界面
*/
#import "ViewController.h"
#import "HMApp.h" @interface ViewController ()
/**
* 用来存放所有数据的数组
*/
@property (nonatomic, strong) NSArray *appes;
@end @implementation ViewController /**
* 控制器的view加载完成之后就会调用此方法
*/
- (void)viewDidLoad {
[super viewDidLoad];
// 格子之间的间距
CGFloat margin = ;
// 格子的宽
CGFloat appViewW = ;
// 格子的高
CGFloat appViewH = ;
// 一行中用三个格子
NSInteger column = ;
// 最左边的间距 = (控制器view的宽 - 一行中所有格子的宽 - 格子间的间距 * (一行中格子的个数 - 1)) * 0.5
CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - ) *margin) * 0.5;
CGFloat topMargin = leftMargin;
// 根据数据的个数来动画创建每一个应用
for (NSInteger i = ; i < self.appes.count; i++) { // 0> 先取出每一个应该的数据
// NSDictionary *dict = self.appes[i];
// 取数组中每一个用来表示数据的模型对象
HMApp *app = self.appes[i]; // 1.创建appView 用来装里面的子控件
UIView *appView = [[UIView alloc] init];
// 2.设置背景色
// appView.backgroundColor = [UIColor blueColor]; // 计算列号
NSInteger col = i % column;
// 计算行号
NSInteger row = i / column;
// 3.设置frame
// 计算appViewX = 左边间距 + (appView宽 + 格子间距) *当前格子是在当前行中的第几个
CGFloat appViewX = leftMargin + (appViewW + margin) * col;
// appViewY = 顶部间距 + (appViewH + margin) * 当前格子在当前列中是第几个
CGFloat appViewY = topMargin + (appViewH + margin) * row; appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH); // 4.添加到控制器的view中
[self.view addSubview:appView]; // 5.创建应用图片
UIImageView *iconView = [[UIImageView alloc] init];
// 设置背景色
// iconView.backgroundColor = [UIColor purpleColor];
CGFloat iconW = ;
CGFloat iconH = iconW;
CGFloat iconX = (appViewW - iconW) * 0.5;
CGFloat iconY = ;
iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);
[appView addSubview:iconView]; // 设置应用图片
iconView.image = [UIImage imageNamed:app.icon]; // 6.应用的名称
UILabel *nameLabel = [[UILabel alloc] init];
// 设置背景色
// nameLabel.backgroundColor = [UIColor yellowColor];
CGFloat nameX = ;
// CGFloat nameY = iconY + iconH;
CGFloat nameY = CGRectGetMaxY(iconView.frame);
CGFloat nameW = appViewW;
CGFloat nameH = ;
// 设置frame
nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH);
// 把名称标签添加到父控件中
[appView addSubview:nameLabel]; // 设置应用名称
nameLabel.text = app.name;
// 设置字体大小
nameLabel.font = [UIFont systemFontOfSize:13.0];
// 设置文字居中
nameLabel.textAlignment = NSTextAlignmentCenter; // 7.下载按钮
UIButton *downloadBtn = [[UIButton alloc] init];
// downloadBtn.backgroundColor = [UIColor redColor];
CGFloat downloadX = iconX;
CGFloat downloadY = CGRectGetMaxY(nameLabel.frame);
CGFloat downlaodW = iconW;
CGFloat downlaodH = ;
downloadBtn.frame = CGRectMake(downloadX, downloadY, downlaodW, downlaodH);
[appView addSubview:downloadBtn]; // 设置按钮背景图片
[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
[downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateDisabled];
// 设置按钮的文字
[downloadBtn setTitle:@"下载" forState:UIControlStateNormal];
[downloadBtn setTitle:@"已下载" forState:UIControlStateDisabled]; downloadBtn.titleLabel.font = [UIFont systemFontOfSize:];
}
} #pragma mark - 懒加载
- (NSArray *)appes {
// 1.判断当前的数组属性是否为空,如果为空的时候再去加载数据
if (_appes == nil) {
// 2.获取plist文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
// 3.加载plist文件
NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; // 创建一个可变数据用来保存每一个模型对象(创建可变数组时并给其分配好容量)
NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:dictArr.count];
// 遍历字典数组把每一个字典转换成一个模型对象
for (NSDictionary *dict in dictArr) {
// 创建模型对象
// HMApp *app = [[HMApp alloc] initWithDict:dict];
HMApp *app = [HMApp appWithDict:dict];
// 给模型对象中的属性赋值
// app.icon = dict[@"icon"];
// app.name = dict[@"name"];
// 把模型添加到数组
[arrM addObject:app];
}
// 把装有所有模型的数组赋值给我们的数组属性
_appes = arrM; } return _appes; }
@end

五、用xib自定义view

HMAppView.xib文件

 /*--------------------Model-------------------*/

 #import <Foundation/Foundation.h>
/** NSString block用copy
除了字符串和 block 控件 其它基本OC对象都用strong
weak 控件最好都用
assgin 基本数据类型
*/
@interface HMApp : NSObject
/** 应用图片 */
@property (nonatomic, copy) NSString *icon;
/** 应用名称 */
@property (nonatomic, copy) NSString *name; // id他instancetype有什么区别
// 1.相同点:他们都可以当方法的返回值
// 2.不同点:id可以来声明变量,id可以当参数类型,\
// id是一个万能指针,他在编译的时候不会确定真实的类型,只有在运行时候才知道真实类型
// instancetype在编译的时候就能确定他的返回值真实类型,这种更安全
//clang 3.5
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)appWithDict:(NSDictionary *)dict;
@end #import "HMApp.h" @implementation HMApp
- (instancetype)initWithDict:(NSDictionary *)dict {
if (self = [super init]) {
self.icon = dict[@"icon"];
self.name = dict[@"name"];
} return self;
} + (instancetype)appWithDict:(NSDictionary *)dict {
return [[self alloc] initWithDict:dict];
}
@end /*-----------------View---------------------*/
#import <UIKit/UIKit.h>
@class HMApp;
@interface HMAppView : UIView
// 把模型变成一个属性引用到自定义视图中
@property (nonatomic, strong) HMApp *app; + (instancetype)appView;
@end #import "HMAppView.h"
#import "HMApp.h" @interface HMAppView ()
/** 应用的图片 */
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
/** 应用的名称 */
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@end @implementation HMAppView
// 当点击下载按钮之后调用的方法
- (IBAction)downloadBtnClick:(UIButton *)downBtn {
NSLog(@"%ld----%@", self.tag ,self);
// 1.把按钮设置为禁用状态
downBtn.enabled = NO;
// 2.创建一个label
UILabel *downLabel = [[UILabel alloc] init];
downLabel.text = [NSString stringWithFormat:@"%@下载完成", self.app.name];
// 设置字体
downLabel.font = [UIFont systemFontOfSize:13.0];
// 设置文字居中
downLabel.textAlignment = NSTextAlignmentCenter;
// 设置label的文字颜色
downLabel.textColor = [UIColor redColor];
// 设置背景色
downLabel.backgroundColor = [UIColor blackColor];
// 设置bounds
downLabel.bounds = CGRectMake(, , , );
// 设置标签的位置在屏幕的中心
downLabel.center = self.superview.center;
// 把提示标签添加在控制器的view上
[self.superview addSubview:downLabel];
// 设置label透明度
downLabel.alpha = 0.0;
// 设置圆角半径
downLabel.layer.cornerRadius = ;
// 把超出边界的部分裁剪掉
downLabel.clipsToBounds = YES;
// downLabel.layer.masksToBounds = YES; //执行一个两秒中的动画,让标签慢慢的显示
[UIView animateWithDuration:2.0 animations:^{ // 表示要执行的动画代码
// 设置label的透明度
downLabel.alpha = 0.7;
} completion:^(BOOL finished) { // 表示动画执行完成之后要做得事情
// 上面的动画执行完成之后推迟2秒之后执行一个2秒的一个动画
[UIView animateWithDuration:2.0 delay:2.0 options:UIViewAnimationOptionCurveLinear animations:^{
// 设置label透明度
downLabel.alpha = 0.0;
} completion:^(BOOL finished) { // 动画执行完成之后把label从父控件中移除
// 把这个label从它的父控件中移除掉
[downLabel removeFromSuperview];
}];
}];
} + (instancetype)appView {
return [[[NSBundle mainBundle] loadNibNamed:@"HMAppView" owner:nil options:nil]lastObject];
}
// 重写模型属性的set方法,当外部给自定义视图的模型属性赋值时就会调用此方法,
- (void)setApp:(HMApp *)app {
#warning mark - 重写set方法一定要注意给属性下划线的成员变量赋值
_app = app;
// 1.设置应用图片
self.iconView.image = [UIImage imageNamed:app.icon];
// 2.设置应用名称
self.nameLabel.text = app.name; } @end /*-------------------Controller--------------*/
/**
xib和stroyboard的区别
1.相同点:都可以用来我们软件界面
2.不同点:在storyboard可以用来搭建整个应用的所有界面,最少也是一个界面
xib可以用来描述一个界面中的某一个部分,或一个应用的一个界面,及整个界面
*/
#import "ViewController.h"
#import "HMApp.h"
#import "HMAppView.h" @interface ViewController ()
/**
* 用来存放所有数据的数组
*/
@property (nonatomic, strong) NSArray *appes;
@end @implementation ViewController /**
* 控制器的view加载完成之后就会调用此方法
*/
- (void)viewDidLoad {
[super viewDidLoad];
// 格子之间的间距
CGFloat margin = ;
// // 格子的宽
// CGFloat appViewW = 100;
// // 格子的高
// CGFloat appViewH = 120;
// 一行中用三个格子
NSInteger column = ;
// 根据数据的个数来动画创建每一个应用
for (NSInteger i = ; i < self.appes.count; i++) { // 1.创建appView
HMAppView *appView = [HMAppView appView];
appView.tag = i;
// 2.取数组中每一个用来表示数据的模型对象
HMApp *app = self.appes[i];
// 3.给自定义视图传递模型
appView.app = app;
// 自定义视图的大小应该根据xib中的视图的大小来动态的设置而不应该直接固定死
// 4.拿到xib中appView的宽
CGFloat appViewW = appView.frame.size.width;
// xib中appView的高来表示我们一个视图的高
CGFloat appViewH = appView.frame.size.height;
// 最左边的间距 = (控制器view的宽 - 一行中所有格子的宽 - 格子间的间距 * (一行中格子的个数 - 1)) * 0.5
CGFloat leftMargin = (self.view.bounds.size.width - appViewW * column - (column - ) *margin) * 0.5;
// 头部间距
CGFloat topMargin = leftMargin;
// 计算列号
NSInteger col = i % column;
// 计算行号
NSInteger row = i / column;
// 3.设置frame
// 计算appViewX = 左边间距 + (appView宽 + 格子间距) *当前格子是在当前行中的第几个
CGFloat appViewX = leftMargin + (appViewW + margin) * col;
// appViewY = 顶部间距 + (appViewH + margin) * 当前格子在当前列中是第几个
CGFloat appViewY = topMargin + (appViewH + margin) * row; appView.frame = CGRectMake(appViewX, appViewY, appViewW, appViewH); // 4.添加到控制器的view中
[self.view addSubview:appView]; }
} #pragma mark - 懒加载
- (NSArray *)appes {
// 1.判断当前的数组属性是否为空,如果为空的时候再去加载数据
if (_appes == nil) {
// 2.获取plist文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
// 3.加载plist文件
NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; // 创建一个可变数据用来保存每一个模型对象(创建可变数组时并给其分配好容量)
NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:dictArr.count];
// 遍历字典数组把每一个字典转换成一个模型对象
for (NSDictionary *dict in dictArr) {
// 创建模型对象
// HMApp *app = [[HMApp alloc] initWithDict:dict];
HMApp *app = [HMApp appWithDict:dict];
// 给模型对象中的属性赋值
// app.icon = dict[@"icon"];
// app.name = dict[@"name"];
// 把模型添加到数组
[arrM addObject:app];
}
// 把装有所有模型的数组赋值给我们的数组属性
_appes = arrM; } return _appes; } /** 用xib来自定义一个视图的步骤
1.创建一个xib文件用来描述我们局部界面(并在里面摆放好所有的子控件,并设置好它们的属性)
2.创建一个类来和我们的xib文件进行关联(这个类也是用来管理我们的xib文件,创建的自定义类的类名最好和我们xib的文件名称一样)(创建的类它要继承至什么类,取决于xib文件中最顶层控件的类型)
3.指定xib中class类型,如果不指定创建出来的xib和我们的自定义类没有任何关系
4.把需要修改或需要设置的控件连线到我们自定义类.m中
5.在自定义view类的.h文件引入模型,就是把模型当成一个属性定义在我们的自定义view类中
6.重写模型属性set方法,当外部给这个模型属性赋值的时候就会调用模型属性的set方法,我们在重写的模型属性的set方法中给自定义视图的子控件去设置数据 */ @end

补充说明

View的封装思路

(1) 如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部子控件的创建屏蔽起来,不让外界关心

(2) 外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应的数据

mvc机制简单说明

说明:

(1)在开发过程中,作为控制器处理的量级应该很轻,不该操心的不操心。协调好模型和视图就ok了,要学会当一个好老板。

(2)三个部分各司其职,数据模型只负责数据的处理,视图部分只负责把拿到的数据进行显示,两个部分都是被动的,等待着大管家控制器的调遣。

(3)在OC中,如果视图和数据模型之间有通道,那控制器是否处于失控状态呢?

1.MVC是一种设计思想,贯穿于整个iOS开发中,需要积累一定的项目经验,才能深刻体会其中的含义和好处
  MVC中的三个角色
  M:Model,模型数据
  V:View,视图(界面)
  C:Control,控制中心
 
2.MVC的几个明显的特征和体现:
 View上面显示什么东西,取决于Model
 只要Model数据改了,View的显示状态会跟着更改
 Control负责初始化Model,并将Model传递给View去解析展示

iOS UI-九宫格的更多相关文章

  1. [IOS]IOS UI指南

    [IOS]IOS UI指南 众所周知,IOS的界面设计,越来越流行,可以说都形成了一个标准,搜集了一些资料,供自己以后学习使用! iOS Human Interface Guidelines (中文翻 ...

  2. IOS UI 第八篇:基本UI

    实现图片的滚动,并且自动停止在每张图片上     - (void)viewDidLoad{    [super viewDidLoad]; UIScrollView *scrollView = [[U ...

  3. 国外IOS UI指南

    国外IOS UI指南 众所周知,IOS的界面设计,越来越流行,可以说都形成了一个标准,搜集了一些资料,供自己以后学习使用! iOS Human Interface Guidelines (中文翻译) ...

  4. iOS UI的几种模式

    iOS UI的几种模式: 1.平凡模式(原生控件组合): 2.新闻模式: 3.播放器模式: 4.微博模式:

  5. 通过实现一个TableView来理解iOS UI编程

    推荐一篇神作: 通过实现一个TableView来理解iOS UI编程 http://blog.jobbole.com/61101/

  6. iOS masonry九宫格 单行 多行布局

    Masonry是个好东西,在当前尺寸各异的iOS开发适配中发挥着至关重要的作用,由于项目中Masonry布局用的比较多,对于UI布局也有了一些自己的理解,经常会有人问道Masonry布局九宫格要怎么布 ...

  7. [iOS UI设计笔记整理汇总]

    8.UIsearchbar放到Navigationbar 上(意思是建个View作为titleview) //此处调用的是第三方封装的SearchBar,也可以自定义. self.searchBarW ...

  8. iOS UI高级之网络编程(HTTP协议)

    HTTP协议的概念 HTTP协议,Hyper Text Transfer Protocol (超文本传输协议)是用于从万维网服务器传送超文本到本地浏览器的传输协议,HTTP是一个应用层协议,由请求和响 ...

  9. iOS - UI - UIWebView

    1.UIWebView UIWebView 是 苹果提供的用来展示网页的UI控件.它也是最占内存的控件. iOS8.0 webkit框架. WKWebView,相比UIWebView,节省了1/3~1 ...

  10. [iOS UI进阶 - 0] Quiartz2D

    A.简介 1. 需要掌握的 drawRect:方法的使用 常见图形的绘制:线条.多边形.圆 绘图状态的设置:文字颜色.线宽等 图形上下文状态的保存与恢复 图形上下文栈 1.基本图形绘制* 线段(线宽. ...

随机推荐

  1. MHA集群(gtid复制)和vip漂移

    在上一片博客中,讲述了怎么去配置MHA架构!这片博客不再细说,只说明其中MySQL主从搭建,这里使用的是gtid加上半同步复制! 步骤与上一片博客一样,不同之处在于MySQL主从的搭建!详细的gtid ...

  2. 根据wsdl文件,Web工程自动生成webservice客户端调用

    根据wsdl文件,Web工程自动生成webservice客户端调用 1,工具:带有webservice插件的eclips 2,步骤: (1),新建一个Web工程:WSDLTest (2),浏览器访问W ...

  3. c++标准库多线程入门

    从c++ 11开始,语言核心和标准库开始引入了对多线程的原生支持.如下所示: int doSth(char c) { default_random_engine dre(c); uniform_int ...

  4. 更换 nodejs npm 镜像为 淘宝 镜像

    淘宝npm镜像官方介绍文档:https://npm.taobao.org/ ,使用命令在这个官方文档里查询. 安装工具cnpm: $ npm install -g cnpm --registry=ht ...

  5. java在访问https资源时的证书信任问题

    java程序在访问https资源时,出现报错 sun.security.validator.ValidatorException: PKIX path building failed: sun.sec ...

  6. React 回忆录(四)React 中的状态管理

    Hi 各位,欢迎来到 React 回忆录!

  7. cmd命令安装、卸载、启动和停止Windows Servic

    1.运行--〉cmd:打开cmd命令框 2.在命令行里定位到InstallUtil.exe所在的位置 InstallUtil.exe 默认的安装位置是在C:/Windows/Microsoft.NET ...

  8. shell下如何删除文件的某一列

    答:cat file | awk '{$1=null;print $0}' (删除第一列)

  9. OI无关--关于侧边栏

    自己在比较闲的时候学了一点html和js,大概能写一些比较简单的东西了,于是就动起了侧边栏的念头. 如果能在博客里加一个题目快速跳转也很兹磁啊. 首先要选择题目,oj的名字肯定是不能直接输入,因为还有 ...

  10. (转)Nuts and Bolts of Applying Deep Learning

    Kevin Zakka's Blog About Nuts and Bolts of Applying Deep Learning Sep 26, 2016 This weekend was very ...