一、纯代码自定义等高cell
首先创建一个继承UITableViewCell的类
@interface XMGTgCell : UITableViewCell
在该类中依次做一下操作
1.添加子控件
1 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 2 { 3 if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 4 // 图片 5 UIImageView *iconImageView = [[UIImageView alloc] init]; 6 [self.contentView addSubview:iconImageView]; 7 self.iconImageView = iconImageView; 8 9 // 标题 10 UILabel *titleLabel = [[UILabel alloc] init]; 11 [self.contentView addSubview:titleLabel]; 12 self.titleLabel = titleLabel; 13 14 // 价格 15 UILabel *priceLabel = [[UILabel alloc] init]; 16 [self.contentView addSubview:priceLabel]; 17 self.priceLabel = priceLabel; 18 19 // 购买数 20 UILabel *buyCountLabel = [[UILabel alloc] init]; 21 [self.contentView addSubview:buyCountLabel]; 22 self.buyCountLabel = buyCountLabel; 23 } 24 return self; 25 }
2.布局子控件
/**
* 需要注意的是通过initWithStyle:创建cell,就不会调用下面这个方法
* - (instancetype)initWithFrame:(CGRect)frame;
* 那么可以在layoutSubviews中计算所有子控件的frame
* 需求:图片与lable之间,lable与屏幕的margin都是10(加配图)
*/
1 - (void)layoutSubviews 2 { 3 [super layoutSubviews]; 4 5 CGFloat margin = 10; 6 CGFloat contentH = self.contentView.frame.size.height; 7 CGFloat contentW = self.contentView.frame.size.width; 8 9 // 图片 10 CGFloat iconX = margin; 11 CGFloat iconY = margin; 12 CGFloat iconW = 80; 13 CGFloat iconH = contentH - 2 * iconY; 14 self.iconImageView.frame = CGRectMake(iconX, iconY, iconW, iconH); 15 16 // 标题 17 CGFloat titleX = iconX + iconW + margin; 18 CGFloat titleY = iconY; 19 CGFloat titleW = contentW - titleX - margin; 20 CGFloat titleH = 20; 21 self.titleLabel.frame = CGRectMake(titleX, titleY, titleW, titleH); 22 23 // 价格 24 CGFloat priceX = titleX; 25 CGFloat priceH = 15; 26 CGFloat priceY = iconY + iconH - priceH; 27 CGFloat priceW = 100; 28 self.priceLabel.frame = CGRectMake(priceX, priceY, priceW, priceH); 29 30 // 购买数 31 CGFloat buyCountW = 150; 32 CGFloat buyCountH = 13; 33 CGFloat buyCountX = contentW - margin - buyCountW; 34 CGFloat buyCountY = iconY + iconH - buyCountH; 35 self.buyCountLabel.frame = CGRectMake(buyCountX, buyCountY, buyCountW, buyCountH); 36 }
3.设置子控件数据
在设置数据之前,我们可以创建一个TG类,用于保存每一个cell的数据,这就是典型的数据转模型,在前面也有介绍过,比如我们的数据是这样的
实现代码:
1 /******************* XMGTg.h *******************/ 2 #import <Foundation/Foundation.h> 3 4 @interface XMGTg : NSObject 5 /** 标题 */ 6 @property (nonatomic, copy) NSString *title; 7 /** 购买数 */ 8 @property (nonatomic, copy) NSString *buyCount; 9 /** 图片 */ 10 @property (nonatomic, copy) NSString *icon; 11 /** 价格 */ 12 @property (nonatomic, copy) NSString *price; 13 14 + (instancetype)tgWithDict:(NSDictionary *)dict; 15 @end 16 17 /******************* XMGTg.m *******************/ 18 #import "XMGTg.h" 19 20 @implementation XMGTg 21 + (instancetype)tgWithDict:(NSDictionary *)dict 22 { 23 XMGTg *tg = [[self alloc] init]; 24 [tg setValuesForKeysWithDictionary:dict]; 25 return tg; 26 } 27 @end 28 29 /******************* XMGTgCell *******************/ 30 #import <UIKit/UIKit.h> 31 @class XMGTg; 32 33 @interface XMGTgCell : UITableViewCell 34 /** 团购模型数据 */ 35 @property (nonatomic, strong) XMGTg *tg; 36 @end 37 38 // 那么重写tg的setter方法就可以设置数据了 39 - (void)setTg:(XMGTg *)tg 40 { 41 _tg = tg; 42 43 self.iconImageView.image = [UIImage imageNamed:tg.icon]; 44 self.titleLabel.text = tg.title; 45 self.priceLabel.text = [NSString stringWithFormat:@"¥%@", tg.price]; 46 self.buyCountLabel.text = [NSString stringWithFormat:@"%@人已购买", tg.buyCount]; 47 }
二、Autolayout布局子控件(Masonry)
在布局控件时我们可以使用三方框架,Masonry
那么我么可以直接把创建子控件以及布局控件全部写在
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
这个方法中
1 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 2 { 3 if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 4 CGFloat margin = 10; 5 6 // 图片 7 UIImageView *iconImageView = [[UIImageView alloc] init]; 8 [self.contentView addSubview:iconImageView]; 9 self.iconImageView = iconImageView; 10 11 [iconImageView makeConstraints:^(MASConstraintMaker *make) { 12 make.left.top.equalTo(self.contentView).offset(margin); 13 make.bottom.equalTo(self.contentView).offset(-margin); 14 make.width.equalTo(80); 15 }]; 16 17 // 标题 18 UILabel *titleLabel = [[UILabel alloc] init]; 19 [self.contentView addSubview:titleLabel]; 20 self.titleLabel = titleLabel; 21 22 [titleLabel makeConstraints:^(MASConstraintMaker *make) { 23 make.top.equalTo(iconImageView); 24 make.left.equalTo(iconImageView.right).offset(margin); 25 make.height.equalTo(20); 26 make.right.equalTo(self.contentView).offset(-margin); 27 }]; 28 29 // 价格 30 UILabel *priceLabel = [[UILabel alloc] init]; 31 priceLabel.font = [UIFont systemFontOfSize:15]; 32 priceLabel.textColor = [UIColor orangeColor]; 33 [self.contentView addSubview:priceLabel]; 34 self.priceLabel = priceLabel; 35 36 [priceLabel makeConstraints:^(MASConstraintMaker *make) { 37 make.left.equalTo(titleLabel); 38 make.bottom.equalTo(iconImageView); 39 make.size.equalTo(CGSizeMake(100, 15)); 40 }]; 41 42 // 购买数 43 UILabel *buyCountLabel = [[UILabel alloc] init]; 44 buyCountLabel.font = [UIFont systemFontOfSize:13]; 45 buyCountLabel.textColor = [UIColor grayColor]; 46 buyCountLabel.textAlignment = NSTextAlignmentRight; 47 [self.contentView addSubview:buyCountLabel]; 48 self.buyCountLabel = buyCountLabel; 49 50 [buyCountLabel makeConstraints:^(MASConstraintMaker *make) { 51 make.bottom.equalTo(iconImageView); 52 make.right.equalTo(titleLabel); 53 make.size.equalTo(CGSizeMake(150, 13)); 54 }]; 55 } 56 return self; 57 }
三、字典转模型的几种方式(MJExtension)
1.遍历数组
一般最笨的方法分以下三步:加载字典数组、创建模型数组、将字典数组转换为模型数组
示例代码如下:
1 - (NSArray *)tgs 2 { 3 if (!_tgs) { 4 // 加载字典数组 5 NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tgs" ofType:@"plist"]]; 6 7 // 创建模型数组 8 NSMutableArray *tgArray = [NSMutableArray array]; 9 10 // 将字典数组 -> 模型数组 11 for (NSDictionary *dict in dictArray) { 12 XMGTg *tg = [XMGTg tgWithDict:dict]; 13 [tgArray addObject:tg]; 14 } 15 _tgs = tgArray; 16 } 17 return _tgs; 18 }
2.世界流行框架MJExtension
再来看看用李明杰的MJExtension框架怎么解决
有一个方法,一句话可以解决
_tgs = [XMGTg objectArrayWithFilename:@"tgs.plist"];
或者这样
_tgs = [XMGTg objectArrayWithFile:[[NSBundle mainBundle] pathForResource:@"tgs" ofType:@"plist"]];
或是这样
_tgs = [XMGTg objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tgs" ofType:@"plist"]]];
那么在上次说到的索引条案例中可以这样写
// 懒加载 - (NSArray *)cargroups { if (!_cargroups) { // 提前告诉CarGroup类其中的Cars数组要解析成什么模型数组 [CarGroup setupObjectClassInArray:^NSDictionary *{ return @{ @"cars": @"Car" }; }]; _cargroups = [CarGroup objectArrayWithFilename:@"cars.plist"]; } return _cargroups; }
四、xib自定义等高的cell
首先可以先创建一个名为XMGTgCell继承UITableViewCell的类
然后创建你想要的xib文件
并且xib中的Custom Class中的class一定要设置成XMGTgCell
最后在XMGTgCell的实现中重写
- (void)setTg:(XMGTg *)tg
设置数据
1 #import <UIKit/UIKit.h> 2 3 @class XMGTg; 4 5 @interface XMGTgCell : UITableViewCell 6 /** 团购模型数据 */ 7 @property (nonatomic, strong) XMGTg *tg; 8 @end 9 10 #import "XMGTgCell.h" 11 #import "XMGTg.h" 12 13 @interface XMGTgCell() 14 @property (weak, nonatomic) IBOutlet UIImageView *iconImageView; 15 @property (weak, nonatomic) IBOutlet UILabel *titleLabel; 16 @property (weak, nonatomic) IBOutlet UILabel *priceLabel; 17 @property (weak, nonatomic) IBOutlet UILabel *buyCountLabel; 18 @end 19 20 @implementation XMGTgCell 21 22 - (void)setTg:(XMGTg *)tg 23 { 24 _tg = tg; 25 26 self.iconImageView.image = [UIImage imageNamed:tg.icon]; 27 self.titleLabel.text = tg.title; 28 self.priceLabel.text = [NSString stringWithFormat:@"¥%@", tg.price]; 29 self.buyCountLabel.text = [NSString stringWithFormat:@"%@人已购买", tg.buyCount]; 30 } 31 @end
五、不同类型的cell共存
首先在cellForRowAtIndexPath方法中返回不同类型的cell
1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 if (indexPath.row % 2 == 0) { 4 XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:tgID]; 5 cell.tg = self.tgs[indexPath.row]; 6 return cell; 7 } else { 8 XMGNewsCell *cell = [tableView dequeueReusableCellWithIdentifier:newsID]; 9 return cell; 10 } 11 }
并且在使用这些cell之前要先注册
- (void)viewDidLoad { [super viewDidLoad]; self.tableView.rowHeight = 70; [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([XMGTgCell class]) bundle:nil] forCellReuseIdentifier:tgID]; [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([XMGNewsCell class]) bundle:nil] forCellReuseIdentifier:newsID]; }
效果如下
六、storyboard自定义cell
这两种不同的cell绑定的Identifier分别为:tg、test
那么让我们来看下代码
1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 if (indexPath.row % 2 == 0) { 4 static NSString *ID = @"tg"; 5 XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 6 7 cell.tg = self.tgs[indexPath.row]; 8 9 return cell; 10 } else { 11 return [tableView dequeueReusableCellWithIdentifier:@"test"]; 12 } 13 }
如果我们在viewDidLoad注册一个Identifier为tg,并且类型为UITableViewCell的cell,会出现什么情况呢
- (void)viewDidLoad { [super viewDidLoad]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"tg"]; }
经过测试,发现运行程序会直接蹦了,并且报了一个错误
reason: '-[UITableViewCell setTg:]: unrecognized selector sent to instance 0x7f8fcbc2be70'
这里是什么意思呢,首先在这里要知道 "当缓存池中找不到cell 的时候,先根据重用标识从注册这里找,然后再从storysboard中找"
这个错误的意思是发送了一个不能识别的消息-[UITableViewCell setTg:]
也就是说UITableViewCell中的setTg方法它找不到,程序运行到
"cell.tg = self.tgs[indexPath.row];这一句时就会报错,因为我们根本没有在UITableViewCell里创建tg这个属性,自然也就找不到tg的set方法,进而可以验证上面所说的系统会优先选择代码创建的cell而不是storyboard里的"
七、分割线,静态cell
分割线的原理:实际上cell中的Content View的高度要比cell少1左右的高度(大概),那么我们可以紧贴着Content View底部添加一个高度为0~1、宽度等于cell的view,并把颜色设置为灰色,最好将self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;不显示分割线
静态cell,iPhone的设置界面就是用的静态cell
八、团购案例(TG)
最后是今天自己敲的完整的代码
1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UITableViewController 4 5 @end 6 7 #import "ViewController.h" 8 #import "TgCellTableViewCell.h" 9 #import "MJExtension.h" 10 #import "TgCell.h" 11 12 #define ID @"chgCell" 13 14 @interface ViewController () 15 @property (nonatomic, strong) NSArray *tgCells; 16 @end 17 18 @implementation ViewController 19 - (NSArray *)tgCells 20 { 21 if (nil == _tgCells) { 22 _tgCells = [TgCell objectArrayWithFilename:@"tgs.plist"]; 23 } 24 return _tgCells; 25 } 26 27 - (void)viewDidLoad { 28 [super viewDidLoad]; 29 self.tableView.rowHeight = 70; 30 31 // self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 32 33 [self.tableView registerClass:[TgCellTableViewCell class] forCellReuseIdentifier:ID]; 34 35 } 36 37 - (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section 38 { 39 return self.tgCells.count; 40 } 41 42 - (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath 43 { 44 TgCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 45 cell.tgcell = self.tgCells[indexPath.row]; 46 47 return cell; 48 } 49 @end 50 51 /**************** TgCellTableViewCell*******************/ 52 #import <UIKit/UIKit.h> 53 #import "TgCell.h" 54 @interface TgCellTableViewCell : UITableViewCell 55 @property (nonatomic, strong) TgCell *tgcell; 56 @end 57 58 #import "TgCellTableViewCell.h" 59 60 @interface TgCellTableViewCell() 61 // 图标 62 @property (nonatomic, weak) UIImageView *icon_imageView; 63 // 标题 64 @property (nonatomic, weak) UILabel *titel_lable; 65 // 价格 66 @property (nonatomic, weak) UILabel *price_lable; 67 // 购买人数 68 @property (nonatomic, weak) UILabel *buy_lable; 69 70 @end 71 72 @implementation TgCellTableViewCell 73 74 // 添加一个灰色的边框 75 - (void)awakeFromNib 76 { 77 self.layer.borderWidth = 1; 78 self.layer.borderColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.3].CGColor; 79 } 80 81 // 添加所有子控件 82 - (nonnull instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier 83 { 84 if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 85 // 1.创建图标 86 UIImageView *icon_imageView = [[UIImageView alloc] init]; 87 [self.contentView addSubview:icon_imageView]; 88 self.icon_imageView = icon_imageView; 89 90 // 2.创建标题 91 UILabel *titel_lable = [[UILabel alloc] init]; 92 [self.contentView addSubview:titel_lable]; 93 self.titel_lable = titel_lable; 94 95 // 3.创建价格 96 UILabel *price_lable = [[UILabel alloc] init]; 97 [self.contentView addSubview:price_lable]; 98 price_lable.textColor = [UIColor orangeColor]; 99 price_lable.font = [UIFont systemFontOfSize:15]; 100 self.price_lable = price_lable; 101 102 103 // 4.创建购买人数 104 UILabel *buy_lable = [[UILabel alloc] init]; 105 [self.contentView addSubview:buy_lable]; 106 buy_lable.textAlignment = NSTextAlignmentRight; 107 buy_lable.textColor = [UIColor grayColor]; 108 buy_lable.font = [UIFont systemFontOfSize:13]; 109 self.buy_lable = buy_lable; 110 111 } 112 return self; 113 } 114 115 116 117 // 布局控件 118 - (void)layoutSubviews 119 { 120 [super layoutSubviews]; 121 122 CGFloat margin = 10; 123 CGFloat contentW = self.contentView.frame.size.width; 124 CGFloat contentH = self.contentView.frame.size.height; 125 // 设置frame 126 // 1、设置图标的frame 127 CGFloat icon_imageViewX = margin; 128 CGFloat icon_imageViewY = margin; 129 CGFloat icon_imageViewW = 80; 130 CGFloat icon_imageViewH = contentH - 2 * margin; 131 self.icon_imageView.frame = CGRectMake(icon_imageViewX, icon_imageViewY, icon_imageViewW, icon_imageViewH); 132 133 // 2、设置标题的frame 134 CGFloat titel_lableX = CGRectGetMaxX(self.icon_imageView.frame) + margin; 135 CGFloat titel_lableY = margin; 136 CGFloat titel_lableW = contentW - titel_lableX - margin; 137 CGFloat titel_lableH = 20; 138 self.titel_lable.frame = CGRectMake(titel_lableX, titel_lableY, titel_lableW, titel_lableH); 139 140 // 3、设置价格的frame 141 CGFloat price_lableX = titel_lableX; 142 CGFloat price_lableH = 15; 143 CGFloat price_lableW = 100; 144 CGFloat price_lableY = CGRectGetMaxY(self.icon_imageView.frame) - price_lableH; 145 self.price_lable.frame = CGRectMake(price_lableX, price_lableY, price_lableW, price_lableH); 146 147 // 4、设置购买人数的frame 148 CGFloat buy_lableX = CGRectGetMaxX(self.price_lable.frame) + margin; 149 CGFloat buy_lableH = 13; 150 CGFloat buy_lableY = CGRectGetMaxY(self.icon_imageView.frame) - buy_lableH; 151 CGFloat buy_lableW = contentW - buy_lableX - margin; 152 self.buy_lable.frame = CGRectMake(buy_lableX, buy_lableY, buy_lableW, buy_lableH); 153 154 } 155 156 - (void)setTgcell:(TgCell *)tgcell 157 { 158 _tgcell = tgcell; 159 160 self.icon_imageView.image = [UIImage imageNamed:tgcell.icon]; 161 self.titel_lable.text = tgcell.title; 162 self.price_lable.text = [NSString stringWithFormat:@"¥%@",tgcell.price]; 163 self.buy_lable.text = [NSString stringWithFormat:@"%@人购买",tgcell.buyCount]; 164 } 165 166 @end 167 168 /**************** TgCell*******************/ 169 #import <Foundation/Foundation.h> 170 171 @interface TgCell : NSObject 172 /** 标题 */ 173 @property (nonatomic, copy) NSString *title; 174 /** 购买数 */ 175 @property (nonatomic, copy) NSString *buyCount; 176 /** 图片 */ 177 @property (nonatomic, copy) NSString *icon; 178 /** 价格 */ 179 @property (nonatomic, copy) NSString *price; 180 @end 181 182 #import "TgCell.h" 183 184 @implementation TgCell 185 186 @end