第一节课:
.复习
.运行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. P4289 [HAOI2008]移动玩具(bfs)

    P4289 [HAOI2008]移动玩具 双向bfs+状态压缩+记忆化搜索 双向bfs用于对bfs的优化,每次找到可扩展节点少的一边进行一次bfs,找到的第一个互相接触的点即为最短路径 矩阵范围仅4* ...

  2. Python3 解决 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

    Python3 解决 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte 一.问题 request.Reque ...

  3. http://bugs.mysql.com/bug.php?id=72123

    今天某个环境发生了这个bug. http://bugs.mysql.com/bug.php?id=72123

  4. linux不常用但很有用的命令(持续完善)

    Linux登录后设置提示信息: /etc/issue 本地端登录前显示信息文件 /etc/issue.net 网络端登录前显示信息文件 /etc/motd 登陆后显示信息文件 可以添加以下几个常用选项 ...

  5. AP聚类算法

    一.算法简介 Affinity Propagation聚类算法简称AP,是一个在07年发表在Science上的聚类算法.它实际属于message-passing algorithms的一种.算法的基本 ...

  6. Xcode基本设置系列和Xcode报错解决方案

    1, arc机制中调用非arc文件. Xcode——>Project->Build Phases,将需要非arc文件更改为:"-fno-objc-arc"   ,该参数 ...

  7. 论文笔记——PRUNING FILTERS FOR EFFICIENT CONVNETS

    论文地址:https://arxiv.org/abs/1608.08710 主要思想 这篇文章主要讲了对filters的裁剪,裁剪方法是计算L1范数,然后裁剪掉较少的,多少取决于加速比. 实现效果 V ...

  8. 1、webpack编译打包Sass编译的css进js文件

    cnpm install css-loader --save-dev    //css-loader 是将css打包进js cnpm install style-loader --save-dev   ...

  9. 创建标签等操作DOM的原生js API

    ()创建新节点 createDocumentFragment() //创建一个DOM片段 createElement() //创建一个具体的元素 createTextNode() //创建一个文本节点 ...

  10. Codeforces Round #289 (Div. 2, ACM ICPC Rules) E. Pretty Song 算贡献+前缀和

    E. Pretty Song time limit per test 1 second memory limit per test 256 megabytes input standard input ...