使用 CATiledLayer 时 setNeedsDisplayInRect 重绘整个视图

发布于 2024-08-19 04:06:54 字数 2494 浏览 4 评论 0原文

这是我第一次发帖,所以请原谅我在 stackoverflow 礼仪中的任何失误。

我还没有找到任何示例代码或任何解决我遇到的问题的问题,所以希望有人能对此有所启发。

我正在使用 Quartz,并且有一个 CATiledLayer,我在上面绘制了几个可以单击的框。当您单击其中一个时,我想用蓝色轮廓重新绘制该框,但不重新绘制视图的其余部分。从我读过的评论来看,一旦我单击其中一个框的边界,并将脏矩形设置为该框的大小,我似乎应该使用 setNeedsDisplayInRect 而不是 setNeedsDisplay 。但是,每当我的 (void)drawRect:(CGRect)rect 函数被调用时, (void)drawRect:(CGRect)rect 中的矩形始终是我的视图的大小,无论我尝试在 setNeedsDisplayInRect 中使哪个矩形无效。我不认为我在其他任何地方调用 setNeedsDisplay 或 setNeedsDisplayInRect,但由于某种原因整个视图无效。如果我不使用 CATiledLayer,则不会出现此问题,并且在调用 setNeedsDisplayInRect 时,DrawRect 会收到正确的矩形。

这是我的代码的简化版本:

#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>

#import "EAGLView.h"
#import "MapViewController.h"


// A class extension to declare private methods
@interface EAGLView ()

@property (nonatomic, retain) EAGLContext *context;

@end

@implementation EAGLView

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

- (id)initWithFrame:(CGRect)frame
{
    //self.frame.size.width is 920
    //self.frame.size.height is 790
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor whiteColor];

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        _myContext = CGBitmapContextCreate(NULL, self.frame.size.width, self.frame.size.height, 8, 4*self.frame.size.width, colorSpace, kCGImageAlphaPremultipliedFirst);
        CGColorSpaceRelease(colorSpace);

        _myLayer = CGLayerCreateWithContext(_myContext, self.frame.size, NULL);

        CATiledLayer *animLayer = (CATiledLayer *) self.layer;
        animLayer.levelsOfDetailBias = 2;
        animLayer.tileSize = CGSizeMake(1000,1000);


    }
    return self;    
}


- (void)drawRect:(CGRect)rect {
    // Drawing code, rect is always equal to the size of the view (920,720)

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    testRect = CGRectMake(0, 0, 100.0, 100.0);
    [self setNeedsDisplayInRect:testRect];
}

- (void)dealloc {

    [super dealloc];
}

@end

还有其他人遇到过这样的问题吗?这是 CATiledLayer 的限制还是我只是错误地使用了它?顺便说一句,我使用 CATiledLayer 的原因仅仅是为了在放大和缩小 UIScrollView 时可以保持清晰的图形。 CATiledLayer 嵌入在 UIScrollView 中,但从 UIScrollView 中删除 CATiledLayer 并不能解决此问题。如果有人可以建议更好的替代方案来获得缩放时的“矢量化图形”效果,请告诉我。我在 CATiledLayer 上花了很多时间,但我就是无法让它做我想做的事。

编辑:我可以删除这些行,但仍然遇到相同的问题:

CATiledLayer *animLayer = (CATiledLayer *) self.layer;
animLayer.levelsOfDetailBias = 2;
animLayer.tileSize = CGSizeMake(1000,1000);

this is my first time posting so please excuse any lapses in stackoverflow etiquette.

I haven't found any example code or any questions that address the problem I'm having, so hopefully someone can shed some light on this.

I'm using Quartz and I have a CATiledLayer on which I have drawn several boxes you can click on. When you click one, I want to redraw that box with a blue outline, but not redraw the rest of the view. From the comments I have read it seems like I should be using setNeedsDisplayInRect instead of setNeedsDisplay once I have clicked inside the bounds of one of the boxes, and set the dirty rect to the size of that box. However, whenever my (void)drawRect:(CGRect)rect function is called, the rect in (void)drawRect:(CGRect)rect is always the size of my view, no matter what rect I tried to invalidate in setNeedsDisplayInRect. I don't think I am calling setNeedsDisplay or setNeedsDisplayInRect anywhere else, but for some reason the entire view is invalidated. If I don't use a CATiledLayer, this problem doesn't appear and DrawRect receives the correct rect when setNeedsDisplayInRect is called.

Here is a simplified version of my code:

#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>

#import "EAGLView.h"
#import "MapViewController.h"


// A class extension to declare private methods
@interface EAGLView ()

@property (nonatomic, retain) EAGLContext *context;

@end

@implementation EAGLView

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

- (id)initWithFrame:(CGRect)frame
{
    //self.frame.size.width is 920
    //self.frame.size.height is 790
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor whiteColor];

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        _myContext = CGBitmapContextCreate(NULL, self.frame.size.width, self.frame.size.height, 8, 4*self.frame.size.width, colorSpace, kCGImageAlphaPremultipliedFirst);
        CGColorSpaceRelease(colorSpace);

        _myLayer = CGLayerCreateWithContext(_myContext, self.frame.size, NULL);

        CATiledLayer *animLayer = (CATiledLayer *) self.layer;
        animLayer.levelsOfDetailBias = 2;
        animLayer.tileSize = CGSizeMake(1000,1000);


    }
    return self;    
}


- (void)drawRect:(CGRect)rect {
    // Drawing code, rect is always equal to the size of the view (920,720)

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    testRect = CGRectMake(0, 0, 100.0, 100.0);
    [self setNeedsDisplayInRect:testRect];
}

- (void)dealloc {

    [super dealloc];
}

@end

Has anyone else run into a problem like this? Is this a limitation of CATiledLayer or am I just using it incorrectly? By the way, the reason I am using the CATiledLayer is solely so that I can maintain sharp graphics as I zoom in and out on a UIScrollView. The CATiledLayer is embedded in a UIScrollView, but removing the CATiledLayer from the UIScrollView does not fix this problem. If anyone can suggest a better alternative to get the "vectorized graphics" effect on zoom, please let me know. I've spent a lot of time with CATiledLayer and I just can't get it to do what I want.

Edit: I can remove these lines and still get the same problem:

CATiledLayer *animLayer = (CATiledLayer *) self.layer;
animLayer.levelsOfDetailBias = 2;
animLayer.tileSize = CGSizeMake(1000,1000);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

爱你是孤单的心事 2024-08-26 04:06:54

好吧,看起来如果我添加行 animLayer.levelsOfDetail = 2;在 animLayer.levelsOfDetailBias 之后,它解决了我遇到的问题。现在正确的矩形正在发送到drawRect,并且在我更新时没有闪烁。我想这是一个非常简单的修复,我需要阅读如何使用levelsofDetailBias 和levelsOfDetail。

编辑:这实际上解决了我遇到的另一个问题,但我仍然无法将正确的 dirtyRect 传递给 DrawRect,所以请忽略这个

Well, it seems like if I add the line animLayer.levelsOfDetail = 2; right after animLayer.levelsOfDetailBias, it fixed the problem I had. The correct rect is being sent to drawRect now, and there is no flicker as I update. I guess that was a pretty simple fix, and I need to read up on how to use levelsofDetailBias and levelsOfDetail.

Edit: This actually fixed another problem I had, but I still can't get the correct dirtyRect to be passed to DrawRect, so please disregard this

半步萧音过轻尘 2024-08-26 04:06:54

来自 Apple 的问答:“整个视图将如果您调用 -setNeedsDisplayInRect:-setNeedsDisplay:,则会重绘。”

看起来 -setNeedsDisplayInRect: 方法并没有比 -setNeedsDisplay: 方法有任何好处。这导致人们猜测此行为是 iOS 处理重绘的错误。

似乎没有一个干净简单的解决方案。其中的建议是将您的视图分解为多个子视图,并仅对受影响的子视图请求重绘,或者自行跟踪要重绘的区域。

包括我在内的其他一些人也遇到了同样的问题,例如此处这里< /a>.

From Apple's Q&A: "the entire view will be redrawn if you call -setNeedsDisplayInRect: or -setNeedsDisplay:."

It seems that the -setNeedsDisplayInRect: method doesn't give any benefits over the method -setNeedsDisplay:. This has lead to speculations that this behaviour is a bug in iOS's handling of redraws.

There doesn't seem to be a clean and simple solution. Among the suggestions are to break up your view into several subviews and request redraws only for those which are affected, or to keep track of the area to redraw on your own.

Some others, including me, had the same problem, e.g. here and here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文