• iOS开发——UI进阶篇(二)自定义等高cell,xib自定义等高的cell,Autolayout布局子控件,团购案例


    一、纯代码自定义等高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

    将来的你会感谢今天如此努力的你! 版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    最长递增长度 (最长上升子序列)
    完全背包问题
    vue中使用el-tabs组件遇到的问题
    ORACLE中排序的时候空值处理
    ORA-01089数据库无法正常关闭
    Oracle中的LPAD和RPAD的使用
    Oracle中Translate函数的使用
    通过对照表快速建view
    Oracle数据库create or replace
    打字网站
  • 原文地址:https://www.cnblogs.com/chglog/p/4663136.html
Copyright © 2020-2023  润新知