UIView: как сделать неразрушающий рисунок? - PullRequest
17 голосов
/ 15 мая 2009

Мой оригинальный вопрос:

Я создаю простой рисунок приложение и должны быть в состоянии рисовать поверх существующего, ранее нарисованного контента в моем drawRect. Как правильно рисовать поверх существующего контента? без полной замены?

Основываясь на ответах, полученных здесь и в других местах, заключаем сделку.

  1. Вы должны быть готовы перерисовать весь прямоугольник всякий раз, когда drawRect называется.

  2. Вы не можете предотвратить удаление содержимого, выполнив следующие действия:

    [self setClearsContextBeforeDrawing: NO];

    Это всего лишь подсказка графическому движку, что нет смысла предварительно его очищать, поскольку вам, вероятно, все равно придется перерисовывать всю область. Это может помешать автоматическому удалению вашего вида, , но вы не можете зависеть от него .

  3. Чтобы рисовать поверх вашего вида без стирания, сделайте ваш рисунок в закадровом растровом контексте (который никогда не очищается системой.) Затем в вашем drawRect скопируйте из этого внеэкранного буфера на вид.

Пример:

- (id) initWithCoder: (NSCoder*) coder {    
     if (self = [super initWithCoder: coder]) {
         self.backgroundColor = [UIColor clearColor];
         CGSize size = self.frame.size;
         drawingContext = [self createDrawingBufferContext: size];
     }

     return self;
 }

- (CGContextRef) createOffscreenContext: (CGSize) size  {
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width*4, colorSpace, kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colorSpace);

    CGContextTranslateCTM(context, 0, size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    return context;
}


- (void)drawRect:(CGRect) rect {    
    UIGraphicsPushContext(drawingContext);
    CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext); 
    UIImage *uiImage = [[UIImage alloc] initWithCGImage:cgImage];
    UIGraphicsPopContext();
    CGImageRelease(cgImage);
    [uiImage drawInRect: rect];
    [uiImage release];
 }

TODO : может ли кто-нибудь оптимизировать drawRect, чтобы для копии использовалась только (обычно крошечная) измененная область прямоугольника?

Ответы [ 4 ]

5 голосов
/ 15 мая 2009

Довольно часто все рисуют на закадровом изображении и просто отображают это изображение при рисовании на экране. Вы можете прочитать: Создание контекста растровой графики .

1 голос
/ 15 июня 2010

При оптимизации drawRect

Попробуйте это:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext);
    CGContextClipToRect(context, rect);
    CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), cgImage);
    CGImageRelease(cgImage);
}

После этого вы также должны закомментировать следующие строки в вашем коде:

//CGContextTranslateCTM(context, 0, size.height);
//CGContextScaleCTM(context, 1.0, -1.0);

Также создан отдельный вопрос , чтобы быть уверенным, что это оптимальный путь.

0 голосов
/ 12 июля 2012

Это предотвращает стирание вашего вида перед выполнением drawRect:

[self.layer setNeedsDisplay];

Кроме того, я считаю, что лучше рисовать все в методе drawRect (если у вас нет веских причин не делать этого). Рисование за кадром и передача занимает больше времени и добавляет больше сложности, чем простое рисование всего один раз.

0 голосов
/ 14 ноября 2009

Кажется, это лучший метод, чем я использовал. То есть в случае касания я делаю копию представления, которое должно быть обновлено. Затем в drawRect я беру это изображение и рисую его в виде и одновременно изменяю другой вид.

Но это кажется неэффективным, но единственный способ, которым я понял, как это сделать.

...