再续tableView

#pragma mark - 数据源方法
// 如果没有实现,默认是1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 2;
}


// 每个分组中的数据总数
// sction:分组的编号
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        // 第0个分组
        return 5;
    } else {
        return 18;
    }
}


// 告诉表格控件,每一行cell单元格的细节
// indexPath
//  @property(nonatomic,readonly) NSInteger section;    分组
//  @property(nonatomic,readonly) NSInteger row;        行
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 实例化TableViewCell时,使用initWithStyle方法来进行实例化
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    
    cell.textLabel.text = [NSString stringWithFormat:@"XXXX %02d X - %04d", indexPath.section, indexPath.row];
    
    return cell;
}


// 返回分组的标题文字
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return [NSString stringWithFormat:@"XXX %02d X", section];
}


- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
    if (section == 0) {
        return @"太牛叉了";
    } else {
        return @"牛叉闪闪亮";
    }
}




必备代码:
- (instancetype)initWithDict:(NSDictionary *)dict
{
    self = [super init];
    if (self) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}


+ (instancetype)heroWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}


+ (NSArray *)heros
{
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"heros.plist" ofType:nil]];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSDictionary *dict in array) {
        [arrayM addObject:[self heroWithDict:dict]];
    }
    
    return arrayM;
}






/**
 UITableViewCellStyleDefault,   默认类型 标题+可选图像
 UITableViewCellStyleValue1,    标题+明细+图像
 UITableViewCellStyleValue2,    不显示图像,标题+明细
 UITableViewCellStyleSubtitle   标题+明细+图像
 */
// 告诉表格每个单元格的明细信息
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"表格行明细 %d", indexPath.row);
    
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
    
    // 取出英雄对象
    HMHero *hero = self.heros[indexPath.row];
    
    // 标题
    cell.textLabel.text = hero.name;
    // 明细信息
    cell.detailTextLabel.text = hero.intro;
    // 图像
    cell.imageView.image = [UIImage imageNamed:hero.icon];
    
    // 设置右边的箭头
    // 1> UITableViewCellAccessoryDisclosureIndicator 箭头,可以"提示"用户,当前行是可以点击的,通常选中行,会跳到新的页面
    // 2> UITableViewCellAccessoryCheckmark 对号,通常提示用户该行数据设置完毕,使用的比较少
    // 3> UITableViewCellAccessoryDetailButton 按钮,通常点击按钮可以做独立的操作,例如alertView
    //    点击按钮并不会选中行
    // 4> UITableViewCellAccessoryDetailDisclosureButton 按钮+箭头,各自操作
//    cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
    
    // 指定右侧的自定义视图
    /**
     通常accessoryType提供的类型不能满足时,才会使用自定义控件
     
     但是需要自行添加监听方法,通常用在自定义cell,不要写在视图控制器中!!!
     
     自定义控件的事件触发,同样不会影响表格行的选中!
     */
    UISwitch *switcher = [[UISwitch alloc] init];
    // 添加监听方法
    [switcher addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
    
    cell.accessoryView = switcher;
    
    return cell;
}


/**
 代理方法的优先级比rowHeight优先级高
 
 应用场景:很多应用程序,每一行的高度是不一样的,例如:新浪微博
 
 表格工作观察的小结
 
 1> 要知道总共有多少数据
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 
 2> 计算“每一行”的行高
 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 
 问题:在此方法执行时,cell被实例化了吗?
 方法的作用是什么?
 
 scrollView需要指定contentSize才能够滚动,如果没有实现方法,行高默认是44
 
 需要知道每一行的高度,才能够准确的计算出contentSize
 
 知道每一行的高度后,自然知道每一个屏幕应该显示多少行,表格明细方法的执行次数就知道了
 
 3> 表格明细
 调用屏幕显示所需要的行数,懒加载,只有要显示的表格行,才会被实例化!
 
 小的结论:
 
 *  tableView.rowHeight:    效率高,适用于所有的表格行高度一致
 *  代理方法指定行高:          效率差,适合于每一个行的行高不一样,能够让表格更加的灵活
 
 */






- (instancetype)initWithDict:(NSDictionary *)dict
{
    self = [super init];
    if (self) {
//        [self setValuesForKeysWithDictionary:dict];
        [self setValue:dict[@"title"] forKey:@"title"];
        
        // dict[@"cars"]存放的是字典的数组
        // 希望将字典的数组转换成HMCar模型的数组
//        [self setValue:dict[@"cars"] forKey:@"cars"];
        self.cars = [HMCar carsWithArray:dict[@"cars"]];
    }
    return self;
}


+ (instancetype)carGroupWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}


+ (NSArray *)carGroups
{
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cars_total.plist" ofType:nil]];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSDictionary *dict in array) {
        [arrayM addObject:[self carGroupWithDict:dict]];
    }
    
    return arrayM;
}


- (NSString *)description
{
    return [NSString stringWithFormat:@"<%@: %p> {title: %@, cars: %@}", self.class, self, self.title, self.cars];
}






// 单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 可重用标示符
    static NSString *ID = @"Cell";
    
    // 让表格缓冲区查找可重用cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    // 如果没有找到可重用cell
    if (cell == nil) {
        // 实例化cell
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    
    // 设置cell内容
    // 1> 取出数据模型
    HMCarGroup *group = self.carGroups[indexPath.section];
    HMCar *car = group.cars[indexPath.row];
    
    // 2> 设置数据
    cell.imageView.image = [UIImage imageNamed:car.icon];
    cell.textLabel.text = car.name;
    
    return cell;
}






// 右侧索引列表
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    // 索引数组中的"内容",跟分组无关
    // 索引数组中的下标,对应的是分组的下标
//    return @[@"哇哈哈", @"hello", @"哇哈哈", @"hello", @"哇哈哈", @"hello", @"哇哈哈", @"hello"];
    
    // 返回self.carGroup中title的数组
//    NSMutableArray *arrayM = [NSMutableArray array];
//    for (HMCarGroup *group in self.carGroups) {
//        [arrayM addObject:group.title];
//    }
//    return arrayM;
    
    // KVC是cocoa的大招
    // 用来间接获取或者修改对象属性的方式
    // 使用KVC在获取数值时,如果指定对象不包含keyPath的"键名",会自动进入对象的内部查找
    // 如果取值的对象是一个数组,同样返回一个数组
    NSArray *array = [self.carGroups valueForKeyPath:@"cars.name"];
    NSLog(@"%@", array);
    
    return [self.carGroups valueForKeyPath:@"title"];
}






// 只要实现了此方法,就能够支持手势拖拽删除了,删除需要自己干!
/**
 UITableViewCellEditingStyleNone,
 UITableViewCellEditingStyleDelete,     删除
 UITableViewCellEditingStyleInsert      添加
 */
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSLog(@"要删除");
        
        // MVC => 数据是保存在模型中
        // 1. 删除self.dataList中indexPath对应的数据
        [self.dataList removeObjectAtIndex:indexPath.row];
        NSLog(@"%@", self.dataList);
        
        // 2. 刷新表格(重新加载数据)
        // 重新加载所有数据
//        [self.tableView reloadData];
        // deleteRowsAtIndexPaths让表格控件动画删除指定的行
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        NSLog(@"要添加数据");
        
        // 1. 向数组添加数据
        [self.dataList insertObject:@"王小二" atIndex:indexPath.row + 1];
        // 2. 刷新表格
//        [self.tableView reloadData];
        // insertRowsAtIndexPaths让表格控件动画在指定indexPath添加指定行
        // 新建一个indexPath
        NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
 
        [self.tableView insertRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationMiddle];
    }
}


// 只要实现此方法,就可以显示拖动控件
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    // 界面数据UITableView已经完成了
    // 调整数据即可
//    [self.dataList exchangeObjectAtIndex:sourceIndexPath.row withObjectAtIndex:destinationIndexPath.row];
    // 1. 将源从数组中取出
    id source = self.dataList[sourceIndexPath.row];
    // 2. 将源从数组中删除
    [self.dataList removeObjectAtIndex:sourceIndexPath.row];
    NSLog(@"%@", self.dataList);
    
    // 3. 将源插入到数组中的目标位置
    [self.dataList insertObject:source atIndex:destinationIndexPath.row];
    
    NSLog(@"%@", self.dataList);
}


#pragma mark - 代理方法
// 返回编辑样式,如果没有实现此方法,默认都是删除
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
//    if (indexPath.row % 2) {
//        return UITableViewCellEditingStyleInsert;
//    } else {
//        return UITableViewCellEditingStyleDelete;
//    }
    return UITableViewCellEditingStyleInsert;
}




#pragma mark - 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.tgs.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1. 可重用标示符
    static NSString *ID = @"Cell";
    // 2. tableView查询可重用Cell
    HMTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    // 3. 如果没有可重用cell
    if (cell == nil) {
//        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
        // 从XIB加载自定义视图
        cell = [[[NSBundle mainBundle] loadNibNamed:@"HMTgCell" owner:nil options:nil] lastObject];
    }
    
    // 4. 设置Cell内容
    // 1> 取出模型
    HMTg *tg = self.tgs[indexPath.row];
    
//    cell.textLabel.text = tg.title;
//    cell.imageView.image = [UIImage imageNamed:tg.icon];
//    
//    cell.detailTextLabel.text = [NSString stringWithFormat:@"¥%@           已有%@人购买", tg.price, tg.buyCount];
    cell.titleLabel.text = tg.title;
    cell.iconView.image = [UIImage imageNamed:tg.icon];
    cell.priceLabel.text = tg.price;
    cell.buyCountLabel.text = tg.buyCount;
    
    return cell;
}












- (void)setStatus:(HMStatus *)status
{
    _status = status;
    
    // 0. 定义间距
    CGFloat padding = 10;
    
    // 1. 头像
    CGFloat iconX = padding;
    CGFloat iconY = padding;
    CGFloat iconW = 30;
    CGFloat iconH = 30;
    self.iconF = CGRectMake(iconX, iconY, iconW, iconH);
    
    // 2. 姓名大小由文字的长度来决定
    // boundingRectWithSize计算给定文本字符串所占的区域
    // 返回值是一个x,y = 0的CGRect,w,h是计算好的宽高
    //
    // 如果要计算多行的准确高度,需要传入NSStringDrawingUsesLineFragmentOrigin选项
    // dict用于指定字体的相关属性的字典,UIKit框架中的第一个头文件
    // context: nil
    NSDictionary *nameDict = @{NSFontAttributeName: kNameFont};
    CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];
    nameFrame.origin.x = CGRectGetMaxX(self.iconF) + padding;
    nameFrame.origin.y = padding + (self.iconF.size.height - nameFrame.size.height) * 0.5;
    self.nameF = nameFrame;
    
    // vip图标
    CGFloat vipX = CGRectGetMaxX(self.nameF) + padding;
    CGFloat vipY = self.nameF.origin.y;
    CGFloat vipW = 14;
    CGFloat vipH = 14;
    self.vipF = CGRectMake(vipX, vipY, vipW, vipH);
    
    // 正文
    NSDictionary *textDict = @{NSFontAttributeName: kTextFont};
    CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];
    textFrame.origin.x = padding;
    textFrame.origin.y = CGRectGetMaxY(self.iconF) + padding;
    self.textF = textFrame;
    
    if (self.status.picture.length > 0) {
        // 配图
        CGFloat pictureX = padding;
        CGFloat pictureY = CGRectGetMaxY(textFrame) + padding;
        CGFloat pictureW = 100;
        CGFloat pictureH = 100;
        self.pictureF = CGRectMake(pictureX, pictureY, pictureW, pictureH);
        
        self.cellHeight = CGRectGetMaxY(self.pictureF) + padding;
    } else {
        self.cellHeight = CGRectGetMaxY(self.textF) + padding;
    }
}


+ (NSArray *)statusFrames
{
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil]];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSDictionary *dict in array) {
        // 要添加statusFrame对象
        HMStatusFrame *statusFrame = [[HMStatusFrame alloc] init];
        
        // 实例化一个新的Status模型
        HMStatus *status = [HMStatus statusWithDict:dict];
        
        // 调用自己的setter方法,保存status数据模型,同时计算出所有控件的位置
        statusFrame.status = status;
        
        // 将statusFrame添加到数组
        [arrayM addObject:statusFrame];
    }
    
    return arrayM;
}














- (UIImageView *)iconView
{
    if (_iconView == nil) {
        _iconView = [[UIImageView alloc] init];
        [self.contentView addSubview:_iconView];
    }
    return _iconView;
}


- (UILabel *)nameView
{
    if (_nameView == nil) {
        _nameView = [[UILabel alloc] init];
        // 默认字体是17号
        _nameView.font = kNameFont;
        [self.contentView addSubview:_nameView];
    }
    return _nameView;
}


- (UIImageView *)vipView
{
    if (_vipView == nil) {
        _vipView = [[UIImageView alloc] init];
        _vipView.image = [UIImage imageNamed:@"vip"];
        _vipView.hidden = YES;
        
        [self.contentView addSubview:_vipView];
    }
    return _vipView;
}


- (UILabel *)textView
{
    if (_textView == nil) {
        _textView = [[UILabel alloc] init];
        _textView.font = kTextFont;
        _textView.numberOfLines = 0;
        
        [self.contentView addSubview:_textView];
    }
    return _textView;
}


- (UIImageView *)pictureView
{
    if (_pictureView == nil) {
        _pictureView = [[UIImageView alloc] init];
        [self.contentView addSubview:_pictureView];
    }
    return _pictureView;
}


- (void)setStatus:(HMStatus *)status
{
    _status = status;
    
    // 1> 设置数据
    [self settingData];
    
    // 2> 设置位置
    [self settingFrame];
}


/** 设置数据 */
- (void)settingData
{
    // 头像
    self.iconView.image = [UIImage imageNamed:self.status.icon];
    // 姓名
    self.nameView.text = self.status.name;
    // vip(可选的)
    if (self.status.vip) {
        self.vipView.hidden = NO;
        self.nameView.textColor = [UIColor redColor];
    } else {
        self.vipView.hidden = YES;
        self.nameView.textColor = [UIColor blackColor];
    }
    
    // 正文
    self.textView.text = self.status.text;
    
    // 配图(可选参数)
    // imageNamed:nil CUICatalog: Invalid asset name supplied: (null), or invalid scale factor: 2.000000
    if (self.status.picture.length > 0) {
        self.pictureView.hidden = NO;
        self.pictureView.image = [UIImage imageNamed:self.status.picture];
    } else {
        self.pictureView.hidden = YES;
    }
}


/** 设置位置 */
- (void)settingFrame
{
    // 0. 定义间距
    CGFloat padding = 10;
    
    // 1. 头像
    CGFloat iconX = padding;
    CGFloat iconY = padding;
    CGFloat iconW = 30;
    CGFloat iconH = 30;
    self.iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);
    
    // 2. 姓名大小由文字的长度来决定
    // boundingRectWithSize计算给定文本字符串所占的区域
    // 返回值是一个x,y = 0的CGRect,w,h是计算好的宽高
    //
    // 如果要计算多行的准确高度,需要传入NSStringDrawingUsesLineFragmentOrigin选项
    // dict用于指定字体的相关属性的字典,UIKit框架中的第一个头文件
    // context: nil
    NSDictionary *nameDict = @{NSFontAttributeName: kNameFont};
    CGRect nameFrame = [self.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nameDict context:nil];
    nameFrame.origin.x = CGRectGetMaxX(self.iconView.frame) + padding;
    nameFrame.origin.y = padding + (self.iconView.bounds.size.height - nameFrame.size.height) * 0.5;
    self.nameView.frame = nameFrame;
    
    // vip图标
    CGFloat vipX = CGRectGetMaxX(self.nameView.frame) + padding;
    CGFloat vipY = self.nameView.frame.origin.y;
    CGFloat vipW = 14;
    CGFloat vipH = 14;
    self.vipView.frame = CGRectMake(vipX, vipY, vipW, vipH);
    
    // 正文
    NSDictionary *textDict = @{NSFontAttributeName: kTextFont};
    CGRect textFrame = [self.status.text boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:textDict context:nil];
    textFrame.origin.x = padding;
    textFrame.origin.y = CGRectGetMaxY(self.iconView.frame) + padding;
    self.textView.frame = textFrame;
    
    CGFloat cellHeight;
    
    if (self.status.picture.length > 0) {
        // 配图
        CGFloat pictureX = padding;
        CGFloat pictureY = CGRectGetMaxY(textFrame) + padding;
        CGFloat pictureW = 100;
        CGFloat pictureH = 100;
        self.pictureView.frame = CGRectMake(pictureX, pictureY, pictureW, pictureH);
        
        cellHeight = CGRectGetMaxY(self.pictureView.frame) + padding;
    } else {
        cellHeight = CGRectGetMaxY(self.textView.frame) + padding;
    }
    




#pragma mark - 代理方法
/** 计算单元格行高 */
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /**
     计算行高的方法,会在加载表格数据时,有多少行计算多少次 contentSize
     
     问题:此方法执行的时候,cell还没有被实例化!
     但是:行高计算是在实例化cell时,通过设置status属性,计算的=>有了status模型,就可以知道行高!
     
     问题:如何在cell实例化之前,获得行高?
     解决方法:通过status可以计算得到行高!=》再建立一个模型,专门计算所有控件的位置
     */
    HMStatusFrame *statusFrame = self.statusFrames[indexPath.row];
    
    return statusFrame.cellHeight;
}





























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值