为什么drawRect留下图像的一部分? [英] Why is drawRect leaving parts of image?

查看:64
本文介绍了为什么drawRect留下图像的一部分?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的情况:

我有一个包含餐厅列表的表,每个条目在使用drawRect绘制的记分栏中显示一段时间内的检查结果。

I have a table which contains a list of restaurants, each entry shows the results of inspections over time on a scorebar that is drawn using drawRect.

当用户向下滚动表格然后向上滚动,以便显示带有黄色和红色正方形的记分栏时,以前的记分栏将显示这些正方形。日期也会绘制到以前的记分栏中。

When the user scrolls the table down and then up, so that scorebars with yellow and red squares are shown, previous scorebars pick up those squares. Dates are also drawn into previous scorebars.

我的问题在于摆脱旧的正方形。

My problem lies in getting rid if the old squares. Shouldn't they be erased each time drawRect is called?

我在下面放置了三张图片,希望可以解释我的意思。

I've placed three images below that hopefully explain what I mean.

我认为表格行缓存自定义单元格不是问题吗?
在此,一旦UITableCell建立单元出队,便会绘制记分条;单元格中的所有其他视图都是正确的,这使我认为问题出在drawRect无法清除图形上下文。

I don't think this is a problem with table rows caching custom cells? Here the scorebars are drawn once the UITableCell establishment cell is dequeued; all the other views in the cell are correct, which makes me think the issue is with drawRect failing to clear the graphics context.

- (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(如果存在),但是该代码永远不会找到DSFScorebarView类的其他子视图。最后,将创建scorebarView并将其添加到视图的子视图中。

During updateCellContent, we try to clear out old scorebarviews, if they exist, but the code never finds additional subviews of the DSFScorebarView class. Finally, the scorebarView is created and added to the view's subviews.

- (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];

}

得分栏视图使用在initWithInspections中使用drawRect并确保分数栏的长度不超过17平方(最近的检查)。每次检查都给定一个绿色=低|黄色=中等=高=的正方形,并在该正方形下方绘制年份。

The scorebarview is drawn using drawRect within initWithInspections and ensures that scorebars are no more than 17 squares long (most recent inspections). Each inspection is given a square of green = low|yellow = moderate|red = high and the year is drawn below the square.

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

I've set self.clearsContextBeforeDrawing = YES, but it doesn't correct the problem.

// 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(第2行)的记分栏已更改。

    在实施了@HaIR的解决方案后,我得到了一条灰色背景的白色条,在点击表格行后。在将多余的宽度添加到涂掉年线之后,这非常丑陋。

    After implementing @HaIR's solution below, I get a white strip against the grey background, after tapping a table row. It's pretty ugly, after adding the extra width to 'white-out' the Year line.

    - (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) {
      ...
    

    推荐答案

    您已经接管了DrawRect,因此它只会做您在dra中手动执行的操作

    You've taken over DrawRect, so its only going to do what you manually do in the dra

    您正在重新使用单元格,因此,例如,您在下面显示了Turf Hotel Restaurant图

    You are re-using cells, so, for example, you have the Turf Hotel Restaurant graph showing underneath the 2nd version of the Grace Market/Maple Plaza.

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

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

    If you are just clearing the background in your cells instead of having a background color. then:

    CGContextClearRect(context, rect);
    

    在DrawRect开始时可能更合适。

    at the start of your DrawRect may be more appropriate.

    修订:

    更仔细地看您的问题,根本的问题是您没有找到并删除旧的DSFScoreboardView。也许您应该尝试通过子视图进行递归搜索。像这样:

    Looking at your question more closely, the root problem is that you are not finding and deleting the old DSFScoreboardView's. Perhaps you should try a recursive search through the subviews. Like:

    - (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

    这篇关于为什么drawRect留下图像的一部分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆