为什么drawRect留下部分图像?

这是我的情况:

我有一个包含餐馆列表的表格,每个条目显示使用drawRect绘制的记分栏上随着时间的检查结果。

当用户向下滚动表格然后向上滚动时,就会显示带有黄色和红色方块的记分栏,以前的记分栏会显示这些方块。 date也被引入到之前的记分栏中。

我的问题在于摆脱旧的方块。 每次drawRect被调用时都不应该被擦除吗?

我已经放置了三张图片,希望能够解释我的意思。

我不认为这是表格行caching自定义单元格的问题? 这里,一旦UITableCellbuild立单元出队,绘制得分条; 单元格中的所有其他视图都是正确的,这让我觉得问题在于drawRect无法清除graphics上下文。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row < self.establishments.count) { return [self establishmentCellForIndexPath:indexPath]; } else if (self._noResultsFound) { return [self noResultsCell]; } else { return [self loadingCell]; } } - (UITableViewCell *)establishmentCellForIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"EstablishmentCell"; DSFEstablishment *establishment = [self.establishments objectAtIndex:[indexPath row]]; DSFEstablishmentCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; [cell setEstablishment:establishment]; [cell updateCellContent]; return cell; } 

在updateCellContent期间,我们尝试清除旧的scorebarviews,如果它们存在,但代码永远不会findDSFScorebarView类的其他子视图。 最后,创buildscorebarView并将其添加到视图的子视图中。

 - (void)updateCellContent { NSLog(@"updateCellContent: %@", self.establishment.latestName); self.name.text = self.establishment.latestName; self.address.text = self.establishment.address; self.type.text = self.establishment.latestType; if (self.establishment.distance) { self.distance.text = [NSString stringWithFormat:@"%.2f km", self.establishment.distance]; } else { self.distance.text = @""; } // Clear out old scorebarView if exists for (UIView *view in self.subviews) { if ([view isKindOfClass:[DSFScorebarView class]]) { NSLog(@">>>removeFromSuperview"); [view removeFromSuperview]; } } DSFScorebarView *scorebarView = [[DSFScorebarView alloc] initWithInspections:self.establishment.inspections]; [self addSubview:scorebarView]; 

}

scorebarview是使用initWithInspections中的drawRect绘制的,并确保记分栏不超过17个方块(最近的检查)。 每次检查都会给出一个绿色的平方,低于黄色=中等红色=高,并且年份被画在平方下方。

我已经设置self.clearsContextBeforeDrawing = YES,但它不能解决问题。

 // Custom init method - (id)initWithInspections:(NSArray *)inspections { CGRect scorebarFrame = CGRectMake(20, 38, 273, 22); if ((self = [super initWithFrame:scorebarFrame])) { self.inspections = inspections; self.clearsContextBeforeDrawing = YES; [self setBackgroundColor:[UIColor clearColor]]; } return self; } - (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); float xOffset = 0; // Keep track of position of next box -- start at 1 float yOffset = 0; // Fixed Y offset. Adjust to match shadows NSString *previousYear = nil; UIFont *yearFont = [UIFont fontWithName:@"PFTempestaFiveCompressed" size:8.0]; // take subset/slice of inspections. only the last 17, so it will fit on screen. int inspections_count = (int)[self.inspections count]; int startIndex = inspections_count > 17 ? inspections_count - 17 - 1 : 0; int subarrayLength = inspections_count > 17 ? 17 : inspections_count; NSArray *inspectionsSlice = [self.inspections subarrayWithRange:NSMakeRange(startIndex, subarrayLength)]; for (id inspection in inspectionsSlice) { // Top of box NSMutableArray *pos0RGBA = [inspection colorForStatusAtPositionRGBA:0]; CGFloat topColor[] = ... CGContextSetFillColor(ctx, topColor); CGRect box_top = CGRectMake(xOffset, yOffset, kScoreBoxWidth, kScoreBoxHeight / 2); CGContextAddRect(ctx, box_top); CGContextFillPath(ctx); // Bottom of box NSMutableArray *pos1RGBA = [inspection colorForStatusAtPositionRGBA:1]; CGFloat bottomColor[] = ... CGContextSetFillColor(ctx, bottomColor); CGRect box_bottom = CGRectMake(xOffset, kScoreBoxHeight / 2 + yOffset, kScoreBoxWidth, kScoreBoxHeight / 2); CGContextAddRect(ctx, box_bottom); CGContextFillPath(ctx); // Year Text NSString *theYear = [inspection dateYear]; if (![theYear isEqualToString:previousYear]) { CGFloat *yearColor = ... CGContextSetFillColor(ctx, yearColor); // +/- 1/2 adjustments are positioning tweaks CGRect yearRect = CGRectMake(xOffset+1, yOffset+kScoreBoxHeight-2, kScoreBoxWidth+50, kScoreBoxHeight); [theYear drawInRect:yearRect withFont:yearFont]; previousYear = theYear; } xOffset += kScoreBoxWidth + kScoreBoxGap; } 
  • 表格加载,绘制4行

起始位置

  • 用户向下滚动; 再绘制8行

在这里输入图像说明

  • 用户滚动回到顶部; Grace Market / Maple Pizza(第二排)的比分已经改变。

在这里输入图像说明

在执行下面的@ HaIR的解决scheme之后,在点击一个表格行之后,我得到一个灰色背景的白色条纹。 这是非常丑陋的,增加了额外的宽度,“年”线“白”。

 - (void)drawRect:(CGRect)rect { ... CGFloat backgroundColour[] = {1.0, 1.0, 1.0, 1.0}; CGContextSetFillColor(ctx, backgroundColour); CGRect fullBox = CGRectMake(xOffset, yOffset, kScoreBoxWidth * 17, 2 * (kScoreBoxHeight-2)); CGContextAddRect(ctx, fullBox); CGContextFillPath(ctx); for (id inspection in inspectionsSlice) { ... 

与记分牌图表和白色小条的灰色表盘

你已经接pipe了DrawRect,所以它只能做你在dra中手动做的事情

在绘制任何东西之前,先用背景色填充整个酒吧区域。

您正在重新使用单元格,例如,您可以在格雷斯市场/枫树广场的第二个版本下面显示草坪酒店餐厅图表。

 CGContextSetFillColor(ctx, yourBackgroundColor); CGRect fullBox = CGRectMake(xOffset, yOffset, kScoreBoxWidth * 17, kScoreBoxHeight); CGContextAddRect(ctx, fullBox); CGContextFillPath(ctx); 

如果您只是清除单元格中的背景,而不是具有背景色。 然后:

 CGContextClearRect(context, rect); 

在DrawRect的开始可能会更合适。

修订:

更仔细地看待你的问题,根本问题是你没有find并删除旧的DSFScoreboardView的。 也许你应该尝试通过子视图的recursionsearch。 喜欢:

 - (void)logViewHierarchy { NSLog(@"%@", self); for (UIView *subview in self.subviews) { //look right here for your DSFScorebarView's [subview logViewHierarchy]; } } @end // In your implementation [myView logViewHierarchy]; 

(取自https://stackoverflow.com/a/2746508/793607