• IOS的UITableView


    UITableView

    概述

    1 UITableView
    2     一般用来展示表格数据、可以滚动(继承自UIScrollView).性能极佳
    3 UITableView分两种样式:
    4     Plain,不分组的样式
    5     Grouped,分组的样式
    6     UITableView默认为Plain样式,改为Grouped后实现分组,如果再改回Plain 那么在滚动的时候 上一层的头标签就会一直作为索引显示,类似于通讯录中的A B的显示方式

    使用:

     1 如果要使用UITableView 那么需要实现UITableViewDataSource协议后重写 2 
     3 //展现数据有几组,当不实现这个方法时,默认为一组
     4 -(NSInteger)numberOfSectionsInTableView:(UITableView *) tableView
     5 
     6 //一组有几行
     7 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section
     8 
     9 //每行显示什么内容
    10 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    11 
    12 //实现右侧的索引栏
    13 -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
    14 (获取group数组中的每个对象的title值,并返回到一个NSArray中
    15 [self.groups valueForKeyPath:@"title"])
    16 
    17 //通过代理坚挺cell的点击事件
    18 //选中某行
    19 -(void)tableView:(UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
    20 
    21 //取消选中某行
    22 -(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;
    23 
      //设置组标题
      -(NSString *)tableView :(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;

      //设置组描述
      -(NSString *)tableView :(UITableView *)tableView titleForFooterInsection:(NSInteger)section;


    24 //修改每行的行高 25 1.如果tableView的行高一样,那么就在控制器的viewDidLoad中统一设置行高tableView.rowHeight(这种方法比较高效) 26 2.通过代理方法实现: 27 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath(低效)

      //把UITableView中的最后一行的数据滚动到最上面
          NSIndexPath *idxPath = [NSIndexPath indexPathForRow:self.goods.count - 1 inSection:0];
         [self.tableView scrollToRowAtIndexPath:idxPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
     

     UITableView的常见属性

    1 rowHeight 可以统一设置所有行的高度
    2 
    3 separatorColor 分割线的颜色
    4 separatorStyle 分割线的样式
    5 
    6 tableHeaderView 一般可以放广告
    7 tableFooterView  一般可以放加载更多

    Cell的常见属性

     1 imageView
     2 textLabel
     3 detailTextLabel
     4 
     5 accessoryType
     6 accessoryView
     7 
     8 backgroundColor,设置单元格的背景颜色
     9 
    10 backgroundView 可以利用这个属性来设置单元格的背景图片,指定一个UIImageView就可以了
    11 
    12 selectedBackgroundView 当某行被选中的时候的背景

     单元格Cell的重用

    1 //注意:只适用于单元格样式一致的时候
    2 //单元格重用的基本方法
    3 //1.声明一个 静态的重用ID (只所以声明静态是为了节省控制器不断的释放,创建成员对象)
    4 //2.根据重用ID去缓存池中获取对应的cell对象
    5 //3.如果没有获取到,就创建一个,如果获取到了就直接设置单元格内容
    6 //4.返回单元格

    注意:当使用自定义的cell的时候 是无法通过 dequeueReusableCellWithIdentifier:ID的方式来指定ID的

    所以需要在布局文件中进行设置

    代码示例:

    1.  .plist的数据结构

      

     模型代码:

     1.1)CZGroup.h 

     1 #import <Foundation/Foundation.h>
     2 
     3 @interface GZGroup :NSObject
     4 
     5 @property (nonatomic ,copy) NSString *titile;
     6 @property (nonatomic, strong) NSArray *cars;
     7 
     8 -(instancetype)initWithDict :(NSDictionary *)dict;
     9 +(instancetype)groupWithDict:(NSDictionary *)dict;
    10 
    11 @end

      GZGroup.m

    #import "CZGroup.h"
    #import "CZCar.h"
    @implementation CZGroup
    
    - (instancetype)initWithDict:(NSDictionary *)dict
    {
        if (self = [super init]) {
            //        self.title = dict[@"title"];
            //        self.cars = dict[@"cars"];
    
            [self setValuesForKeysWithDictionary:dict];
            
            // 当有模型嵌套的时候需要手动把字典转成模型
            // 创建一个用来保存模型的数组
            NSMutableArray *arrayModels = [NSMutableArray array];
            // 手动做一下字典转模型
            for (NSDictionary *item_dict in dict[@"cars"]) {
                CZCar *model = [CZCar carWithDict:item_dict];
                [arrayModels addObject:model];
            }
            self.cars = arrayModels;
        }
        return self;
    }
    + (instancetype)groupWithDict:(NSDictionary *)dict
    {
        return [[self alloc] initWithDict:dict];
    }
    @end

    控制器代码,重用cell需要这是一个ID

     1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
     2 {
     3     // 1. 获取模型数据
     4     // 根据组的索引获取对应的组的模型
     5     CZGroup *group = self.groups[indexPath.section];
     6     // 根据当前行的索引, 获取对应组的对应行的车
     7     CZCar *car = group.cars[indexPath.row];
     8     
     9     
    10     
    11     // 2. 创建单元格
    12     // 2.1 声明一个重用ID
    13     static NSString *ID = @"car_cell";
    14     // 2.2 根据重用ID去缓存池中获取对应的cell对象
    15     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    16     // 2.3 如果没有获取到, 那么就创建一个
    17     if (cell == nil) {
    18         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    19     }
    20     
    21     // 3. 设置单元格内容
    22     cell.imageView.image = [UIImage imageNamed:car.icon];
    23     cell.textLabel.text = car.name;
    24     
    25     // 4. 返回单元格
    26     return cell;
    27 }

     自定义Cell

    案例一:团购

    Viewontroller.m

      1 #import "ViewController.h"
      2 #import "CZGoods.h"
      3 #import "CZGoodsCell.h"
      4 #import "CZFooterView.h"
      5 #import "CZHeaderView.h"
      6 
      7 @interface ViewController () <UITableViewDataSource, CZFooterViewDelegate>
      8 
      9 // 用来存储所有的团购商品的数据
     10 @property (nonatomic, strong) NSMutableArray *goods;
     11 
     12 @property (weak, nonatomic) IBOutlet UITableView *tableView;
     13 @end
     14 
     15 @implementation ViewController
     16 
     17 
     18 #pragma mark - 懒加载数据
     19 - (NSMutableArray *)goods
     20 {
     21     if (_goods == nil) {
     22         NSString *path = [[NSBundle mainBundle] pathForResource:@"tgs.plist" ofType:nil];
     23         NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
     24         NSMutableArray *arrayModels = [NSMutableArray array];
     25         for (NSDictionary *dict in arrayDict) {
     26             CZGoods *model = [CZGoods goodsWithDict:dict];
     27             [arrayModels addObject:model];
     28         }
     29         _goods = arrayModels;
     30     }
     31     return _goods;
     32 }
     33 
     34 #pragma mark - 数据源方法
       //返回有UITableView 有多少个组,默认为1,当组为1时 可以忽略不写 35 //- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 36 //{ 37 // return 1; 38 //} 39 40 //返回组内有多少行数据 41 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 42 { 43 return self.goods.count; 44 } 45 46 //返回Cell对象 47 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 48 { 49 // 1. 获取模型数据 50 CZGoods *model = self.goods[indexPath.row]; 51 52 // 2. 创建单元格 53 // 通过xib的方式来创建单元格 54 CZGoodsCell *cell = [CZGoodsCell goodsCellWithTableView:tableView]; 55 56 57 // 3. 把模型数据设置给单元格 58 // 在控制器中直接为cell的每个子控件赋值数据造成的问题: 59 // 1. 控制器强依赖于Cell, 一旦cell内部的子控件发生了变化, 那么控制器中的代码也得改(这就造成了紧耦合) 60 // 2. cell的封装不够完整, 凡是用到这个cell的地方, 每次都要编写为cell的子控件依次赋值的语句,比如:cell.xxx = model.title; 61 // 3. 解决: 直接把模型传递给自定义Cell, 然后在自定义cell内部解析model中的数据赋值给自定义cell内部的子控件。 62 cell.goods = model; 63 64 // 4.返回单元格 65 return cell; 66 } 67 68 69 70 #pragma mark - 隐藏状态栏 71 - (BOOL)prefersStatusBarHidden 72 { 73 return YES; 74 } 75 80 - (void)viewDidLoad { 81 [super viewDidLoad]; 82 self.tableView.rowHeight = 44; 83 84 // 设置UITableView的footerView 85 // UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd]; 86 // 87 // btn.backgroundColor = [UIColor redColor]; 88 // btn.frame = CGRectMake(20, 50, 30, 100); 89 // // tableView的footerView的特点: 只能修改x和height的值, Y 和 width不能改。 90 // self.tableView.tableFooterView = btn; 91 92 93 94 // 通过Xib设置UITableView的footerView 95 CZFooterView *footerView = [CZFooterView footerView]; 96 // 设置footerView的代理 97 footerView.delegate = self; 98 self.tableView.tableFooterView = footerView; 99 100 101 // 创建Header View 102 CZHeaderView *headerView = [CZHeaderView headerView]; 103 self.tableView.tableHeaderView = headerView; 104 105 106 107 108 109 } 110 111 #pragma mark - CZFooterView的代理方法 112 113 - (void)footerViewUpdateData:(CZFooterView *)footerView 114 { 115 // 3. 增加一条数据 116 117 118 // 3.1 创建一个模型对象 119 CZGoods *model = [[CZGoods alloc] init]; 120 model.title = @"驴肉火烧"; 121 model.price = @"6.0"; 122 model.buyCount = @"1000"; 123 model.icon = @"37e4761e6ecf56a2d78685df7157f097"; 124 125 // 3.2 把模型对象加到控制器的goods集合当中 126 [self.goods addObject:model]; 127 128 // 4. 刷新UITableView 129 [self.tableView reloadData]; 130 131 // // 局部刷新(只适用于UITableView总行数没有发生变化的情况) 132 // NSIndexPath *idxPath = [NSIndexPath indexPathForRow:self.goods.count - 1 inSection:0]; 133 // [self.tableView reloadRowsAtIndexPaths:@[idxPath] withRowAnimation:UITableViewRowAnimationLeft]; 134 135 136 // 5. 把UITableView中的最后一行的数据滚动到最上面 137 NSIndexPath *idxPath = [NSIndexPath indexPathForRow:self.goods.count - 1 inSection:0]; 138 [self.tableView scrollToRowAtIndexPath:idxPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; 139 } 140 141 - (void)didReceiveMemoryWarning { 142 [super didReceiveMemoryWarning]; 143 // Dispose of any resources that can be recreated. 144 } 145 146 @end

    自定义的CZGoodsCell对象

    CZGoodsCell.h

    //导入 UIKit/UIKit.h 文件
    #import <UIKit/UIKit.h>
    @class CZGoods;
    //继承 UITableViewCell
    @interface CZGoodsCell : UITableViewCell
    
    @property (nonatomic, strong) CZGoods *goods;
    
    // 封装一个创建自定义Cell的方法
    + (instancetype)goodsCellWithTableView:(UITableView *)tableView;
    @end

    CZGoodsCell.m

     1 #import "CZGoodsCell.h"
     2 #import "CZGoods.h"
     3 
     4 @interface CZGoodsCell ()
     5 @property (weak, nonatomic) IBOutlet UIImageView *imgViewIcon;
     6 @property (weak, nonatomic) IBOutlet UILabel *lblTitle;
     7 @property (weak, nonatomic) IBOutlet UILabel *lblPrice;
     8 @property (weak, nonatomic) IBOutlet UILabel *lblBuyCount;
     9 
    10 @end
    11 
    12 
    13 @implementation CZGoodsCell
    14 
    15 + (instancetype)goodsCellWithTableView:(UITableView *)tableView
    16 {
    17     static NSString *ID = @"goods_cell";
    18     CZGoodsCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    19     if (cell == nil) {
    20         cell = [[[NSBundle mainBundle] loadNibNamed:@"CZGoodsCell" owner:nil options:nil] firstObject];
    21     }
    22     return cell;
    23 }
    24 
    25 
    26 - (void)setGoods:(CZGoods *)goods
    27 {
    28     _goods = goods;
    29     // 把模型的数据设置给子控件
    30     self.imgViewIcon.image = [UIImage imageNamed:goods.icon];
    31     self.lblTitle.text = goods.title;
    32     self.lblPrice.text = [NSString stringWithFormat:@"¥ %@", goods.price];
    33     self.lblBuyCount.text = [NSString stringWithFormat:@"%@ 人已购买", goods.buyCount];
    34 }
    35 
    36 - (void)awakeFromNib {
    37     // Initialization code
    38 }
    39 
    40 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    41     [super setSelected:selected animated:animated];
    42 
    43     // Configure the view for the selected state
    44 }
    45 
    46 @end

    尾部的加载更多按钮

    CZFooterView.h

     1 #import <UIKit/UIKit.h>
     2 @class CZFooterView;
     3 
      //设置一个代理对象 4 @protocol CZFooterViewDelegate <NSObject, UIScrollViewDelegate>
      //提示用户使用这个代理的时候必须实现下面的代理方法 5 @required 6 - (void)footerViewUpdateData:(CZFooterView *)footerView; 7 @end 8 9 @interface CZFooterView : UIView 10 11 + (instancetype)footerView; 12 @property (nonatomic, weak) id<CZFooterViewDelegate> delegate; 13 @end

    CZFooterView.m

     1 #import "CZFooterView.h"
     2 
     3 @interface CZFooterView ()
     4 @property (weak, nonatomic) IBOutlet UIButton *btnLoadMore;
     5 @property (weak, nonatomic) IBOutlet UIView *waitingView;
     6 - (IBAction)btnLoadMoreClick;
     7 @end
     8 
     9 
    10 @implementation CZFooterView
    11 
    12 + (instancetype)footerView
    13 {
    14     CZFooterView *footerView = [[[NSBundle mainBundle] loadNibNamed:@"CZFooterView" owner:nil options:nil] lastObject];
    15     return footerView;
    16 }
    17 
    18 
    19 /**
    20 *  加载更多按钮的单击事件
    21 */
    22 - (IBAction)btnLoadMoreClick {
    23     // 1. 隐藏"加载更多"按钮
    24     self.btnLoadMore.hidden = YES;
    25     
    26     // 2. 显示"等待指示器"所在的那个UIView
    27     self.waitingView.hidden = NO;
    28     
    29     
    30     
    31     //GCD方法,标示延迟一定的时间后执行,由于我们这里是模拟操作,当点击按钮后,数据立刻会刷新,所以为了模拟逼真一些,这里就加了一个延迟操作的方法
    32     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    33         
    34         // 3. 调用代理方法实现下面的功能
    35         // 调用footerViewUpdateData方法之前, 为了保证调用不出错, 所以要先判断一下代理对象是否真的实现了这个方法, 如果实现了这个方法再调用, 否则不调用.
    36         if ([self.delegate respondsToSelector:@selector(footerViewUpdateData:)]) {
    37             // 3. 增加一条数据
    38             // 3.1 创建一个模型对象
    39             // 3.2 把模型对象加到控制器的goods集合当中
    40             // 4. 刷新UITableView
    41             [self.delegate footerViewUpdateData:self];
    42         }
    43         
    44         
    45         // 4. 显示"加载更多"按钮
    46         self.btnLoadMore.hidden = NO;
    47         
    48         // 5. 隐藏"等待指示器"所在的那个UIView
    49         self.waitingView.hidden = YES;
    50         
    51     });
    52     
    53     
    54     
    55     
    56     
    57     
    58 }
    59 @end

    案例二:微博

    1):当我们的控制器Controller是 tableView的时候,我们可以直接使用Table View Controller,需要指定dataSource 和 delegate的代理对象

    2):由于微博中的内容信息是不一致的,table栏的宽度也是不一致的,所以我们没有办法在 viedieLoad中 使用self.tableview.rowHeight 来设置统一的高度,所以我们针对每一个Cell的Frame做了一个封装,在懒加载数据时,将数据直接给Frame对象,然后Frame对象根据内容计算出高度,后再Cell的时候 直接返回Cell对象

    封装的Frame对象

    CZWeiboFrame.h

     1 #import <Foundation/Foundation.h>
     2 #import <CoreGraphics/CoreGraphics.h>
     3 #import <UIKit/UIKit.h>
     4 #define nameFont [UIFont systemFontOfSize:12]
     5 #define textFont [UIFont systemFontOfSize:14]
     6 
     7 @class CZWeibo;
     8 @interface CZWeiboFrame : NSObject
     9 
    10 @property (nonatomic, strong) CZWeibo *weibo;
    11 
    12 // 用来保存头像的frame
    13 @property (nonatomic, assign, readonly) CGRect iconFrame;
    14 
    15 // 昵称的frame
    16 @property (nonatomic, assign, readonly) CGRect nameFrame;
    17 
    18 
    19 // vip的frame
    20 @property (nonatomic, assign, readonly) CGRect vipFrame;
    21 
    22 // 正文的frame
    23 @property (nonatomic, assign, readonly) CGRect textFrame;
    24 
    25 //配图的frame
    26 @property (nonatomic, assign, readonly) CGRect picFrame;
    27 
    28 // 行高
    29 @property (nonatomic, assign, readonly) CGFloat rowHeight;
    30 
    31 @end

    CZWeiboFrame.m

     1 #import "CZWeiboFrame.h"
     2 #import "CZWeibo.h"
     3 
     4 @implementation CZWeiboFrame
     5 
     6 // 重写weibo属性的set方法
     7 - (void)setWeibo:(CZWeibo *)weibo
     8 {
     9     _weibo = weibo;
    10     
    11     // 计算每个控件的frame, 和行高
    12     
    13     // 提取统一的间距
    14     CGFloat margin = 10;
    15     
    16     // 1. 头像
    17     CGFloat iconW = 35;
    18     CGFloat iconH = 35;
    19     CGFloat iconX = margin;
    20     CGFloat iconY = margin;
    21     _iconFrame = CGRectMake(iconX, iconY, iconW, iconH);
    22     
    23     
    24     
    25     // 2. 昵称
    26     // 获取昵称字符串
    27     NSString *nickName = weibo.name;
    28     CGFloat nameX = CGRectGetMaxX(_iconFrame) + margin;
    29     
    30     // 根据Label中文字的内容, 来动态计算Label的高和宽
    31     CGSize nameSize = [self sizeWithText:nickName andMaxSize:CGSizeMake(MAXFLOAT, MAXFLOAT) andFont:nameFont];
    32     
    33     CGFloat nameW = nameSize.width;
    34     CGFloat nameH = nameSize.height;
    35     CGFloat nameY = iconY + (iconH - nameH) / 2;
    36     
    37     _nameFrame = CGRectMake(nameX, nameY, nameW, nameH);
    38     
    39     
    40     
    41     // 3. 会员
    42     CGFloat vipW = 10;
    43     CGFloat vipH = 10;
    44     CGFloat vipX = CGRectGetMaxX(_nameFrame) + margin;
    45     CGFloat vipY = nameY;
    46     _vipFrame = CGRectMake(vipX, vipY, vipW, vipH);
    47     
    48     
    49     
    50     // 4. 正文
    51     CGFloat textX = iconX;
    52     CGFloat textY = CGRectGetMaxY(_iconFrame) + margin;
    53     CGSize textSize = [self sizeWithText:weibo.text andMaxSize:CGSizeMake(300, MAXFLOAT) andFont:textFont];
    54     CGFloat textW = textSize.width;
    55     CGFloat textH = textSize.height;
    56     _textFrame = CGRectMake(textX, textY, textW, textH);
    57     
    58     
    59     // 5. 配图
    60     CGFloat picW = 100;
    61     CGFloat picH = 100;
    62     CGFloat picX = iconX;
    63     CGFloat picY = CGRectGetMaxY(_textFrame) + margin;
    64     _picFrame = CGRectMake(picX, picY, picW, picH);
    65     
    66     
    67     //6. 计算每行的高度
    68     CGFloat rowHeight = 0;
    69     if (self.weibo.picture) {
    70         // 如果有配图, 那么行高就等于配图的最大的Y值  + margin
    71         rowHeight = CGRectGetMaxY(_picFrame) + margin;
    72     } else {
    73         // 如果没有配图, 那么行高就等于正文的最大的Y值  + margin
    74         rowHeight = CGRectGetMaxY(_textFrame) + margin;
    75     }
    76     
    77     // 注意::: 计算完毕行高以后,不要忘记为属性赋值。
    78     _rowHeight = rowHeight;
    79     
    80     
    81 }
    82 
    83 // 根据给定的字符串、最大值的size、给定的字体, 来计算文字应该占用的大小
    84 - (CGSize)sizeWithText:(NSString *)text andMaxSize:(CGSize)maxSize andFont:(UIFont *)font
    85 {
    86     NSDictionary *attr = @{NSFontAttributeName : font};
    87     return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil].size;
    88 }
    89 @end

    自定义的cell对象

    之前封装的frame主要用来存储所需要的对象数据,以及计算各个控件和总的tableView Item的frame 

    而我们在cell中是用来创建我们需要的对象,以及将最终形成的布局文件返回给tableView

    CZWeiboCell.h

    1 #import <UIKit/UIKit.h>
    2 @class CZWeiboFrame;
    3 @interface CZWeiboCell : UITableViewCell
    4 
    5 @property (nonatomic, strong) CZWeiboFrame *weiboFrame;
    6 
    7 + (instancetype)weiboCellWithTableView:(UITableView *)tableView;
    8 @end

    CZWeiboCell.m

      1 #import "CZWeiboCell.h"
      2 #import "CZWeibo.h"
      3 #import "CZWeiboFrame.h"
      4 
      5 
      6 
      7 @interface CZWeiboCell ()
      8 @property (nonatomic, weak) UIImageView *imgViewIcon;
      9 @property (nonatomic, weak) UILabel *lblNickName;
     10 @property (nonatomic, weak) UIImageView *imgViewVip;
     11 @property (nonatomic, weak) UILabel *lblText;
     12 @property (nonatomic, weak) UIImageView *imgViewPicture;
     13 
     14 
     15 @end
     16 
     17 
     18 @implementation CZWeiboCell
     19 
     20 
     21 #pragma mark - 重写单元格的initWithStyle:方法
     22 
     23 + (instancetype)weiboCellWithTableView:(UITableView *)tableView
     24 {
     25     static NSString *ID = @"weibo_cell";
     26     CZWeiboCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
     27     if (cell == nil) {
     28         cell = [[CZWeiboCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
     29     }
     30     return cell;
     31 }
     32 
     33 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
     34 {
     35     if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
     36         // 创建5个子控件
     37         
     38         // 1. 头像
     39         UIImageView *imgViewIcon = [[UIImageView alloc] init];
     40         [self.contentView addSubview:imgViewIcon];
     41         self.imgViewIcon = imgViewIcon;
     42         
     43         // 2. 昵称
     44         UILabel *lblNickName = [[UILabel alloc] init];
     45         // 设置Label的文字大小
     46         lblNickName.font = nameFont;
     47         
     48         [self.contentView addSubview:lblNickName];
     49         self.lblNickName = lblNickName;
     50         
     51         // 3. 会员
     52         UIImageView *imgViewVip = [[UIImageView alloc] init];
     53         imgViewVip.image = [UIImage imageNamed:@"vip"];
     54         [self.contentView addSubview:imgViewVip];
     55         self.imgViewVip = imgViewVip;
     56         
     57         // 4. 正文
     58         UILabel *lblText = [[UILabel alloc] init];
     59         lblText.font = textFont;
     60         // 设置正文的Label可以自动换行
     61         lblText.numberOfLines = 0;
     62         [self.contentView addSubview:lblText];
     63         self.lblText = lblText;
     64         
     65         // 5. 配图
     66         UIImageView *imgViewPicture = [[UIImageView alloc] init];
     67         [self.contentView addSubview:imgViewPicture];
     68         self.imgViewPicture = imgViewPicture;
     69     }
     70     return self;
     71 }
     72 
     73 
     74 #pragma mark - 重写weibo属性的set方法
     75 - (void)setWeiboFrame:(CZWeiboFrame *)weiboFrame
     76 {
     77     _weiboFrame = weiboFrame;
     78     
     79     // 1. 设置当前单元格中的子控件的数据
     80     [self settingData];
     81     
     82     // 2. 设置当前单元格中的子控件的frame
     83     [self settingFrame];
     84 }
     85 
     86 
     87 // 设置数据的方法
     88 - (void)settingData
     89 {
     90     CZWeibo *model = self.weiboFrame.weibo;
     91     // 1. 头像
     92     self.imgViewIcon.image = [UIImage imageNamed:model.icon];
     93     
     94     // 2. 昵称
     95     self.lblNickName.text = model.name;
     96     
     97     // 3. 会员
     98     if (model.isVip) {
     99         // 设置显示会员图标
    100         self.imgViewVip.hidden = NO;
    101         // 设置昵称的颜色是红色
    102         self.lblNickName.textColor = [UIColor redColor];
    103     } else {
    104         // 设置隐藏会员图标
    105         self.imgViewVip.hidden = YES;
    106         // 设置昵称的颜色是黑色
    107         self.lblNickName.textColor = [UIColor blackColor];
    108     }
    109     
    110     // 4. 正文
    111     self.lblText.text = model.text;
    112  
    113     
    114     // 5. 配图
    115     if (model.picture) {
    116         // 有配图
    117         // 如果model.picture的值是nil, 那么下面这句话执行会报异常
    118         self.imgViewPicture.image = [UIImage imageNamed:model.picture];
    119         // 显示图片框
    120         self.imgViewPicture.hidden = NO;
    121     } else {
    122         // 如果没有配图, 隐藏图片框
    123         self.imgViewPicture.hidden = YES;
    124     }
    125 
    126 }
    127 
    128 // 设置frame的方法
    129 - (void)settingFrame
    130 {
    131     // 1. 头像
    132     
    133     self.imgViewIcon.frame = self.weiboFrame.iconFrame;
    134     
    135     // 2. 昵称
    136     self.lblNickName.frame = self.weiboFrame.nameFrame;
    137     
    138     // 3. 会员
    139     self.imgViewVip.frame = self.weiboFrame.vipFrame;
    140     
    141     // 4. 正文
    142     
    143     self.lblText.frame = self.weiboFrame.textFrame;
    144     
    145     // 5. 配图
    146     self.imgViewPicture.frame = self.weiboFrame.picFrame;
    147 }
    148 
    149 - (void)awakeFromNib {
    150     // Initialization code
    151 }
    152 
    153 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    154     [super setSelected:selected animated:animated];
    155 
    156     // Configure the view for the selected state
    157 }
    158 
    159 @end

    TableViewController控制器的类

    这个类会把我们需要重写的方法展现出来,我们只需要对我们用到的方法进行重写就可以了

      1 #import "CZTableViewController.h"
      2 #import "CZWeibo.h"
      3 #import "CZWeiboCell.h"
      4 #import "CZWeiboFrame.h"
      5 
      6 @interface CZTableViewController ()
      7 
      8 // 现在要求weiboFrames集合中保存的很多个CZWeiboFrame模型,不再是CZWeibo模型了。
      9 @property (nonatomic, strong) NSArray *weiboFrames;
     10 
     11 @end
     12 
     13 @implementation CZTableViewController
     14 
     15 #pragma mark - 懒加载数据
     16 - (NSArray *)weiboFrames
     17 {
     18     if (_weiboFrames == nil) {
     19         NSString *path = [[NSBundle mainBundle] pathForResource:@"weibos.plist" ofType:nil];
     20         
     21         NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
     22         
     23         NSMutableArray *arrayModels = [NSMutableArray array];
     24         
     25         for (NSDictionary *dict in arrayDict) {
     26             // 创建一个数据模型
     27             CZWeibo *model = [CZWeibo weiboWithDict:dict];
     28             
     29             // 创建一个frame 模型
     30             // 创建了一个空得frame模型
     31             CZWeiboFrame *modelFrame = [[CZWeiboFrame alloc] init];
     32             
     33             // 把数据模型赋值给了modeFrame模型中的weibo属性
     34             modelFrame.weibo = model;
     35             
     36             
     37             [arrayModels addObject:modelFrame];
     38         }
     39         _weiboFrames = arrayModels;
     40     }
     41     return _weiboFrames;
     42 }
     43 
     44 
     45 
     46 - (void)viewDidLoad {
     47     [super viewDidLoad];
     48     
     49     // 统一设置行高
     50     //self.tableView.rowHeight = 300;
     51     
     52 //    NSLog(@"%@", self.view);
     53 //    NSLog(@"%@", self.tableView);
     54     
     55     // Uncomment the following line to preserve selection between presentations.
     56     // self.clearsSelectionOnViewWillAppear = NO;
     57     
     58     // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
     59     // self.navigationItem.rightBarButtonItem = self.editButtonItem;
     60 }
     61 
     62 - (void)didReceiveMemoryWarning {
     63     [super didReceiveMemoryWarning];
     64     // Dispose of any resources that can be recreated.
     65 }
     66 
     67 #pragma mark - Table view 数据源方法
     68 
     69 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     70     return 1;
     71 }
     72 
     73 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     74     return self.weiboFrames.count;
     75 }
     76 
     77 
     78 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     79     
     80     
     81     // 1. 获取模型数据
     82     CZWeiboFrame *model = self.weiboFrames[indexPath.row];
     83     
     84     
     85     // 2. 创建单元格
     86     CZWeiboCell *cell = [CZWeiboCell weiboCellWithTableView:tableView];
     87     
     88     // 3. 设置单元格数据
     89     cell.weiboFrame = model;
     90     
     91     // 4. 返回单元格
     92     return cell;
     93 }
     94 
     95 
     96 
     97 #pragma mark - Table view 代理方法
     98 
     99 // 返回每行的行高的方法,对于这个案例,其中最重要的就是关于如何计算行高
    100 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    101 {
    102     CZWeiboFrame *weiboFrame = self.weiboFrames[indexPath.row];
    103     return weiboFrame.rowHeight;
    104 }
    105 
    106 
    107 - (BOOL)prefersStatusBarHidden
    108 {
    109     return YES;
    110 }
    111 
    112 
    113 @end

     案例三:做一个类似于QQ聊天的tableView界面

    这个界面有两个难点:

    1.信息背后的框体 要包裹住消息内容

    2.监听系统的键盘弹出事件,将我们的View 整体向上位移

    问题1:

     1 我们通过 设置 内边距的形式来进行解决
     2 
     3 btnText.contentEdgeInsets = UIEdgeInsetsMake(15, 20, 15, 20); 
     4 
     5 同时对于图片我们要选择平铺的方式进行拉伸
     6 
     7  // 加载图片
     8     UIImage *imageNormal = [UIImage imageNamed:imgNor];
     9     UIImage *imageHighlighted = [UIImage imageNamed:imgHighlighted];
    10     
    11     // 用平铺的方式拉伸图片
    12     imageNormal = [imageNormal stretchableImageWithLeftCapWidth:imageNormal.size.width * 0.5 topCapHeight:imageNormal.size.height * 0.5];
    13     imageHighlighted = [imageHighlighted stretchableImageWithLeftCapWidth:imageHighlighted.size.width * 0.5 topCapHeight:imageHighlighted.size.height * 0.5];
    14     
    15     // 设置背景图
    16     [self.btnText setBackgroundImage:imageNormal forState:UIControlStateNormal];
    17     [self.btnText setBackgroundImage:imageHighlighted forState:UIControlStateHighlighted];

    问题二:

     1 - (void)viewDidLoad {
     2     [super viewDidLoad];
     3     // 取消分割线
     4     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
     5     
     6     // 设置UITableView的背景色
     7     self.tableView.backgroundColor = [UIColor colorWithRed:236 / 255.0 green:236 / 255.0 blue:236 / 255.0 alpha:1.0];
     8     
     9     // 设置UITableView的行不允许被选中
    10     self.tableView.allowsSelection = NO;
    11     
    12     // 设置文本框最左侧有一段间距
    13     UIView *leftVw = [[UIView alloc] init];
    14     leftVw.frame = CGRectMake(0, 0, 5, 1);
    15     
    16     // 把leftVw设置给文本框
    17     self.txtInput.leftView = leftVw;
    18     self.txtInput.leftViewMode = UITextFieldViewModeAlways;
    19     
    20     
    21     // 监听键盘的弹出事件
    22     // 1. 创建一个NSNotificationCenter对象。
    23     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    24     
    25     // 2. 监听键盘的弹出通知
    26     [center addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
    27     
    28 }
    29 
    30 - (void)keyboardWillChangeFrame:(NSNotification *)noteInfo
    31 {
    32 //    NSLog(@"通知名称: %@", noteInfo.name);
    33 //    
    34 //    NSLog(@"通知的发布者: %@", noteInfo.object);
    35 //    
    36 //    NSLog(@"通知的具体内容: %@", noteInfo.userInfo);
    37     // 1. 获取当键盘显示完毕或者隐藏完毕后的Y值
    38     CGRect rectEnd = [noteInfo.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    39     CGFloat keyboardY = rectEnd.origin.y;
    40     
    41     // 用键盘的Y值减去屏幕的高度计算出平移的值
    42     // 1. 如果是键盘弹出事件, 那么计算出的值就是负的键盘的高度
    43     // 2. 如果是键盘的隐藏事件, 那么计算出的值就是零, 因为键盘在隐藏以后, 键盘的Y值就等于屏幕的高度。
    44     CGFloat tranformValue = keyboardY - self.view.frame.size.height;
    45     
    46     [UIView animateWithDuration:0.25 animations:^{
    47         // 让控制器的View执行一次“平移”
    48         self.view.transform = CGAffineTransformMakeTranslation(0, tranformValue);
    49     }];
    50     
    51     
    52     
    53     // 让UITableView的最后一行滚动到最上面
    54     NSIndexPath *lastRowIdxPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];
    55     [self.tableView scrollToRowAtIndexPath:lastRowIdxPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    56 }
    57 
    58 
    59 // ***************** 注意: 监听通知以后一定要在监听通知的对象的dealloc方法中移除监听 *************/.
    60 
    61 - (void)dealloc
    62 {
    63     // 移除通知
    64     [[NSNotificationCenter defaultCenter] removeObserver:self];
    65 }

    整体代码

    1.做一个NSString的类扩展 用于字体最大的尺寸

    NSString+CZNSStringExt.h

     1 #import <Foundation/Foundation.h>
     2 #import <UIKit/UIKit.h>
     3 @interface NSString (CZNSStringExt)
     4 
     5 // 对象方法
     6 - (CGSize)sizeOfTextWithMaxSize:(CGSize)maxSize font:(UIFont *)font;
     7 
     8 // 类方法
     9 + (CGSize)sizeWithText:(NSString *)text maxSize:(CGSize)maxSize font:(UIFont *)font;
    10 @end

    NSString+CZNSStringExt.m

     1 #import "NSString+CZNSStringExt.h"
     2 
     3 @implementation NSString (CZNSStringExt)
     4 
     5 // 实现对象方法
     6 - (CGSize)sizeOfTextWithMaxSize:(CGSize)maxSize font:(UIFont *)font
     7 {
     8     NSDictionary *attrs = @{NSFontAttributeName : font};
     9     return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
    10 }
    11 
    12 // 类方法
    13 + (CGSize)sizeWithText:(NSString *)text maxSize:(CGSize)maxSize font:(UIFont *)font
    14 {
    15     return [text sizeOfTextWithMaxSize:maxSize font:font];
    16 }
    17 
    18 @end

    2.控制器对象

    ViewController.m

      1 #import "ViewController.h"
      2 #import "CZMessage.h"
      3 #import "CZMessageFrame.h"
      4 #import "CZMessageCell.h"
      5 
      6 @interface ViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>
      7 @property (weak, nonatomic) IBOutlet UITableView *tableView;
      8 
      9 // 用来保存所有的消息的frame模型对象
     10 @property (nonatomic, strong) NSMutableArray *messageFrames;
     11 @property (weak, nonatomic) IBOutlet UITextField *txtInput;
     12 
     13 @end
     14 
     15 @implementation ViewController
     16 #pragma mark - /********** 懒加载数据 *********/
     17 - (NSMutableArray *)messageFrames
     18 {
     19     if (_messageFrames == nil) {
     20         NSString *path = [[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil];
     21         NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
     22         
     23         NSMutableArray *arrayModels = [NSMutableArray array];
     24         for (NSDictionary *dict in arrayDict) {
     25             // 创建一个数据模型
     26             CZMessage *model = [CZMessage messageWithDict:dict];
     27             
     28             // 获取上一个数据模型
     29             CZMessage *lastMessage = (CZMessage *)[[arrayModels lastObject] message];
     30             
     31             // 判断当前模型的“消息发送时间”是否和上一个模型的“消息发送时间”一致, 如果一致做个标记
     32             if ([model.time isEqualToString:lastMessage.time]) {
     33                 model.hideTime = YES;
     34             }
     35             
     36             // 创建一个frame 模型
     37             CZMessageFrame *modelFrame = [[CZMessageFrame alloc] init];
     38             
     39             modelFrame.message = model;
     40             
     41             
     42             // 把frame 模型加到arrayModels
     43             [arrayModels addObject:modelFrame];
     44         }
     45         _messageFrames = arrayModels;
     46     }
     47     return _messageFrames;
     48 }
     49 
     50 
     51 #pragma mark - /********** 文本框的代理方法 *********/
     52 //- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
     53 //{
     54 //    return YES;
     55 //}
     56 
     57 // 当键盘上的return键被单击的时候触发
     58 - (BOOL)textFieldShouldReturn:(UITextField *)textField
     59 {
     60     // 1. 获取用户输入的文本
     61     NSString *text = textField.text;
     62     
     63     // 2. 发送用户的消息
     64     [self sendMessage:text withType:CZMessageTypeMe];
     65     
     66     // 3. 发送一个系统消息
     67     [self sendMessage:@"不认识!" withType:CZMessageTypeOther];
     68     
     69     // 清空文本框
     70     textField.text = nil;
     71     
     72     return YES;
     73 }
     74 
     75 // 发送消息
     76 - (void)sendMessage:(NSString *)msg withType:(CZMessageType)type
     77 {
     78     // 2. 创建一个数据模型和frame 模型
     79     CZMessage *model = [[CZMessage alloc] init];
     80     
     81     // 获取当前系统时间
     82     NSDate *nowDate = [NSDate date];
     83     // 创建一个日期时间格式化器
     84     NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
     85     // 设置格式
     86     formatter.dateFormat = @"今天 HH:mm";
     87     // 进行日期时间的格式化
     88     model.time = [formatter stringFromDate:nowDate];
     89     model.type = type;
     90     model.text = msg;
     91     
     92     
     93     
     94     // 根据当前消息的时间和上一条消息的时间, 来设置是否需要隐藏时间Label
     95     CZMessageFrame *lastMessageFrame = [self.messageFrames lastObject];
     96     NSString *lastTime = lastMessageFrame.message.time;
     97     if ([model.time isEqualToString:lastTime]) {
     98         model.hideTime = YES;
     99     }
    100     
    101     //***** 注意: 要先设置数据模型的hideTime属性, 然后再设置modelFrame.message = model;
    102     // 因为在设置modelFrame.message = model;的时候set方法中, 内部会用到model.hideTime属性。
    103     
    104     // 创建一个frame 模型
    105     CZMessageFrame *modelFrame = [[CZMessageFrame alloc] init];
    106     modelFrame.message = model;
    107     
    108     
    109     
    110     // 3. 把frame 模型加到集合中
    111     [self.messageFrames addObject:modelFrame];
    112     
    113     
    114     
    115     
    116     // 4. 刷新UITableView的数据
    117     [self.tableView reloadData];
    118     
    119     // 5. 把最后一行滚动到最上面
    120     NSIndexPath *idxPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];
    121     [self.tableView scrollToRowAtIndexPath:idxPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    122 }
    123 
    124 
    125 
    126 #pragma mark - /********** UITableView的代理方法 *********/
    127 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    128 {
    129     // 把键盘叫回去, 思路: 让控制器所管理的UIView结束编辑
    130     [self.view endEditing:YES];
    131 }
    132 
    133 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    134 {
    135     NSLog(@"★★★★★★★★★");
    136 }
    137 
    138 
    139 
    140 #pragma mark - /********** 数据源方法 *********/
    141 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    142 {
    143     return 1;
    144 }
    145 
    146 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    147 {
    148     return self.messageFrames.count;
    149 }
    150 
    151 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    152 {
    153     // 1. 获取模型数据
    154     CZMessageFrame *modelFrame = self.messageFrames[indexPath.row];
    155     
    156     // 2. 创建单元格
    157     
    158     CZMessageCell *cell = [CZMessageCell messageCellWithTableView:tableView];
    159     
    160     // 3. 把模型设置给单元格对象
    161     cell.messageFrame = modelFrame;
    162     
    163     // 4.返回单元格
    164     return cell;
    165 }
    166 
    167 // 返回每一行的行高
    168 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    169 {
    170     CZMessageFrame *messageFrame = self.messageFrames[indexPath.row];
    171     return messageFrame.rowHeight;
    172 }
    173 
    174 
    175 
    176 #pragma mark - /********** 其他 *********/
    177 - (void)viewDidLoad {
    178     [super viewDidLoad];
    179     // 取消分割线
    180     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    181     
    182     // 设置UITableView的背景色
    183     self.tableView.backgroundColor = [UIColor colorWithRed:236 / 255.0 green:236 / 255.0 blue:236 / 255.0 alpha:1.0];
    184     
    185     // 设置UITableView的行不允许被选中
    186     self.tableView.allowsSelection = NO;
    187     
    188     // 设置文本框最左侧有一段间距
    189     UIView *leftVw = [[UIView alloc] init];
    190     leftVw.frame = CGRectMake(0, 0, 5, 1);
    191     
    192     // 把leftVw设置给文本框
    193     self.txtInput.leftView = leftVw;
    194     self.txtInput.leftViewMode = UITextFieldViewModeAlways;
    195     
    196     
    197     // 监听键盘的弹出事件
    198     // 1. 创建一个NSNotificationCenter对象。
    199     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    200     
    201     // 2. 监听键盘的弹出通知
    202     [center addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
    203     
    204 }
    205 
    206 - (void)keyboardWillChangeFrame:(NSNotification *)noteInfo
    207 {
    208 //    NSLog(@"通知名称: %@", noteInfo.name);
    209 //    
    210 //    NSLog(@"通知的发布者: %@", noteInfo.object);
    211 //    
    212 //    NSLog(@"通知的具体内容: %@", noteInfo.userInfo);
    213     // 1. 获取当键盘显示完毕或者隐藏完毕后的Y值
    214     CGRect rectEnd = [noteInfo.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    215     CGFloat keyboardY = rectEnd.origin.y;
    216     
    217     // 用键盘的Y值减去屏幕的高度计算出平移的值
    218     // 1. 如果是键盘弹出事件, 那么计算出的值就是负的键盘的高度
    219     // 2. 如果是键盘的隐藏事件, 那么计算出的值就是零, 因为键盘在隐藏以后, 键盘的Y值就等于屏幕的高度。
    220     CGFloat tranformValue = keyboardY - self.view.frame.size.height;
    221     
    222     [UIView animateWithDuration:0.25 animations:^{
    223         // 让控制器的View执行一次“平移”
    224         self.view.transform = CGAffineTransformMakeTranslation(0, tranformValue);
    225     }];
    226     
    227     
    228     
    229     // 让UITableView的最后一行滚动到最上面
    230     NSIndexPath *lastRowIdxPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];
    231     [self.tableView scrollToRowAtIndexPath:lastRowIdxPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    232 }
    233 
    234 
    235 // ***************** 注意: 监听通知以后一定要在监听通知的对象的dealloc方法中移除监听 *************/.
    236 
    237 - (void)dealloc
    238 {
    239     // 移除通知
    240     [[NSNotificationCenter defaultCenter] removeObserver:self];
    241 }
    242 
    243 
    244 - (void)didReceiveMemoryWarning {
    245     [super didReceiveMemoryWarning];
    246     // Dispose of any resources that can be recreated.
    247 }
    248 
    249 - (BOOL)prefersStatusBarHidden
    250 {
    251     return YES;
    252 }
    253 
    254 @end

    3.自定义的cell对象

    CZMessageCell.h

     1 #import <UIKit/UIKit.h>
     2 
     3 @class CZMessageFrame;
     4 @interface CZMessageCell : UITableViewCell
     5 
     6 // 为自定义单元格增加一个frame 模型属性
     7 @property (nonatomic, strong) CZMessageFrame *messageFrame;
     8 
     9 
    10 // 封装一个创建自定义Cell的方法
    11 + (instancetype)messageCellWithTableView:(UITableView *)tableView;
    12 
    13 @end

    CZMessageCell.m

      1 #import "CZMessageCell.h"
      2 #import "CZMessage.h"
      3 #import "CZMessageFrame.h"
      4 
      5 @interface CZMessageCell ()
      6 
      7 @property (nonatomic, weak) UILabel *lblTime;
      8 @property (nonatomic, weak) UIImageView *imgViewIcon;
      9 @property (nonatomic, weak) UIButton *btnText;
     10 @end
     11 
     12 
     13 @implementation CZMessageCell
     14 
     15 #pragma mark -  重写initWithStyle方法
     16 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
     17 {
     18     if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
     19         // 创建子控件
     20         
     21         // 显示时间的label
     22         UILabel *lblTime = [[UILabel alloc] init];
     23         // 设置文字大小
     24         lblTime.font = [UIFont systemFontOfSize:12];
     25         // 设置文字居中
     26         lblTime.textAlignment = NSTextAlignmentCenter;
     27         [self.contentView addSubview:lblTime];
     28         self.lblTime = lblTime;
     29         
     30         
     31         // 显示头像的UIImageView
     32         UIImageView *imgViewIcon = [[UIImageView alloc] init];
     33         [self.contentView addSubview:imgViewIcon];
     34         self.imgViewIcon = imgViewIcon;
     35         
     36         
     37         // 显示正文的按钮
     38         UIButton *btnText = [[UIButton alloc] init];
     39         // 设置正文的字体大小
     40         btnText.titleLabel.font = textFont;
     41         // 修改按钮的正文文字颜色
     42         [btnText setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
     43         // 设置按钮中的label的文字可以换行
     44         btnText.titleLabel.numberOfLines = 0;
     45         // 设置按钮的背景色
     46         //btnText.backgroundColor = [UIColor purpleColor];
     47         
     48         // 设置按钮中的titleLabel的背景色
     49         //btnText.titleLabel.backgroundColor = [UIColor greenColor];
     50         
     51         // 设置按钮的内边距
     52         btnText.contentEdgeInsets = UIEdgeInsetsMake(15, 20, 15, 20);
     53         
     54         [self.contentView addSubview:btnText];
     55         self.btnText = btnText;
     56     }
     57     
     58     // 设置单元格的背景色为clearColor
     59     self.backgroundColor = [UIColor clearColor];
     60     return self;
     61 }
     62 
     63 
     64 #pragma mark -  重写frame 模型的set方法
     65 - (void)setMessageFrame:(CZMessageFrame *)messageFrame
     66 {
     67     _messageFrame = messageFrame;
     68     
     69     // 获取数据模型
     70     CZMessage *message = messageFrame.message;
     71     
     72     // 分别设置每个子控件的数据 和 frame
     73     
     74     // 设置 "时间Label"的数据 和 frame
     75     self.lblTime.text = message.time;
     76     self.lblTime.frame = messageFrame.timeFrame;
     77     self.lblTime.hidden = message.hideTime;
     78     
     79     
     80     
     81     // 设置 头像
     82     // 根据消息类型, 判断应该使用哪张图片
     83     NSString *iconImg = message.type == CZMessageTypeMe ? @"me" : @"other";
     84     self.imgViewIcon.image = [UIImage imageNamed:iconImg];
     85     self.imgViewIcon.frame = messageFrame.iconFrame;
     86     
     87     
     88     // 设置消息正文
     89     [self.btnText setTitle:message.text forState:UIControlStateNormal];
     90     self.btnText.frame = messageFrame.textFrame;
     91     
     92     
     93     // 设置正文的背景图
     94     NSString *imgNor, *imgHighlighted;
     95     if (message.type == CZMessageTypeMe) {
     96         // 自己发的消息
     97         imgNor = @"chat_send_nor";
     98         imgHighlighted = @"chat_send_press_pic";
     99         
    100         // 设置消息的正文文字颜色为 "白色"
    101         [self.btnText setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    102     } else {
    103         // 对方发的消息
    104         imgNor = @"chat_recive_nor";
    105         imgHighlighted = @"chat_recive_press_pic";
    106         
    107        // 设置消息的正文文字颜色为 "黑色"
    108         [self.btnText setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    109     }
    110     
    111     // 加载图片
    112     UIImage *imageNormal = [UIImage imageNamed:imgNor];
    113     UIImage *imageHighlighted = [UIImage imageNamed:imgHighlighted];
    114     
    115     // 用平铺的方式拉伸图片
    116     imageNormal = [imageNormal stretchableImageWithLeftCapWidth:imageNormal.size.width * 0.5 topCapHeight:imageNormal.size.height * 0.5];
    117     imageHighlighted = [imageHighlighted stretchableImageWithLeftCapWidth:imageHighlighted.size.width * 0.5 topCapHeight:imageHighlighted.size.height * 0.5];
    118     
    119     // 设置背景图
    120     [self.btnText setBackgroundImage:imageNormal forState:UIControlStateNormal];
    121     [self.btnText setBackgroundImage:imageHighlighted forState:UIControlStateHighlighted];
    122 }
    123 
    124 
    125 #pragma mark -  创建自定义Cell的方法
    126 + (instancetype)messageCellWithTableView:(UITableView *)tableView
    127 {
    128     static NSString *ID = @"message_cell";
    129     CZMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    130     if (cell == nil) {
    131         cell = [[CZMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    132     }
    133     return cell;
    134 }
    135 
    136 - (void)awakeFromNib {
    137     // Initialization code
    138 }
    139 
    140 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    141     [super setSelected:selected animated:animated];
    142 
    143     // Configure the view for the selected state
    144 }
    145 
    146 @end

    4.消息模型

    CZMessage.h

     1 #import <Foundation/Foundation.h>
     2 
     3 typedef enum {
     4     CZMessageTypeMe = 0,    // 表示自己
     5     CZMessageTypeOther = 1  // 表示对方
     6 } CZMessageType;
     7 
     8 
     9 @interface CZMessage : NSObject
    10 
    11 // 消息正文
    12 @property (nonatomic, copy) NSString *text;
    13 
    14 // 消息发送时间
    15 @property (nonatomic, copy) NSString *time;
    16 
    17 // 消息的类型(表示是对方发送的消息还是自己发送的消息)
    18 @property (nonatomic, assign) CZMessageType type;
    19 
    20 // 用来记录是否需要显示"时间Label"
    21 @property (nonatomic, assign) BOOL hideTime;
    22 
    23 
    24 
    25 - (instancetype)initWithDict:(NSDictionary *)dict;
    26 + (instancetype)messageWithDict:(NSDictionary *)dict;
    27 
    28 @end

    CZMeesge.m

     1 #import "CZMessage.h"
     2 
     3 @implementation CZMessage
     4 
     5 - (instancetype)initWithDict:(NSDictionary *)dict
     6 {
     7     if (self = [super init]) {
     8         [self setValuesForKeysWithDictionary:dict];
     9     }
    10     return self;
    11 }
    12 
    13 + (instancetype)messageWithDict:(NSDictionary *)dict
    14 {
    15     return [[self alloc] initWithDict:dict];
    16 }
    17 @end

    5.展示信息的frame

    CZMessageFram.h

     1 #import <Foundation/Foundation.h>
     2 #import <CoreGraphics/CoreGraphics.h>
     3 #define textFont [UIFont systemFontOfSize:13]
     4 
     5 @class CZMessage;
     6 @interface CZMessageFrame : NSObject
     7 
     8 // 引用数据模型
     9 @property (nonatomic, strong) CZMessage *message;
    10 
    11 // 时间Label的frame
    12 @property (nonatomic, assign, readonly) CGRect timeFrame;
    13 
    14 // 头像的frame
    15 @property (nonatomic, assign, readonly) CGRect iconFrame;
    16 
    17 // 正文的frame
    18 @property (nonatomic, assign, readonly) CGRect textFrame;
    19 
    20 // 行高
    21 @property (nonatomic, assign, readonly) CGFloat rowHeight;
    22 
    23 @end

    CZMessageFrame.m

     1 #import "CZMessageFrame.h"
     2 #import <UIKit/UIKit.h>
     3 #import "CZMessage.h"
     4 #import "NSString+CZNSStringExt.h"
     5 
     6 @implementation CZMessageFrame
     7 
     8 - (void)setMessage:(CZMessage *)message
     9 {
    10     _message = message;
    11     
    12     // 计算每个控件的frame 和 行高
    13     // 获取屏幕宽度
    14     CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
    15     // 设置一个统一的间距
    16     CGFloat margin = 5;
    17     
    18     // 计算时间label的frame
    19     CGFloat timeX = 0;
    20     CGFloat timeY = 0;
    21     CGFloat timeW = screenW;
    22     CGFloat timeH = 15;
    23     if (!message.hideTime) {
    24         // 如果需要显示时间label, 那么再计算时间label的frame
    25         _timeFrame = CGRectMake(timeX, timeY, timeW, timeH);
    26     }
    27     
    28     
    29     
    30     // 计算头像的frame
    31     CGFloat iconW = 30;
    32     CGFloat iconH = 30;
    33     CGFloat iconY = CGRectGetMaxY(_timeFrame) + margin;
    34     CGFloat iconX = message.type == CZMessageTypeOther ? margin : screenW - margin - iconW;
    35     _iconFrame = CGRectMake(iconX, iconY, iconW, iconH);
    36     
    37     
    38 
    39     // 计算消息正文的frame
    40     // 1. 先计算正文的大小
    41     CGSize textSize = [message.text sizeOfTextWithMaxSize:CGSizeMake(200, MAXFLOAT) font:textFont];
    42     CGFloat textW = textSize.width + 40;
    43     CGFloat textH = textSize.height + 30;
    44     // 2. 再计算x,y
    45     CGFloat textY = iconY;
    46     CGFloat textX = message.type == CZMessageTypeOther ? CGRectGetMaxX(_iconFrame) : (screenW - margin - iconW - textW);
    47     _textFrame = CGRectMake(textX, textY, textW, textH);
    48     
    49     
    50     
    51     // 计算行高
    52     // 获取 头像的最大的Y值和正文的最大的Y值, 然后用最大的Y值+ margin
    53     CGFloat maxY = MAX(CGRectGetMaxY(_textFrame), CGRectGetMaxY(_iconFrame));
    54     _rowHeight = maxY + margin;
    55     
    56 }
    57 @end

    方案四,好友列表

    几个要注意的:

    1.组上得图标旋转后变形

    2.cell重用的问题

    这里直接继承的TableViewController控制器 直接上代码了

    CZQQFriendsTableViewController.m

      1 #import "CZQQFriendsTableViewController.h"
      2 #import "CZGroup.h"
      3 #import "CZFriend.h"
      4 #import "CZFriendCell.h"
      5 #import "CZGroupHeaderView.h"
      6 
      7 @interface CZQQFriendsTableViewController () <CZGroupHeaderViewDelegate>
      8 
      9 // 保存所有的朋友信息(分组信息)
     10 @property (nonatomic, strong) NSArray *groups;
     11 @end
     12 
     13 @implementation CZQQFriendsTableViewController
     14 
     15 #pragma mark - *********** 懒加载 ***********
     16 - (NSArray *)groups
     17 {
     18     if (_groups == nil) {
     19         NSString *path = [[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil];
     20         NSArray *arrayDicts = [NSArray arrayWithContentsOfFile:path];
     21         
     22         NSMutableArray *arrayModels = [NSMutableArray array];
     23         for (NSDictionary *dict in arrayDicts) {
     24             CZGroup *model = [CZGroup groupWithDict:dict];
     25             [arrayModels addObject:model];
     26         }
     27         _groups = arrayModels;
     28         
     29     }
     30     return _groups;
     31 }
     32 
     33 
     34 #pragma mark - *********** CZGroupHeaderViewDelegate的代理方法 ***********
     35 - (void)groupHeaderViewDidClickTitleButton:(CZGroupHeaderView *)groupHeaderView
     36 {
     37     // 刷新table view
     38     //[self.tableView reloadData];
     39     
     40     // 局部刷新(只刷新某个组)
     41     // 创建一个用来表示某个组的对象
     42     NSIndexSet *idxSet = [NSIndexSet indexSetWithIndex:groupHeaderView.tag];
     43     [self.tableView reloadSections:idxSet withRowAnimation:UITableViewRowAnimationFade];
     44 }
     45 
     46 
     47 
     48 
     49 
     50 #pragma mark - *********** 实现数据源方法 ***********
     51 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
     52 {
     53     return self.groups.count;
     54 }
     55 
     56 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
     57 {
     58     // 因为在这个方法中, 要根据当前组的状态(是否是展开), 来设置不同的返回值
     59     // 所以, 需要为CZGroup模型增加一个用来保存"是否展开"状态的属性
     60     CZGroup *group = self.groups[section];
     61     if (group.isVisible) {
     62         return group.friends.count;
     63     } else {
     64         return 0;
     65     }
     66     
     67 }
     68 
     69 // 返回每行的单元格
     70 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
     71 {
     72     // 1. 获取模型对象(数据)
     73     CZGroup *group = self.groups[indexPath.section];
     74     CZFriend *friend = group.friends[indexPath.row];
     75     
     76     // 2. 创建单元格(视图)
     77     CZFriendCell *cell = [CZFriendCell friendCellWithTableView:tableView];
     78     
     79     // 3. 设置单元格数据(把模型设置给单元格)
     80     cell.friendModel = friend;
     81     
     82     // 4. 返回单元格
     83     return cell;
     84 }
     85 
     86 
     87 //// 设置每一组的组标题(下面的这个方法只能设置每一组的组标题字符串, 但是我们要的是每一组中还包含其他子控件)
     88 //- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
     89 //{
     90 //    CZGroup *group = self.groups[section];
     91 //    return group.name;
     92 //}
     93 
     94 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
     95 {
     96     // 不要在这个方法中直接创建一个UIView对象返回, 因为这样无法实现重用该UIView
     97     // 为了能重用每个Header中的UIView, 所以这里要返回一个UITableViewHeaderFooterView
     98     // 1. 获取模型数据
     99     CZGroup *group = self.groups[section];
    100     
    101     
    102     // 2. 创建UITableViewHeaderFooterView
    103     CZGroupHeaderView *headerVw = [CZGroupHeaderView groupHeaderViewWithTableView:tableView];
    104     headerVw.tag = section;
    105     
    106     // 3. 设置数据
    107     headerVw.group = group;
    108     
    109     // 设置headerView的代理为当前控制器
    110     headerVw.delegate = self;
    111     
    112     
    113     // 在刚刚创建好的header view中获取的header view的frame都是0, 因为刚刚创建好的header view我们没有为其frame赋值, 所以frame都是 0
    114     // 但是, 程序运行起来以后, 我们看到的header view是有frame的。原因是: 在当前方法当中, 将header view返回以后, UITableView在执行的时候, 会用到header view, UITableView既然要用Header View, 那么就必须将header view添加到UITableview中, 当把header view添加到UITableView中的时候, UITableView内部会根据一些设置来动态的为header view的frame赋值,也就是说在UITableView即将使用header view的时候, 才会为header view的frame赋值。
    115     
    116     // 4. 返回view
    117     return headerVw;
    118     
    119     
    120 }
    121 
    122 
    123 
    124 
    125 #pragma mark - *********** 隐藏状态栏 ***********
    126 - (BOOL)prefersStatusBarHidden
    127 {
    128     return YES;
    129 }
    130 
    131 
    132 #pragma mark - *********** 控制器的viewDidLoad方法 ***********
    133 - (void)viewDidLoad
    134 {
    135     [super viewDidLoad];
    136     
    137     // 统一设置每组的组标题的高度
    138     self.tableView.sectionHeaderHeight = 44;
    139 }
    140 
    141 @end

    cell模型对象

    CZFriendCell.h

    1 #import <UIKit/UIKit.h>
    2 @class CZFriend;
    3 @interface CZFriendCell : UITableViewCell
    4 
    5 + (instancetype)friendCellWithTableView:(UITableView *)tableView;
    6 
    7 @property (nonatomic, strong) CZFriend *friendModel;
    8 @end

    CZFriendCell.m

     1 #import "CZFriendCell.h"
     2 #import "CZFriend.h"
     3 
     4 @implementation CZFriendCell
     5 
     6 
     7 + (instancetype)friendCellWithTableView:(UITableView *)tableView
     8 {
     9     static NSString *ID = @"friend_cell";
    10     CZFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    11     if (cell == nil) {
    12         cell = [[CZFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    13     }
    14     return cell;
    15 }
    16 
    17 
    18 - (void)setFriendModel:(CZFriend *)friendModel
    19 {
    20     _friendModel = friendModel;
    21     
    22     // 把模型中的数据设置给单元格的子控件
    23     self.imageView.image = [UIImage imageNamed:friendModel.icon];
    24     self.textLabel.text = friendModel.name;
    25     self.detailTextLabel.text = friendModel.intro;
    26     
    27     // 根据当前的好友是不是vip来决定是否要将"昵称"显示为红色
    28     self.textLabel.textColor = friendModel.isVip ? [UIColor redColor] : [UIColor blackColor];
    29 }
    30 
    31 
    32 - (void)awakeFromNib {
    33     // Initialization code
    34 }
    35 
    36 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    37     [super setSelected:selected animated:animated];
    38 
    39     // Configure the view for the selected state
    40 }
    41 
    42 @end

    CZGroupHeaderView.h

     1 #import <UIKit/UIKit.h>
     2 @class CZGroupHeaderView;
     3 @protocol CZGroupHeaderViewDelegate <NSObject>
     4 
     5 - (void)groupHeaderViewDidClickTitleButton:(CZGroupHeaderView *)groupHeaderView;
     6 
     7 @end
     8 
     9 
    10 @class CZGroup;
    11 @interface CZGroupHeaderView : UITableViewHeaderFooterView
    12 
    13 @property (nonatomic, strong) CZGroup *group;
    14 
    15 + (instancetype)groupHeaderViewWithTableView:(UITableView *)tableView;
    16 
    17 // 增加一个代理属性
    18 @property (nonatomic, weak) id<CZGroupHeaderViewDelegate> delegate;
    19 
    20 @end

    CZGroupHeaderView.m

      1 #import "CZGroupHeaderView.h"
      2 #import "CZGroup.h"
      3 
      4 @interface CZGroupHeaderView ()
      5 
      6 @property (nonatomic, weak) UIButton *btnGroupTitle;
      7 
      8 @property (nonatomic, weak) UILabel *lblCount;
      9 
     10 @end
     11 
     12 
     13 @implementation CZGroupHeaderView
     14 
     15 
     16 // 封装一个类方法来创建一个header view
     17 + (instancetype)groupHeaderViewWithTableView:(UITableView *)tableView
     18 {
     19     static NSString *ID = @"group_header_view";
     20     CZGroupHeaderView *headerVw = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
     21     if (headerVw == nil) {
     22         headerVw = [[CZGroupHeaderView alloc] initWithReuseIdentifier:ID];
     23     }
     24     return headerVw;
     25 }
     26 
     27 // 重写initWithReuseIdentifier方法, 在创建headerView的时候, 同时创建子控件
     28 - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
     29 {
     30     if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
     31         // 创建按钮
     32         UIButton *btnGroupTitle = [[UIButton alloc] init];
     33         // 设置按钮的图片(三角图片)
     34         [btnGroupTitle setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];
     35         // 设置按钮的文字颜色
     36         [btnGroupTitle setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
     37         // 设置按钮默认的背景图片和高亮时的背景图片
     38         [btnGroupTitle setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];
     39         // 设置按钮高亮的背景图片和高亮时的背景图片
     40         [btnGroupTitle setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];
     41         // 设置按钮中内容整体左对齐
     42         btnGroupTitle.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
     43         // 设置按钮的内容的内边距
     44         btnGroupTitle.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
     45         // 设置按钮标题距离左边的边距
     46         btnGroupTitle.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 0);
     47         
     48         // 为按钮增加一个点击事件
     49         [btnGroupTitle addTarget:self action:@selector(btnGroupTitleClicked) forControlEvents:UIControlEventTouchUpInside];
     50         
     51         // 设置按钮中图片的现实模式
     52         btnGroupTitle.imageView.contentMode = UIViewContentModeCenter;
     53         // 设置图片框超出的部分不要截掉
     54         btnGroupTitle.imageView.clipsToBounds = NO;
     55         
     56         [self.contentView addSubview:btnGroupTitle];
     57         self.btnGroupTitle = btnGroupTitle;
     58         
     59         // 创建lable
     60         UILabel *lblCount = [[UILabel alloc] init];
     61         [self.contentView addSubview:lblCount];
     62         self.lblCount = lblCount;
     63     }
     64     return self;
     65 }
     66 
     67 
     68 // 组标题按钮的点击事件
     69 - (void)btnGroupTitleClicked
     70 {
     71     // 1. 设置组的状态
     72     self.group.visible = !self.group.isVisible;
     73     
     74 //    // 2.刷新tableView
     75     // 通过代理来实现
     76     if ([self.delegate respondsToSelector:@selector(groupHeaderViewDidClickTitleButton:)]) {
     77         // 调用代理方法
     78         [self.delegate groupHeaderViewDidClickTitleButton:self];
     79     }
     80     
     81    
     82 }
     83 
     84 // 当一个新的header view 已经加到某个父控件中的时候执行这个方法。
     85 - (void)didMoveToSuperview
     86 {
     87     if (self.group.isVisible) {
     88         // 3. 让按钮中的图片实现旋转
     89         self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
     90     } else {
     91         self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(0);
     92     }
     93 }
     94 
     95 // 重写group属性的set方法
     96 - (void)setGroup:(CZGroup *)group
     97 {
     98     _group = group;
     99     // 设置数据
    100     
    101     // 设置按钮上的文字
    102     [self.btnGroupTitle setTitle:group.name forState:UIControlStateNormal];
    103     // 设置 lblCount商的文字
    104     self.lblCount.text = [NSString stringWithFormat:@"%d / %d", group.online, group.friends.count];
    105     
    106     // 设置按钮中的图片旋转问题
    107     if (self.group.isVisible) {
    108         // 3. 让按钮中的图片实现旋转
    109         self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
    110     } else {
    111         self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(0);
    112     }
    113     
    114     
    115     // 设置frame不要写在这里, 因为在这里获取的当前控件(self)的宽和高都是0
    116     
    117     
    118    
    119 }
    120 
    121 // 当当前控件的frame发生改变的时候会调用这个方法
    122 - (void)layoutSubviews
    123 {
    124     [super layoutSubviews];
    125     
    126     // 设置按钮的frame
    127     self.btnGroupTitle.frame = self.bounds;
    128     //NSLog(@"%@", NSStringFromCGRect(self.btnGroupTitle.frame));
    129     
    130     // 设置lable的frame
    131     CGFloat lblW = 100;
    132     CGFloat lblH = self.bounds.size.height;
    133     CGFloat lblX = self.bounds.size.width - 10 - lblW;
    134     CGFloat lblY = 0;
    135     self.lblCount.frame = CGRectMake(lblX, lblY, lblW, lblH);
    136     //NSLog(@"%@", NSStringFromCGRect(self.lblCount.frame));
    137 }
    138 
    139 /*
    140 // Only override drawRect: if you perform custom drawing.
    141 // An empty implementation adversely affects performance during animation.
    142 - (void)drawRect:(CGRect)rect {
    143     // Drawing code
    144 }
    145 */
    146 
    147 @end
  • 相关阅读:
    一周见闻速记
    glibc下的内存管理
    流(flow)
    Liunx学习笔记
    逆向工程androidAPK(待补充)
    Ubuntu Linux环境搭建|软件篇
    Ubuntu Linux 源记录
    android 权限
    Android源码下载(ubuntu12.04(amd64))
    游戏外挂编程之神器CE的使用
  • 原文地址:https://www.cnblogs.com/developer-wang/p/4529664.html
Copyright © 2020-2023  润新知