在CATiledLayer -setNeedsDisplay之后,并非所有图块都重新绘制

时间:2011-03-04 19:09:36

标签: iphone cocoa-touch ipad ios catiledlayer

我的观点有CATiledLayer。视图控制器具有自定义缩放行为,因此在-scrollViewDidEndZooming上需要重新绘制每个图块。但是,即使在每次缩放后在图层上调用-setNeedsDisplay,也不会重绘所有图块。这导致视图在缩放后有时看起来有问题。 (应该只出现在1个图块中的东西出现在多个地方)。它经常在另一次变焦后自行修正。

这是相关代码。 updatedRects用于测试 - 它存储请求由-drawLayer绘制的唯一矩形。

CanvasView.h:

@interface CanvasView : UIView
@property (nonatomic, retain) NSMutableSet *updatedRects; 
@end

CanvasView.m:

@implementation CanvasView

@synthesize updatedRects; 

+ (Class)layerClass 
{
    return [CATiledLayer class];
}

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
    CGRect rect = CGContextGetClipBoundingBox(context); 
    [updatedRects addObject:[NSValue valueWithCGRect:rect]]; 

    CGContextSaveGState(context); 
    CGContextTranslateCTM(context, rect.origin.x, rect.origin.y); 
    // ...draw into context...
    CGContextRestoreGState(context); 
}

@end

MyViewController.m:

@implementation MyViewController

- (void)viewDidLoad 
{
    [super viewDidLoad];

    canvasView.updatedRects = [NSMutableSet set]; 
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    canvasView.transform = CGAffineTransformIdentity; 
    canvasView.frame = CGRectMake(0, 0, canvasView.frame.size.width * scale, canvasView.frame.size.height); 
    [self updateCanvas]; 
}

- (void)updateCanvas
{
    NSLog(@"# rects updated: %d", [canvasView.updatedRects count]); 
    [canvasView.updatedRects removeAllObjects]; 
    canvasView.frame = CGRectMake(canvasView.frame.origin.x, canvasView.frame.origin.y, canvasView.frame.size.width, myHeight); 
    CGFloat tileSize = 256; 
    NSLog(@"next # rects updated will be: %f", [canvasView.layer bounds].size.width / tileSize); 
    [canvasView.layer setNeedsDisplay]; 
}

@end

测试时,我总是在缩放后一直在视图中滚动,以确保看到每个图块。每当视图看起来错误时,预测的“下一个更新的数量”大于下一次调用-updateCanvas时实际的“更新的数量”。什么会导致这个?

修改:

这是一种可视化问题的更好方法。每次调用updateCanvas时,我都会更改绘制切片的背景颜色并记录调用时间 - 颜色和时间存储在canvasView中。在每个图块上绘制图块的矩形,沿x轴的图块索引,设置背景颜色的时间(秒)以及图块绘制时的时间(秒)。如果一切正常,所有瓷砖应该是相同的颜色。相反,这是我有时会看到的:

Screenshot of tiles with mismatched colors Screenshot of tiles with mismatched colors

我在缩小后似乎只看到错误的结果。 问题可能与scrollViewDidEndZooming,因此updateCanvas每次缩小多次调用的事实有关。编辑:不 - 不多次被召唤。)

1 个答案:

答案 0 :(得分:10)

有一个相当昂贵的黑客可能对你有用:

tiledLayer.contents = nil;
[tiledLayer setNeedsDisplayInRect:tiledLayer.bounds];

如果我没记错的话,第一行实际上将平铺图层转换为普通图层,但第二行将其转回。但是,它会将所有内容都扔到平铺层中。