本分享是iOS开发中有趣的UI模块的相关内容技术点分享。如果您是一位已经有C基础了的iOS爱好者,但还未接触Objectiov C语言,您需要学习我之前分享的 iOS开发核心语言Objective C 系列
如果您是零基础,建议您从我之前分享的iOS开发分分钟搞定C语言 系列开始学习。另外将无偿分享自己整理出来的大概400G iOS学习视频及学习资料,都是干货哦!可以新浪微博私信➕关注 极客James,期待与您的共同学习和探讨!!由于时间有限,每天在工作之余整理的学习分享,难免有不足之处,也希望各路大神指正!
在上一篇iOS开发之有趣的UI —— 基础控件与经典案例中已经对基本控件进行了详细的介绍并且简单的做了一个购物车的项目,但是这个项目还有待完善,里面还有很多非常实用技术点和设计思想,所以本次分享将从以下几个方面进行分享。
made by 极客James
一、plist文件
1.在学习UI控件的时候要时刻掌握这三个基本要素:
(1)创建对象
(2)给对象设置属性,大小,颜色,尺寸等
(3)给对象加数据
上面两点在上一篇的分享中都已经做了详细的分享,今天主要是对第三点给对象加数据进行分享。
2.数据存取
在iOS开发中通常数据存取有两种方式:一种是本地数据,一种是网络数据,本地数据是存取在plist中,而网络数据是存储在服务器需要通过json进行解析获取,今天主要分享本地数据的存取。
3.plist数据
(1)创建一个plist文件
(2)在plist中写数据
(3)将建好的的plist数据通过以下代码导入到文件中
NSArray *dictArray =[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"shops" ofType:@"plist"]];
// 仅仅是加载plist文件的代码块
二、数据转模型
通过自己创建一个plist文件进行了本地数据的存取才是第一步,要想让对象拿到数据最好的办法是将数据转换成模型进行使用,这样不仅效率高还不容易出错。
数据转模型思路:
1.建立一个主要来处理数据的模型文件
2.在创建好的模型文件.h中拿到plist里面所有的元素,并且提供一种自定义对象方法,一种构造类方法来初始化字典。
3.在模型文件的.m中进行自定义对象方法和构造类方法的方法实现,主要目的是将字典里面的数据取出来给模型,把数据封装为对象的方式供用户使用。
4.在viewController文件中懒加载数据,并且将plist数据通过已构造好的方法进行转化为模型。
5.在需要用到的地方,直接用对象方法或者类方法进行调用。
数据转模型代码实现:
1.创建了模型文件ZJShopModel
2.在ZJShopModel.h文件中拿到plist中的元素并且自定义初始化
// 注意:plist中有多少个属性,这里就要写多少个
// 商品名称
@property (nonatomic,strong)NSString *name;
// 商品图标
@property (nonatomic,strong)NSString *icon;
// 自定义对象方法的初始化
- (instancetype)initWithDict:(NSDictionary *)dict;
// 自定义构造类方法的初始化
+ (instancetype)shopWithDict:(NSDictionary *)dict;
3.在ZJShopModel.m文件中进行声明的实现
// 自定义对象方法的实现
- (instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
// 可以通过KVC的方式直接赋值
// KVC方法 [self setValuesForKeysWithDictionary:dict];
self.name = dict[@"name"];
self.icon = dict[@"icon"];
}
return self;
}
// 自定义构造类方法的实现
+ (instancetype)shopWithDict:(NSDictionary *)dict{
return [[self alloc] initWithDict:dict];
}
4.在viewController文件中进行数据的懒加载
(1)首先要声明一个数组
@property (strong,nonatomic)NSArray *shop;
(2)对数组进行懒加载和plist数据的模型转化需要导入模型头文件
- (NSArray *)shop{
if (_shop == nil) {
// 加载plist文件
NSArray *dictArray =[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"shops" ofType:@"plist"]];
// 创建一个可变的空数组
NSMutableArray *shopArray = [NSMutableArray array];
// 遍历字典
for (NSDictionary *dict in dictArray) {
// 取出字典内容给模型
ZJShopModel *shop = [ZJShopModel shopWithDict:dict];
// 将转换好的数据赋给可变数组
[shopArray addObject:shop];
}
_shop = shopArray;
}
return _shop;
}
5.在需要的地方进行调用
// 获得index位置对应的商品数据
ZJShopModel *shops = self.shop[index];
以上是plist数据转模型的最好方法,可以达到数据的独立管理和方便调用,在iOS开发中非常重要。
三、抽取和封装思想
在iOS开发中,封装和抽取思想无处不在,掌握这种思想有利用高效开发,有利于团队合作,有利于程序扩展,所以重要性我不在阐述,直接上代码。
在编写代码的时候,总会遇到重复代码的情况,那么做好的办法就是将相同的代码进行抽取,然后在分析不同之处,用传参数的方法来解决不同,下面就来以购物车为例来分析抽取和封装思想。
分析:
1.增加按钮需要的相关属性:
(1)图片显示状态:Normal Highlighted Disabled
(2)按钮的位置
(3)点击事件
2.删除按钮需要的相关属性
(1)图片显示状态:Normal Highlighted Disabled
(2)按钮的位置
(3)点击事件
3.显示图片和描述的相关属性
(1)图片
(2)文字
(3)位置
通过分析我们可以得出删除按钮和增加按钮具有一样的属性,只不过属性间的内容不同,所以我们要把他们公共拥有的属性继续抽取并给不同的属性进行传值操作。
删除按钮和增加按钮的方法封装:
//将增加和删除按钮相同共同属性进行抽取和封装
- (UIButton *)addButtonWithImage:(NSString *)image hightImage:(NSString *)hightImage disableImage:(NSString *)disableImage frame:(CGRect)frame action:(SEL)action{
// 初始化创建按钮对象
UIButton *btn = [[UIButton alloc]init];
// 设置按钮背景图片 Normal状态
[btn setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
// 设置按钮背景图片 Highlighted状态
[btn setBackgroundImage:[UIImage imageNamed:hightImage] forState:UIControlStateHighlighted];
// 设置按钮背景图片 Disabled状态
[btn setBackgroundImage:[UIImage imageNamed:disableImage] forState:UIControlStateDisabled];
// 设置尺寸
btn.frame = frame;
// 监听按钮点击
[btn addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
// 将按钮增加到视图上
[self.view addSubview:btn];
return btn;
}
抽取和封装了增加按钮和删除按钮的方法,在用的时候直接调用即可。
- (void)viewDidLoad {
[super viewDidLoad];
// 增加按钮
self.addBtn = [self addButtonWithImage:@"add" hightImage:@"add_highlighted"disableImage:@"add_disabled" frame:CGRectMake(30, 30, 50, 50) action:@selector(add)];
// 删除按钮
self.removeBtn = [self addButtonWithImage:@"remove" hightImage:@"remove_highlighted"
disableImage:@"remove_disabled" frame:CGRectMake(270, 30, 50, 50) action:@selector(remove)];
}
四、自定义控件
显示物品模块的分析和封装
物品的显示模块是一个九宫格显示模式,有关九宫格显示计算可以翻阅我的上一篇分享。那么下面就来分享下显示物品模块的相关内容。
(1)shopView用来存放物品的视图
’
’
(2)在shopView上显示的九宫格
’
’
(3)在九宫格上添加数据
以上就是购物车物品显示模块的完整过程,从中我们可以显而易见的看出,每个格子大小宽度都一样,就是内容不同而已,所以我们可以采用封装的思想进行编码。
代码实现过程分析:
(1)通过九宫格算法先布局好界面
(2)创建一个ZJshopView文件专门管理九宫格显示的视图内容
(3)在ZJshopView中创建一个九宫格显示的UIImageView以及UILabel和相关属性,最好是通过对象方法或类方法在创建的时候就让它显示,也就是要自定义View重写init方法等。
(4)将plist转换的模型数据导入到视图中
(5)在需要的地方进行调用
代码实现过程:
1.九宫格算法布局界面
// 设置每个商品的尺寸
CGFloat shopW = 80;
CGFloat shopH = 90;
// 设置显示的列数
int cols = 3;
// 设置每一列之间的间距
CGFloat colMargin = (self.shopView.frame.size.width - cols * shopW) / (cols -1);
// 设置每一行之间的间距
CGFloat rowMargin = 10;
// 创建一个父控件(用来存放图片和文字)
UIView *shopView = [[UIView alloc]init];
shopView.backgroundColor = [UIColor redColor];
// 商品的索引
NSUInteger index = self.shopView.subviews.count;
// 商品的x值(取余运算,将算出商品在第几列)
NSUInteger col = index % cols;
CGFloat shopX = col * (shopW + colMargin);
// 商品的y值(除法运算,将算出商品在第几行)
NSUInteger row = index / cols;
CGFloat shopY = row * (shopH + rowMargin);
shopView.frame = CGRectMake(shopX, shopY, shopW, shopH);
// 将九宫格添加到视图上
[self.shopView addSubview:shopView];
2.创建ZJshopView来专门管九宫格视图内容
ZJshopView.h文件中
注意:在自定义初始化init方法之前系统会自动调用initWithFrame方法,所以为了严谨起见最好自定义初始化initWithFrame,达到初始化时第一个就调用且只调用一次的效果。
@interface ZJshopView ()
@property (nonatomic,weak) UIImageView *iconView;
@property (nonatomic , weak)UILabel *label;
@end
@implementation ZJShopView
// 自定义view 初始化initWithFrame
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]){
UIImageView *iconView = [[UIImageView alloc]init];
[self addSubview:iconView];
// 添加文字
UILabel *label = [[UILabel alloc]init];
label.font = [UIFont systemFontOfSize:11];
label.textAlignment = NSTextAlignmentCenter;
[self addSubview:label];
}
return self;
}
3.设置九宫格里面显示图片和文字的位置
注意:在重写layoutSubviews方法时一定要先调用父类也就是[super layoutSubviews];
- (void)layoutSubviews{
[super layoutSubviews];
CGFloat showH = self.frame.size.height;
CGFloat showW = self.frame.size.width;
self.iconView.frame = CGRectMake(0, 0, showW, showH);
self.label.frame = CGRectMake(0, showW, showW, showH - showW);
}
4.模型数据导入到九宫格内容的视图中
实现思路:
九宫格的视图现在独立在ZJshopView中,而数据我也已经通过数据转模型的方式独立到一个ZJShopModel文件中了,那么现在要给视图给数据,显而易见就是要让模型中的数据赋给视图的相应位置中。要想让数据模型的数据给视图那么就要用到set方法。
代码实现过程:
(1)将ZJShopModel.h导入到ZJshopView.m中,然后在ZJshopView.h中拿到ZJShopModel中的属性也就是要@class ZJShopModel;
(2)在ZJshopView.m中声明视图需要用到的属性,并且赋给视图所用到的属性,两个属性名字最好相同
// 类扩展以下两个对象
@property (nonatomic , weak)UILabel *label;
@property (nonatomic , weak)UIImageView *iconView;
// 将声明的对象赋给视图的中的对象
self.iconView = iconView;
self.label =label;
(3)重写set方法:将模型中的数据赋给视图中的属性
- (void)setShop:(ZJShopModel *)shop{
_shop = shop;
self.iconView.image = [UIImage imageNamed:shop.icon];
self.label.text = shop.name;
}
5.在需要的时候直接创建对象,在初始化的时候获得所需要的所有属性,达到封装的目的,一切OK.
// 在适当的位置掉用以下方法就会创建九宫格的位置以及属性
ZJShopModel *shopView = [[ZJShopModel alloc]init];
// 在适当的位置掉用以下方法就会将数据给九宫格中的视图
shopView.shop = self.shop[index];
五、xib自定义控件
xib是一种轻量级UI可视化设计工具,适用场景为在项目中需要将好多UI控件显示到同一个视图上或者相同的视图具有同样的属性只是位置不同。
上面分析的购物车符合用xib方式来创建的应用场景,下面就来分析下如何采用xib的方式来实现纯代码实现的效果。
1.创建xib
’
’
2.给xib命名为ZJShopView
’
3.创建ZJShopView工程文件并继承UIView
4.让xib继承ZJShopView,并且给xib设置视图属性
5.将xib中的控件和ZJShopView建立关系
6.在ZJShopView.h中导入数据模型通过set方法进行数据的传递
@class ZJShopmodel;
@interface ZJShopView : UIView
// 商品模型
@property (nonatomic, strong) ZJShopmodel *shop;
+ (instancetype)shopViewWithShop:(ZJShopmodel *)shop;
7.在ZJShopView.m中进行xib视图的加载和set方法实现
+ (instancetype)shopViewWithShop:(ZJShopmodel *)shop
{
// 加载xib
ZJShopView *shopView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
shopView.shop = shop;
return shopView;
}
set方法的实现
- (void)setShop:(ZJShopmodel *)shop
{
_shop = shop;
self.iconView.image = [UIImage imageNamed:shop.icon];
self.nameLabel.text = shop.name;
}
通过xib的方法会很快捷的创建出九宫格显示视图的内容,不用在设置九宫格内容的尺寸等属性。
六、MVC设计模式
以下是苹果官方对MVC的定义和解释
翻译:
对于任何 iOS 应用程序而言,模型-视图-控制器 (MVC) 都是一个优秀设计的关键所在。MVC 会将应用程序中的对象分配给以下三种角色中的一种:模型、视图或者控制器。在这种模式中,模型会记录应用程序的数据,视图会显示用户界面并构成应用程序的内容,而控制器则会管理您的视图。通过响应用户的操作并使用内容填充视图,控制器充当了模型和视图二者之间通信的通道。
通过官方的翻译想必您已经领悟了其中的精髓所在,本篇分享中也同样用到了MVC的设计模式和思想,例如本次分享的购物车案例。
M:ZJShopModel 数据模型
V:ZJShopView 视图模型
C:viewController 大管家 视图控制器
通过这种设计模式能够很明显的感受到开发效率的提升,分模块进行编码,然后通过视图控制器来进行调度,有利于程序的扩展性和易读性。
在开发中也提倡通过MVC的设计模式去开发。