文章目录
第一步:建立商品模型
GZGoods.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface CZGoods : NSObject
@property (nonatomic,copy)NSString *buyCount;
@property (nonatomic,copy)NSString *price;
@property (nonatomic,copy)NSString *title;
@property (nonatomic,copy)NSString *icon;
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)goodsWithDict:(NSDictionary *)dict;
@end
NS_ASSUME_NONNULL_END
CZGoods.m
#import "CZGoods.h"
@implementation CZGoods
- (instancetype)initWithDict:(NSDictionary *)dict
{
if(self = [super init]){
//把字典中的键对应的每一个值取出来放到了self中
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
+ (instancetype)goodsWithDict:(NSDictionary *)dict
{
return [[self alloc]initWithDict:dict];
}
@end
第二步:懒加载数据
在控制器ViewController.m中
ViewController.m
#import "ViewController.h"
#import "CZGoods.h"
@interface ViewController ()
//用来存储所有的团购商品的数据
@property (nonatomic,strong) NSArray *goods;
@end
@implementation ViewController
//懒加载数据
#pragma mark -懒加载数据
- (NSArray *)goods
{
if(_goods == nil){
NSString *path = [[NSBundle mainBundle]
pathForResource:@"tgs.plist" ofType:nil];
//加载成一个字典的数组
NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
//把字典转模型
NSMutableArray *arrayModels = [NSMutableArray array];
//遍历
for(NSDictionary *dict in arrayDict){
CZGoods *model = [CZGoods goodsWithDict:dict];
[arrayModels addObject:model];
}
_goods = arrayModels;
}
return _goods;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
@end
第三步:拉一个UITableView
设置数据源,拖到View Controller
所以这个类需要遵守< UITableViewDataSource>这个协议
#import "ViewController.h"
#import "CZGoods.h"
@interface ViewController ()<UITableViewDataSource>
第四步:在这个类里面实现数据源方法
把模型数据设置给单元格时候,需要cell.XXX和model.XXX都要知道,是个小缺点哦。控制器知道的太多了,获取太多单元格内部信息。当前的cell封装的不够完整
//数据源方法
#pragma mark -数据源方法
//因为只有一组,所以下面这个方法可以不写
//-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
//{
// return 1;
//}
//goods有多少个对象就是多少个数据
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.goods.count;
}
//每一行显示单元格,返回值类型是UITableViewCell类型
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//1、获取模型数据,拿到第几行数据,就是第几个模型
CZGoods *model = self.goods[indexPath.row];
//2、创建单元格
//先创建一个ID,再根据ID去取,有的话直接取,没有的话要创建。因为是要重用的。
static NSString *ID = @"goods_cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if(cell == nil){
//创建单元格
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
//3、把模型数据设置给单元格
cell.imageView.image = [UIImage imageNamed:model.icon];
cell.textLabel.text = model.title;
//价格之前有符号,因此要拼接字符串
//数字:cell.detailTextLabel.text = model.price;
//拼接¥:cell.detailTextLabel.text = [NSString stringWithFormat:@"¥ %@",model.price];
//一个单元格默认只有这三个控件了。,要实现第四个控件只能进行拼接啦
cell.detailTextLabel.text = [NSString stringWithFormat:@"¥ %@ %@人已购买",model.price,model.buyCount];
//4、返回单元格
return cell;
}
第五步:隐藏状态栏
//隐藏状态栏
#pragma mark -隐藏状态栏
- (BOOL)prefersStatusBarHidden
{
return YES;
}
第六步:调整细节,创建xib
想实现价格和几人已购买颜色设置不同,位置对齐。
如果仅仅还是使用同一个标签的话,就比较难实现了,因此从单元格下手吧!自带的单元格就不够用了,可以自定义单元格,重新进行创建单元格,使用xib来描述一个单元格。
1、在Views里面建立一个空的xib
2、在这个xib中,只需要拖单元格就可以啦,拖好单元格、标签,就可以设置大小颜色等
3、样式摆好了,接下来一定会使用代码来设置xib的这几个字控件的数据,所以需要通过拖线用一些属性来引用这些数据,来通过属性访问控件。
拖线的话,默认是UITableViewCell类的对象,但是是不能向这个系统的类里面添加属性,拖线的,因此使用xib,要配合建一个类,描述这个单元格的类。需要自定义一个类,继承UITableViewCell,把自己的类名写在这里。
4、建一个类:CZGoodsCell
Subclass of:UITableViewCell
5、因为这个cell里面没有类拓展,所以没法子拖。
所以写上interface
@interface CZGoodsCell()
6、拖线
依次拖好,如下:
第七步:以xib的形式创建单元格
加载xib,mainBundle是安装在手机根目录,在这里找到xib.这里loadNibNamed返回的数组类型,因为多个字控件,因为目前只有一个子控件,所以使用firstObject拿到第一个就ok啦
CZGoodsCell *cell = [[[NSBundle mainBundle] loadNibNamed:@"CZGoodsCell" owner:nil options:nil]firstObject];
这里也要实现重用哦
//2、通过xib的方式创建单元格
static NSString *ID = @"goods_cell";
CZGoodsCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if(cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:@"CZGoodsCell" owner:nil options:nil] firstObject];
}
但是新建的时候,没有设置可重用ID,要在这里设置一下!!
这里面其实也可以稍微改进一下下哦
在自定义的cell中封装一个类方法,通过这个类方法创建一个单元格
所以也封装到xib中就可以啦
(1)在CZGoodsCell.h中
//封装一个创建自定义cell的方法
+ (instancetype)goodsCell;
(2)在CZGoodsCell.m中
+ (instancetype)goodsCell
{
static NSString *ID = @"goods_cell";
CZGoodsCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if(cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:@"CZGoodsCell" owner:nil options:nil] firstObject];
}
}
但是这里面的tableView是不存在的
所以要在封装一个创建自定义cell的方法这里加上去
+ (instancetype)goodsCellWithTableView:(UITableView *)tableView;
+ (instancetype)goodsCellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"goods_cell";
CZGoodsCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if(cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:@"CZGoodsCell" owner:nil options:nil] firstObject];
}
return cell;
}
这个时候,创建单元格可以直接通过
//2、通过xib的方式创建单元格
CZGoodsCell *cell = [CZGoodsCell goodsCellWithTableView:tableView];;
第八步:把模型数据设置给单元格
在控制器中直接给cell的每个子控件赋值数据造成的问题
1、控制器强依赖于Cell,一旦cell内部的子控件发生了变化,那么控制器中的代码也得改,这就造成了紧耦合
2、cell的封装不够完整,凡是用到这个cell的地方,每次都要编写为cell的子控件依次赋值的语句,比如cell.xxx = model.title
3、解决:直接把模型传递给自定义Cell,然后在自定义cell内部解析model中的数据赋值给自定义的cell内部的子控件
//3、把模型数据设置给单元格
cell.goods = model;
把模型直接赋值给goods属性,goods拿到之后需要重新解析
自定义单元格中加入这个属性
需要重新goods的set方法
// CZGoodsCell.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class CZGoods;
@interface CZGoodsCell : UITableViewCell
@property(nonatomic,strong) CZGoods *goods;
@end
NS_ASSUME_NONNULL_END
在CZGoodsCell.m中写出set方法
- (void)setGoods:(CZGoods *)goods
{
_goods = goods;
//把模型的数据设置给子控件
self.imgViewicon.image = [UIImage imageNamed:goods.icon];
self.lblTitle.text = goods.title;
self.lblPrice.text = [NSString stringWithFormat:@"¥ %@",goods.price];
self.lblBuyCount.text = [NSString stringWithFormat:@"%@人已购买 ",goods.buyCount];
}
第九步:小结
所以,这样写下来,自定义cell四句话就搞定啦
//每一行显示单元格,返回值类型是UITableViewCell类型
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//1、获取模型数据,拿到第几行数据,就是第几个模型
CZGoods *model = self.goods[indexPath.row];
//2、通过xib的方式创建单元格
CZGoodsCell *cell = [CZGoodsCell goodsCellWithTableView:tableView];
//3、把模型数据设置给单元格
cell.goods = model;
//4、返回单元格
return cell;
}
通过xib方式实现自定义cell
1、创建一个xib文件
2、在xib中拖一个UITableViewCell设置号高度宽度
3、向UITableViewCell中拖子控件
4、新建一个自定义的UITableViewCell类与xib中的这个cell相关联
新建一个类继承自UITableViewCell
通过拖线的方式将cell中的子控件拖到这个类的属性上,方便后续使用
5、改造数据源方法:cellForRowAtIndex中的创建cell的代码,通过加载xib的方式来创建cell
UITableViewCell *cell = [[[NSBundle mainBundle] loadNibNamed:@"CZGoodsCell" owner:nil options:nil] firstObject];
为了可以重用xib中的Cell,所以要设置xib中的cell
的identifier,这个identifier就是将来的可重用ID
6、设置cell中的子控件的数据
在外部访问不到cell中的子控件的内容,解决方法:把模型数据传递给cell对象,由cell对象内部自己来解析模型数据,并把数据设置到对应的子控件中
在自定义cell的类中创建一个模型类型的属性,重写该属性的set方法,在set方法中将数据赋值给控件
7、完成数据列表的显示,运行可看到效果