一、案例描述:案例类似于QQ好友列表的展开和关闭,每次点击组标题后,展开列表并刷新被点击的一组
二、BUG描述:点击某组标题后,列表无法展开且列表上控件不显示,但该组数据已刷新,断点调试数据已传入,按钮点击事件已执行。
三、代码如下:
1、控制器代码:
//
// ViewController.m
//
// Created by craneteng on 16/1/3.
// Copyright © 2016年 craneteng. All rights reserved.
//
#import "ViewController.h"
#import "HMdata.h"
#import "HMGroupHeaderView.h"
@interface ViewController ()<HMGroupHeaderViewDelegate>
@property(nonatomic,strong)NSArray *data;
@end
@implementation ViewController
#pragma mark - 实现数据源方法
-(NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{
return self.data.count;
}
-(NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
// 1. 获取组模型
HMdata *modle = self.data[section];
if (modle.isVisible) {
//点击后打开图片
return 1;
} else {
return 0;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *ID = @"cell_id";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
//创建cell
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
//赋值
cell.imageView.image = [UIImage imageNamed:@"泡妞宝典"];
cell.textLabel.text = @"程序名媛";
//返回cell
return cell;
}
#pragma mark - 实现组标题的代理方法,自定义每组的header
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
//获取模型数据
HMdata *modle = self.data[section];
//创建一个自定义headerView,并传入模型数据
HMGroupHeaderView *headerView = [[HMGroupHeaderView alloc]groupHeaderViewWithTableView:tableView andModle:modle];
//设置代理用于刷新对应组数据
headerView.delegate = self;
// 把当前是第几组, 记录到header view中
headerView.tag = section;
// 4. 返回header view
return headerView;
}
#pragma mark - 实现代理方法刷新数据
-(void)didClickHeaderViewButton:(HMGroupHeaderView *)headerView{
// 局部刷新 (只刷新某组)
NSIndexSet *idx_set = [NSIndexSet indexSetWithIndex:headerView.tag];
[self.tableView reloadSections:idx_set withRowAnimation:UITableViewRowAnimationRight];
}
#pragma mark - 隐藏状态栏
- (BOOL)prefersStatusBarHidden {
return YES;
}
#pragma mark - 加载数据
-(NSArray *)data{
if (_data == nil) {
NSString *path = [[NSBundle mainBundle]pathForResource:@"Data.plist" ofType:nil];
NSArray *dicM = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *arrayM = [NSMutableArray array];
for (NSDictionary *dict in dicM) {
HMdata *modle = [HMdata dataWithdict:dict];
[arrayM addObject:modle];
}
_data = arrayM;
}
return _data;
}
- (void)viewDidLoad {
self.tableView.rowHeight = 90;
self.tableView.sectionHeaderHeight = 44;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
2、自定义headerView代码:
#import <UIKit/UIKit.h>
@class HMdata,HMGroupHeaderView;
//创建一个代理
@protocol HMGroupHeaderViewDelegate <NSObject>
-(void)didClickHeaderViewButton:(HMGroupHeaderView *)headerView ;
@end
@interface HMGroupHeaderView : UITableViewHeaderFooterView
@property (weak,nonatomic)id<HMGroupHeaderViewDelegate> delegate;
-(instancetype )groupHeaderViewWithTableView:(UITableView *)tableView andModle:(HMdata *)modle;
@end
#import "HMGroupHeaderView.h"
#import "HMdata.h"
@interface HMGroupHeaderView ()
@property (nonatomic, weak) UIButton *button;
@property (nonatomic, weak) UILabel *label;
@property(nonatomic,copy) HMdata *data;
@end
@implementation HMGroupHeaderView
-(instancetype )groupHeaderViewWithTableView:(UITableView *)tableView andModle:(HMdata *)modle{
_data = modle;
//创建组标题
static NSString *ID = @"group_id";
HMGroupHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
if (headerView == nil) {
headerView = [[HMGroupHeaderView alloc] initWithReuseIdentifier:ID];
}
// 把数据设置给子控件
// 设置按钮上显示的文字
[self.button setImage:[UIImage imageNamed:modle.imageName] forState:UIControlStateNormal];
// 设置label上显示的文字
self.label.text = modle.titileName;
return headerView;
}
//重写自定义组标题
-(instancetype )initWithReuseIdentifier:reuseIdentifier{
if (self = [super initWithReuseIdentifier:reuseIdentifier]){
UIButton *button = [[UIButton alloc]init];
//设置按钮图片
// 设置按钮中整个内容左对齐
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
// 设置按钮的文字是黑色
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
// 为按钮注册一个单击事件
[button addTarget:self action:@selector(didClickHeaderButton:) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:button];
self.button = button;
// label
UILabel *label = [[UILabel alloc] init];
// 设置文字右对齐
label.textAlignment = NSTextAlignmentRight;
// label.text = self.data.titileName;
// NSLog(@"%@",self.modle.titileName);
[self.contentView addSubview:label];
self.label = label;
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
// 设置按钮和label的frame值
// 1. button
self.button.frame = self.bounds;
// 2. label
CGFloat margin = 20;
CGFloat labelH = self.bounds.size.height;
CGFloat labelW = 120;
CGFloat labelY = 0;
CGFloat labelX = self.bounds.size.width - labelW - margin;
self.label.frame = CGRectMake(labelX, labelY, labelW, labelH);
}
// 点击了"标题按钮"
- (void)didClickHeaderButton:(UIButton *)sender {
// 设置当前组的"显示状态"
_data.visible = !_data.visible;
// 调用代理对象的方法
if ([self.delegate respondsToSelector:@selector(didClickHeaderViewButton:)]) {
[self.delegate didClickHeaderViewButton:self];
}
}
@end
四、BUG解决:
1、常见思路是在控制器当中用类方法让自定义headerView创建组标题,各种数据通过重写模型的set方法来传入,代码如下:
控制器代码:
//创建一个自定义headerView,并传入模型数据
HMGroupHeaderView *headerView1 = [HMGroupHeaderView groupHeaderViewWithTableView:tableView];
// 传入模型数据
headerView1.data = modle;
自定义headerView代码:
创建:
+(instancetype )groupHeaderViewWithTableView:(UITableView *)tableView{
// NSLog(@"%@",modle.titileName);
// NSLog(@"%@",_modle.titileName);
//创建组标题
static NSString *ID = @"group_id";
HMGroupHeaderView *headerView2 = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
if (headerView2 == nil) {
headerView2 = [[HMGroupHeaderView alloc]initWithReuseIdentifier:ID];
}
return headerView2;
}
设置数据:
- (void)setData:(HMdata *)data{
_data = data;
// 把数据设置给子控件
// 设置按钮上显示的文字
[self.button setImage:[UIImage imageNamed:data.imageName] forState:UIControlStateNormal];
// 设置label上显示的文字
self.label.text = data.titileName;
}
2、如果不通过set方法给自定义headerView传入数据,依然想通过对象方法带模型参数直接赋值,修改y以下代码:
if (headerView == nil) {
headerView = [[HMGroupHeaderView alloc] initWithReuseIdentifier:ID];
}
这句中,通过 [HMGroupHeaderView alloc] 又重新创建了一个自定义headerView,与控制器中这句
HMGroupHeaderView *headerView = [[HMGroupHeaderView alloc]groupHeaderViewWithTableView:tableView andModle:modle];
重复创建了两个对象,导致数据赋值后没有返回到控制器,要保持自定义headerView类和控制器中创建的是一个对象,
自定义headerView类中修改代码如下:
if (headerView == nil) {
headerView = [self initWithReuseIdentifier:ID];
}