2011-02-18 90 views
9

我有一个自定义的UITableView单元格,我添加了一个文本框进行编辑,显示和隐藏基于编辑模式。我也尝试添加一条垂直线条,用于显示编辑时的情况,而且这样做,但我遇到了一些绘图问题。我刚刚添加了一个绿色复选标记rightView,开始处理输入验证反馈,并且我看到类似的问题。自定义UITableViewCell重绘问题

这是单元格的代码,也是我的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相关,但我找不到确切的内容。

任何意见或推动正确的方向将不胜感激。

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

+0

Yup听起来像可重复使用的单元格的问题。你的tableview有多大?大到足以证明重用细胞?如果不抛弃它们并让tableview创建其单元格的单个实例呢? – Rog 2011-02-18 09:48:32

+0

表格视图非常小,它是核心数据条目的详细视图。也许7个细胞,上衣。我有这种奇怪的感觉,我把我的单元格中的layoutsubviews搞乱了。 – Chuck 2011-02-18 10:04:02

回答

8

您需要准备单元以供重用。尝试添加该到EditableCellStyle2实现:

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

也许你修剪过多为您的文章,但在发布代码的可重用的处理单元是完全错误的。

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

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

第三个问题,这几乎肯定是由于过度修剪造成的,因为您从不为第3节创建此“多行地址”单元。您最终可能会重用随机EditableTableCell2,或者可能会崩溃当你从tableView:cellForRowAtIndexPath:返回零时从框架。