0

我已经对 UITableView 进行了分组。

这是我的标题视图方法 - 注意我做了它,所以它只加载一次和下一次而不是重新加载元素,如果它已经有子视图,它只会返回 headerView(我需要这个,因为我在 headerView 中有改变状态的元素,我这样做了不希望他们重新加载):

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
static NSString *headerReuseIdentifier = @"myHeader";

UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
if (headerView == nil) {
    headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:headerReuseIdentifier];//[tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
    CGRect frame=CGRectMake(0, 0, tableView.bounds.size.width, 44);
    headerView.frame=frame;
}

if (headerView.contentView.subviews.count!=0){
    return headerView;//do not reload 
}
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, tableView.frame.size.width-85, 44)];
    [label setFont:[UIFont boldSystemFontOfSize:16]];
    NSString *name=@"not found";
    [label setText:name];

    headerView.backgroundColor=[UIColor clearColor];
    [headerView.contentView addSubview:label];
    //... etc elements

return headerView;
}

我也为单元格实现了类似的逻辑,即如果子视图已经添加到单元格中,它们不会重新加载元素,只是为了看看它在那里是如何工作的:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

if (cell.contentView.subviews.count!=0) {
    return cell;//do not reload 
}

//adding elements here...
return cell;
}

==================================================== ====================

这是第一次的样子,注意步骤:1 和步骤:2 以正确的升序排列在此处输入图像描述

现在,问题是,当调用 [myTableView reloadData] 时,表如下所示:在此处输入图像描述

注意:headerView 视图是向后的!但是,单元格总是以正确的顺序显示。

如果再次调用 [myTableView reloadData] - headerViews 将以正确的顺序显示。

我可以通过避免调用 reloadData 来阻止这种情况的发生,但是我需要在单元格中而不是在 headerViews 中重新加载数据。

有没有人经历过这个 headerViews 翻转 - 你是如何解决的?

Xcode 8.3.2,运行于iPad iOS9.0模拟器

完整代码,可让您测试此错误的头部视图重新排序:

.h 文件

@interface TableTestViewController : UIViewController
@property(strong,nonatomic)IBOutlet UITableView *myTable;
@property(strong,nonatomic)NSMutableArray *steps;
@end

.m 文件

#import "TableTestViewController.h"

@interface TableTestViewController ()

@end

@implementation TableTestViewController
@synthesize steps,myTable;

- (void)viewDidLoad {
[super viewDidLoad];
steps=[[NSMutableArray alloc]initWithObjects:@"Step 1",@"Step 2", nil];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return steps.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 44.0;
}

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
static NSString *headerReuseIdentifier = @"myHeader";

UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
if (headerView == nil) {
    headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:headerReuseIdentifier];//[tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
    CGRect frame=CGRectMake(0, 0, tableView.bounds.size.width, 44);
    headerView.frame=frame;
}

if (headerView.contentView.subviews.count!=0) {
    return headerView;//do not reload when running
}

while (headerView.contentView.subviews.count) {
    id subview=[headerView.contentView.subviews objectAtIndex:0];
    [subview removeFromSuperview];
}

headerView.backgroundColor=[UIColor clearColor];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, tableView.frame.size.width-85, 44)];
[label setFont:[UIFont boldSystemFontOfSize:16]];
[label setText:[steps objectAtIndex:section]];


[headerView.contentView addSubview:label];

    int btnSz=tableView.bounds.size.width/6;
    UIButton *startStepBtn = [[UIButton alloc]initWithFrame:CGRectMake(btnSz*5+5 ,5, 30, 30)];
    [startStepBtn setTitle:@"" forState:UIControlStateNormal];
    startStepBtn.tag=section+1000;
    startStepBtn.enabled=NO;
    [startStepBtn addTarget:self action:@selector(startStep:) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside];

    [headerView.contentView addSubview:startStepBtn];


return headerView;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
int i=1;
return 60*ceil((double)i/5)+10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

if ([cell.contentView.subviews count]!=0) {
    return cell;//do not reload when running
}

//clear 1st
while( [cell.contentView.subviews count] ){
    id subview = [cell.contentView.subviews objectAtIndex:0];
    [subview removeFromSuperview];
}

int btnSz=tableView.bounds.size.width/6;

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, tableView.frame.size.width-85, 44)];
[label setFont:[UIFont boldSystemFontOfSize:16]];
[label setText:[steps objectAtIndex:indexPath.section]];
[cell.contentView addSubview:label];

CGRect frame;

frame = CGRectMake(btnSz*5+5 ,5, 30, 30);
    UIButton *delStepBtn = [[UIButton alloc]initWithFrame:frame];
    [delStepBtn setTitle:@"❌" forState:UIControlStateNormal];
    [delStepBtn addTarget:self action:@selector(deleteStep:) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside];
    [cell.contentView addSubview:delStepBtn];

    frame = CGRectMake(btnSz*5+5 ,5+30, 30, 30);
    UIButton *editStepBtn = [[UIButton alloc]initWithFrame:frame];
    [editStepBtn setTitle:@"" forState:UIControlStateNormal];
    [editStepBtn addTarget:self action:@selector(editStep:) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside];
    [cell.contentView addSubview:editStepBtn];

return cell;
}

-(void)editStep:(id)sender{
[myTable reloadData];
}

@end

实施,您将看到按升序排列的标题,触摸锤子按钮会使表格重新加载,并且标题现在将按降序排列,再次触摸它们将返回升序。

但是,单元格内容始终保持应按升序排列。

4

2 回答 2

1

UITableViewHeaderFooterView是可重复使用的视图,因此您不能确定UITableView每次都会返回完全相同的视图。

UITableViewHeaderFooterView我建议在某些数据源中创建一个子类并将状态保存在外部。

如果您不想这样做,作为一种解决方法,您可以为每个部分使用唯一的重用标识符。在这种情况下,您应该更换

static NSString *headerReuseIdentifier = @"myHeader";

NSString *headerReuseIdentifier = [NSString stringWithFormat: @"myHeader%ld", (long)section];

于 2017-06-13T20:08:28.190 回答
0

您正在进行的检查不是必需的:

if (headerView.contentView.subviews.count!=0){
    return headerView;//do not reload 
}

UILabel但是,每次都实例化 a 并不是一个好习惯。每个实例化都应该在if (headerView == nil)if-case 内完成,这UILabel应该是这个标题或单元格的一个属性。

除此之外,您可以在将text标题/单元格出列时更改属性。

于 2017-06-13T16:41:12.710 回答