UIView: как сделать неразрушающий рисунок?

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

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

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

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

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

    [self setClearsContextBeforeDrawing: NO];

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

  • Чтобы рисовать поверх вашего представления без стирания, сделайте рисунок в контекстном растровом контексте (который никогда не очищается системой.) Затем в 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, чтобы для копии использовалась только (обычно маленькая) область прямоугольника?

Ответы

Ответ 2

Оптимизация 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);

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

Ответ 3

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

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

Ответ 4

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

[self.layer setNeedsDisplay];

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