【问题标题】:Custom UITableViewCell redraw issues自定义 UITableViewCell 重绘问题
【发布时间】:2011-02-18 09:39:33
【问题描述】:

我有一个自定义 UITableView 单元格,我添加了一个文本框进行编辑,它根据编辑模式显示和隐藏。我还尝试添加一条在编辑时显示的垂直线,它确实做到了,但我遇到了一些绘图问题。我刚刚添加了一个绿色复选标记 rightView 以开始处理输入验证反馈,我看到了类似的问题。

这是单元格的代码,也是我的 cellForRowAtIndexPath 的一部分。

#import <UIKit/UIKit.h>

    @interface EditableCellStyle2 : UITableViewCell {
        CGRect editRect;
        UITextField *editField;
        UIView *lineView;
    }

    @property (nonatomic, readonly, retain) UITextField *editField;
    @property (nonatomic, readonly, retain) UIView *lineView;

    @end

#import "EditableCellStyle2.h"


@implementation EditableCellStyle2

@synthesize editField;
@synthesize lineView;


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code.
        editRect = CGRectMake(83, 12, self.contentView.bounds.size.width-83, 19);

        editField = [[UITextField alloc] initWithFrame:editRect];
        editField.font = [UIFont boldSystemFontOfSize:15];
        editField.textAlignment = UITextAlignmentLeft;
        editField.textColor = [UIColor blackColor];
        editField.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;

        [self.contentView addSubview:editField];

        self.editField.enabled = NO;
        self.editField.hidden = YES;


        lineView = [[UIView alloc] initWithFrame:CGRectMake(80, 0, 1, self.contentView.bounds.size.height)];
        self.lineView.backgroundColor = [UIColor lightGrayColor];
        [self.contentView addSubview:lineView];
        self.lineView.hidden = YES;
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

    [super setSelected:selected animated:animated];

    // Configure the view for the selected state.
}

-(void)layoutSubviews
{
    [super layoutSubviews]; // layouts the cell as UITableViewCellStyleValue2 would normally look like

    editRect = CGRectMake(83, 12, self.contentView.frame.size.width-self.detailTextLabel.frame.origin.x-10, 19);
    editField.frame = editRect;
}


- (void)willTransitionToState:(UITableViewCellStateMask)state {
    [super willTransitionToState:state];

    if (state & UITableViewCellStateEditingMask) {
        self.detailTextLabel.hidden = YES;
        self.editField.enabled = YES;
        self.lineView.hidden = NO;
        self.editField.hidden = NO;
    }
}

- (void)didTransitionToState:(UITableViewCellStateMask)state {
    [super didTransitionToState:state];

    if (!(state & UITableViewCellStateEditingMask)) {
        self.editField.enabled = NO;
        self.editField.hidden = YES;
        self.lineView.hidden = YES;
        self.detailTextLabel.hidden = NO;
        self.editField.text = self.detailTextLabel.text;
    }
}


- (void)dealloc {
    [editField release];
    [lineView release];

    [super dealloc];
}


@end

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

    // handling every section by hand since this view is essentially static. Sections 0, 1, 2, and 4 use a generic editable cell.
    // Section 3 uses the multiline address cell.

    static NSString *CellIdentifier = @"Cell";

    EditableCellStyle2 *cell = (EditableCellStyle2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (indexPath.section == 0 || indexPath.section == 1 || indexPath.section == 2 || indexPath.section == 4) {
        if (cell == nil) {
            cell = [[[EditableCellStyle2 alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease];
        }
    }

    // Configure the Odometer
    if (indexPath.section == 0) {
        NSArray *array = [sectionsArray objectAtIndex:indexPath.section];
        NSDictionary *dictionary = [array objectAtIndex:indexPath.row];

        cell.textLabel.text = @"Odometer";
        cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", [dictionary objectForKey:@"Odometer"]];
        cell.tag = kOdometer;
        cell.editField.text = cell.detailTextLabel.text;
        cell.editField.placeholder = @"Odometer";
        cell.editField.tag = kOdometer;
        cell.editField.keyboardType = UIKeyboardTypeNumberPad;

        // Create a view for the green checkmark for odometer input validation and set it as the right view.
        UIImage *checkImage = [UIImage imageNamed:@"tick.png"];
        UIImageView *checkImageView = [[[UIImageView alloc] initWithImage:checkImage] autorelease];
        cell.editField.rightView = checkImageView;
        cell.editField.rightViewMode = UITextFieldViewModeAlways;
    }

return cell;
}

还有更多内容,但所有单元的构建方式都相同。

问题是,在编辑模式下,垂直线会正确显示。当我离开编辑模式时,当我进入正常模式时,任何不在屏幕上的单元格仍然有垂直线(它不会被隐藏)。此外,现在我已经为复选标记指示器添加了 imageView,任何在切换模式时不在屏幕上的单元格都会获得复选标记。 (只有第 0 节设置)。

我还注意到,如果我执行 cell.setNeedsDisplay,如果数据源已更新,则文本标签和详细信息文本标签将不会更新。我必须做 [self.tableView reloadData] 跳过任何活动动画。

我确定这些问题与我使用自定义单元格 + dequeueReusableCellWithIdentifier 有关,但我找不到确切的原因。

我们将不胜感激任何反馈或推动正确方向的努力。

编辑: 不使用可重复使用的细胞似乎已经解决了上述问题。我仍然愿意接受有关单元格代码的反馈。 我忘记了另一个可能相关或不相关的问题。我的一个单元格有一个“点击查看列表”按钮。如果我在编辑模式下将数据输入到单元格中,然后点击该按钮从列表中选择一些信息(它显示模式表视图),当我关闭模式视图时,所有单元格的编辑数据都已恢复为它们原始状态。当我关闭模态视图控制器时,我没有调用重新加载数据。我认为这可以通过不使用可重复使用的单元格来解决,但事实并非如此。

【问题讨论】:

  • 是的,听起来像是可重用单元格的问题。你的 tableview 有多大?大到足以证明重复使用细胞的合理性?如果不放弃它们,让 tableview 改为创建其单元格的单个实例?
  • 表格视图非常小,它是核心数据条目的详细视图。可能有 7 个细胞,上衣。我有一种奇怪的感觉,我在某个地方弄乱了单元格中的布局子视图。
  • 我有或多或少完全相同的问题,所以添加一个赏金以防人们注意到并帮助你,从而同时帮助我。我很确定这是其中之一!细节,但仍然:-)
  • niklassaers,我最终通过手动编码每个表部分并完全删除重用标识符来解决这个问题。这是一个非常小的表格,具有核心数据值的基本静态布局。如果您愿意,我可以发布没有我的特定值(复选标记位置等)的部分代码。

标签: iphone objective-c uitableview


【解决方案1】:

您需要准备单元格以供重复使用。尝试将其添加到 EditableCellStyle2 实现中:

- (void)prepareForReuse {
    [super prepareForReuse];
    [self didTransitionToState:UITableViewCellStateDefaultMask];
}

【讨论】:

  • 天哪。圣母玛利亚。我在基于 UITableView 的自定义引擎中的所有滚动刷新问题现在都已修复。你不知道你救了我多少悲伤。如果我可以给你发电子邮件,我会的。现在打电话给教皇,让你成为 UITableViewCells 的守护神。
【解决方案2】:

也许你为你的帖子修剪了太多,但在发布的代码中你的可重用单元处理都是错误的。

首先,每种不同类型的单元格都需要自己的CellIdentifier。在您的情况下(从您的代码注释来看),这意味着第 3 节与第 0、1、2 和 4 节至少有一个不同的标识符。您可能还想为第 0 节做一个单独的标识符,所以你不要必须继续删除和阅读该复选标记。对于相应的部分,dequeueReusableCellWithIdentifier: 和 initWithStyle:reuseIdentifier:` 都需要使用不同的标识符。

第二个问题是您没有正确重置单元格。必须对 UITableViewCell 进行两种“类型”的初始化:对其类型的每个单元格都相同的初始化,以及取决于正在显示的特定行的初始化。第一种只能(并且应该)在分配新单元格时执行一次。第二种必须每次通过tableView:cellForRowAtIndexPath: 完成。您似乎在其 init 方法中为您的 EditableTableCell2 类正确执行了第一个操作,但我看不到您在其中进行每行初始化的任何地方:您从未重置selected、单元格状态或编辑内容字段,或删除 checkImageView ,因为您在第 0 部分与其他部分使用相同类型的单元格。如果需要,可以在 EditableTableCell2 类的 prepareForReuse 中完成重置 selected、状态以及清除复选框图像和字段内容。

第三个问题,几乎可以肯定是由于过度修剪,是您永远不会为第 3 部分创建这个“多行地址”单元格。您最终可能会重复使用随机 EditableTableCell2,或者可能会因来自的异常而崩溃从tableView:cellForRowAtIndexPath: 返回 nil 时的框架。

【讨论】:

    猜你喜欢
    • 2013-02-26
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多