向下滚动时,无法再通过[cell.contentView viewWithTag]访问UITableViewCell元素

时间:2015-06-02 08:52:21

标签: ios objective-c uitableview

我正在尝试创建展开/折叠单元格。在每个单元格上,它具有边界底部的UIView子视图。如果展开,边框也应该到达单元格的底部。它在单元的初始加载时工作正常,但是,当我向下滚动时,边框不再向下移动。

我正在通过taskOptionsExpand方法调整边框originY。该方法是通过[cell.contentView viewWithTag:2]获取边框视图。

以下代码:

#import "HomeViewController.h"

@interface HomeViewController ()<UITableViewDelegate, UITableViewDataSource>
@property (strong, nonatomic) UITableView *tableView;
@property (strong, nonatomic) NSIndexPath *selectedIndexPath;
@end

@implementation HomeViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.selectedIndexPath = nil;
    [self.view addSubview:self.tableView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (UITableView *)tableView
{

    if (!_tableView) {
        _tableView = [[UITableView alloc] init];

        _tableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
        [_tableView addSubview:self.tableRefreshControl];

    }

    return _tableView;
}


# pragma mark - table view delegates
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

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

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self.selectedIndexPath isEqual:indexPath]) {
        return 80;
    }else{
        return 50;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];

    // text view
    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 0, self.view.frame.size.width-20, 50)];
    view1.backgroundColor = [UIColor clearColor];
    view1.tag = 0;
    UILabel *title = [[UILabel alloc] initWithFrame:view1.frame];
    title.text = @"Lorem ipsum";
    title.textColor = [UIColor grayColor];
    [view1 addSubview:title];

    // options view
    UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
    view2.backgroundColor = [UIColor orangeColor];
    view2.tag = 1;

    // border bottom
    CGRect frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
    if ([self.selectedIndexPath isEqual:indexPath]) {
        frame.origin.y = 79; //expand
    } else {
    }
    UIView *border = [[UIView alloc] initWithFrame:frame];
    border.backgroundColor = [UIColor blueColor];
    border.tag = 2;

    cell.clipsToBounds = YES;
    [cell.contentView addSubview:view1];
    [cell.contentView addSubview:view2];
    [cell.contentView addSubview:border];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self.selectedIndexPath isEqual:indexPath]) {
        [self taskOptionsExpand:NO indexPath:indexPath];
        self.selectedIndexPath = nil;
    } else {
        [self taskOptionsExpand:YES indexPath:indexPath];
        [self taskOptionsExpand:NO indexPath:self.selectedIndexPath];
        self.selectedIndexPath = indexPath;
    }

    [tableView beginUpdates];
    [tableView endUpdates];
}

- (void) taskOptionsExpand:(BOOL) expand indexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
    UIView *border = [cell.contentView viewWithTag:2];
    NSLog(@"border: %@", border);
    if (expand) {
        border.frame = CGRectMake(20,  79, self.view.frame.size.width-40, 1);
    }else{
        border.frame = CGRectMake(20,  49, self.view.frame.size.width-40, 1);
    }

}
@end

2 个答案:

答案 0 :(得分:1)

滚动table view时,单元格为dequeued以获取reusable cell,而reusable cell已有viewWithTag 2 (因为已添加)当创建重用的单元格时,因此添加another view with tag 2将产生上述问题。要解决上述问题,您应删除之前添加的viewWithTag 2,然后重新添加具有相同标记的视图,例如 -

    // remove (previously added) border if it exists
    UIView *border = nil;
    border = [cell.contentView viewWithTag:2];
    if(border)
          [border removeFromSuperview];

    // again create border view

将您的cellForRowAtIndexPath:方法更新为

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

        [cell setSelectionStyle:UITableViewCellSelectionStyleNone];

        // text view
        UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 0, self.view.frame.size.width-20, 50)];
        view1.backgroundColor = [UIColor clearColor];
        view1.tag = 0;
        UILabel *title = [[UILabel alloc] initWithFrame:view1.frame];
        title.text = @"Lorem ipsum";
        title.textColor = [UIColor grayColor];
        [view1 addSubview:title];

        // options view
        UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 30)];
        view2.backgroundColor = [UIColor orangeColor];
        view2.tag = 1;

        // border bottom
        CGRect frame = CGRectMake(20, 49, self.view.frame.size.width-40, 1);
        if ([self.selectedIndexPath isEqual:indexPath]) {
            frame.origin.y = 79; //expand
        } else {
        }

        UIView *border = nil;
        border = [cell.contentView viewWithTag:2];
        if(border)
              [border removeFromSuperview];

        border = [[UIView alloc] initWithFrame:frame];
        border.backgroundColor = [UIColor blueColor];
        border.tag = 2;

        cell.clipsToBounds = YES;
        [cell.contentView addSubview:view1];
        [cell.contentView addSubview:view2];
        [cell.contentView addSubview:border];

        // release your allocated instances after adding them
        [view1 release];
        [view2 release];
        [border release];

        return cell;
    }

此外,您应该releasesubviews allocated view1, view2, border添加到单元格的内容视图后[view1 release]; [view2 release]; [border release];

~/Products/details.aspx?product=26-Toshiba Qosmio Notebook

这将使得从2到1保留计数,并且当细胞被释放时,它们将从那些细胞中移除。

答案 1 :(得分:0)

表视图重用单元格。当单元格在屏幕外滚动时,它将被添加到队列中,并将重新用于下一个要在屏幕上滚动的单元格。这意味着tableView:cellForRowAtIndexPath:方法中的配置代码将在不同的indexPaths上在同一单元格上多次运行。由于您只是在每次配置代码运行时添加border视图,因此它们将堆叠在另一个之上。当您致电viewWithTag:时,您只会获得您添加的多个观看次数之一。

正确的方法是创建一个自定义单元格(UITableViewCell的子类),其中包含需要配置的每个子视图的属性(如果使用xibs / storyboard,则为IBOutlet),以便它们可以是访问。