1
votes

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);
2

2 Answers

1
votes

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

0
votes

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.