UITableViewCell重用自定义UIView作为导致"缓存的组件"问题

时间:2016-09-07 09:50:42

标签: ios objective-c uitableview

我正在创建一个包含带有自定义单元格的UITableView的视图 - 我在自定义视图中覆盖drawRect。我已经尝试重写UITableViewCell并将我的自定义视图添加为IBOutlet,我试图不覆盖它,只是[[cell subviews] objectAtIndex:0];引用它会产生相同的结果。

当我第一次看到这个视图时,一切都很好。如果我慢慢滚动,一切都很好。一旦我快速滚动,重复使用的单元格显然不会重新绘制,因为我最终得到了自定义绘图,对于特定单元格来说是错误的。

单元格配置方法......

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"DialogCell"];
MaskedRoundedCornerDIalogCell* dialogCell = (MaskedRoundedCornerDIalogCell*)[[[cell contentView] subviews] objectAtIndex:0];
[dialogCell setPadding:10];
if (indexPath.row % 2 == 0) {
    [dialogCell setAlignLeft:YES];
    [dialogCell setMaskTopLeftOnly];
    [[dialogCell textContent] setText:@"LEFT ALIGNED TEXT"];
    [[dialogCell textContent] setTextAlignment:NSTextAlignmentLeft];
} else {
    [dialogCell setAlignLeft:NO];
    [dialogCell setMaskBottomRightOnly];
    [[dialogCell textContent] setText:@"RIGHT ALIGNED TEXT"];
    [[dialogCell textContent] setTextAlignment:NSTextAlignmentRight];
}
return cell;
}

我的MaskedRoundedCornerDalogCell实现中的自定义绘图代码(扩展UIView并添加到UITableViewCell的类):

- (void) drawRect:(CGRect)rect {

int maxWidth = rect.size.width - 50;
CGRect container;
if (_alignLeft) {
    container = CGRectMake(rect.origin.x + _padding, rect.origin.y + _padding, maxWidth - (2* _padding), rect.size.height - (2*_padding));
} else {
    container = CGRectMake((rect.size.width - _padding) - (maxWidth - (2* _padding)), rect.origin.y + _padding, maxWidth - (2* _padding), rect.size.height - (2*_padding));
}

UIRectCorner roundedCorners;
if (!_maskTopLeft) {
    roundedCorners = roundedCorners | UIRectCornerTopLeft;
}
if (!_maskTopRight) {
    roundedCorners = roundedCorners | UIRectCornerTopRight;
}
if (!_maskBottomLeft) {
    roundedCorners = roundedCorners | UIRectCornerBottomLeft;
}
if (!_maskBottomRight) {
    roundedCorners = roundedCorners | UIRectCornerBottomRight;
}
UIBezierPath* containerBezierPath = [UIBezierPath bezierPathWithRoundedRect:container byRoundingCorners: roundedCorners cornerRadii:CGSizeMake(25.0F, 25.0F)];

[[UIColor lightGrayColor] setFill];
[containerBezierPath fillWithBlendMode: kCGBlendModeNormal alpha:1.0f];
}

我第一次启动时的样子: Correct Layout

滚动几次后的样子: enter image description here

任何建议,感激地收到......

2 个答案:

答案 0 :(得分:3)

我不确定您是否在drawRect子类中覆盖UITableViewCell,或者它是否在自定义UIView类中。我的建议是在自定义的UIView课程中进行绘制,然后将该视图添加为您的单元格的子视图 - 以防UITableViewCell正在drawRect中执行您的操作意外地压倒一切。

在任何情况下,您看到此行为的原因是因为drawRect仅在视图首次出现在屏幕上或者无效时才会被调用。来自docs

  

首次显示视图或发生使视图的可见部分无效的事件时,将调用此方法。你永远不应该直接调用这个方法。要使视图的一部分无效,从而导致重绘该部分,请调用setNeedsDisplay或setNeedsDisplayInRect:方法。

在单元格的setMask..方法中,尝试调用[self.customDrawingView setNeedsDisplay]使图形无效并强制更新。

  

您可以使用此方法或setNeedsDisplayInRect:来通知系统您的视图内容需要重绘。此方法记录请求并立即返回。在下一个绘图周期之前,视图实际上不会重绘,此时所有无效的视图都会更新。

     

只有在视图的内容或外观发生变化时,才应使用此方法请求重绘视图。如果只是更改视图的几何图形,则通常不会重绘视图。而是根据视图的contentMode属性中的值调整其现有内容。重新显示现有内容可以避免重绘未更改内容的需要,从而提高性能。

答案 1 :(得分:0)

首先,我不认为,覆盖- (void)drawRect:(CGRect)rect是解决问题的正确方法。如果你完全知道你在做什么以及你想要实现什么,我的建议是覆盖它

根据您提供的图片,您遇到的问题与UITableViewCell重复使用有关,但不与图纸有关。

问题。当表格视图滚动到达UITableView的边界以显示新内容时,UITableView不会创建新的单元格实例。它需要当前不可见的单元格(已滚动出来的单元格在屏幕上显示新单元格)并重新使用它(UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"DialogCell"];)。在您的示例中,在重用单元格之后执行的代码行仅设置单元格内容文本。从我提供的图像,我看到,文本正确地坐了起来。问题在于细胞背景。由于在重用后没有单行代码来设置单元格背景,因此在重用之前会显示背景。

推荐。显然,每次重复使用时都需要覆盖单元格背景。如果我是你,我会创建一个类UITableViewCell的子类,让我们说MyTableViewCell。该单元格的方法如下:

- (void)setupWithSide:(Side)side {
    if (side == SideRight) {
        [self setupRightAlignedCintent];
        [self setupLeftBackground];
    }
}

同时,在UITableViewController你必须

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"DialogCell"];

    Side side;

    if (indexPath.row % 2 == 0) {
        side = SideRight;
    } else {
        side = SideLeft;
    }

    [cell setupWithSide:side];

    return cell;
}