不是所有的瓷砖重绘后CATiledLayer -setNeedsDisplay [英] Not all tiles redrawn after CATiledLayer -setNeedsDisplay

查看:304
本文介绍了不是所有的瓷砖重绘后CATiledLayer -setNeedsDisplay的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的视图有一个 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);
// ...绘制上下文...
CGContextRestoreGState(context);
}

@end

MyViewController.m: p>

  @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:%f,[canvasView.layer bounds] .size.width / tileSize);
[canvasView.layer setNeedsDisplay];
}

@end

缩放后一直滚动视图,以确保每个磁贴都被看到。每当视图看起来不正确时,在下一次调用 -updateCanvas 时,预测的下一个rects更新大于实际的#of rects updated。会是什么原因?



编辑



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




我看起来似乎在缩小后看到错误的结果。 问题可能与 scrollViewDidEndZooming ,因此 updateCanvas 的事实有关,可以每次调用多次:不会多次调用。

解决方案

p>有一个相当昂贵的黑客可能为你工作:

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

如果我记得正确,第一行实际上将瓷砖层转换为普通图层,线将其转回。然而,它会把一切都放在平铺的图层中。


My view has a CATiledLayer. The view controller has custom zooming behavior, so on -scrollViewDidEndZooming every tile needs to be redrawn. But, even though -setNeedsDisplay is being called on the layer after every zoom, not all tiles are being redrawn. This is causing the view to sometimes look wrong after a zoom. (Things that should appear in just 1 tile are appearing in multiple places). It often corrects itself after another zoom.

Here's the relevant code. updatedRects is for testing -- it stores the unique rectangles requested to be drawn by -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

When testing this, I always scrolled all the way across the view after zooming to make sure every tile was seen. Whenever the view looked wrong, the predicted "next # of rects updated" was greater than the actual "# of rects updated" on the next call to -updateCanvas. What would cause this?

Edit:

Here's a better way to visualize the problem. Each time updateCanvas is called, I've made it change the background color for drawing tiles and record the time it was called -- the color and time are stored in canvasView. On each tile is drawn the tile's rectangle, the tile's index along the x axis, the time (sec.) when the background color was set, and the time (sec.) when the tile was drawn. If everything is working correctly, all tiles should be the same color. Instead, here's what I'm sometimes seeing:

I only seem to see wrong results after zooming out. The problem might be related to the fact that scrollViewDidEndZooming, and therefore updateCanvas, can get called multiple times per zoom-out. (Edit: No-- not called multiple times.)

解决方案

There is a rather expensive hack that might work for you:

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

If I recall correctly, the first line actually turns the tiled layer to an ordinary layer, but the second line turns it back. However, it’ll throw everything in the tiled layer away.

这篇关于不是所有的瓷砖重绘后CATiledLayer -setNeedsDisplay的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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