Как я мог обмануть [CALayer renderInContext:], чтобы отобразить только часть слоя?

Я хорошо знаю, что нет никакого хорошего способа сделать небольшую часть UIView для изображения, кроме того, чтобы отобразить весь вид и обрезку. (ОЧЕНЬ дорогой на чем-то вроде iPad 3, где получилось огромное изображение). См. здесь для описания метода renderInContext (нет альтернатив).

Часть представления, которую я хочу отобразить, не может быть предопределена, что означает, что я не могу настроить иерархию представления для маленького раздела как своего собственного UIView (и, следовательно, CALayer).

Моя идея...

У меня была идея, но мне нужно какое-то направление, если я собираюсь добиться успеха. Что делать, если я создаю категорию в UIView (или CALayer), которая добавляет метод по строкам:

[UIView renderSubframe:(CGFrame)frame];

Как? Ну, я думаю, что если бы фиктивный взгляд на размер подкадра был создан, тогда представление можно было временно переключить на это. Затем слой фиктивного представления может вызвать renderInContext:, что приводит к эффективному и быстрому способу получения представлений.

Итак...

Я действительно не настолько, чтобы ускориться с CALayer/Quartz core stuff... Будет ли это иметь какие-либо шансы работать? Если нет, то каким другим способом я мог бы достичь одного и того же, что наиболее эффективным способом я мог бы достичь того же результата (или кто-то еще столкнулся с этой проблемой и придумал другое решение)?

Ответ 1

Здесь категория, в которую я закончила писать. Не так сложно, как я думал, благодаря удобному CGAffineTransform.

#import "UIView+RenderSubframe.h"
#import <QuartzCore/QuartzCore.h>

@implementation UIView (RenderSubframe)

- (UIImage *) renderWithBounds:(CGRect)frame {

    CGSize imageSize = frame.size;

    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
    CGContextRef c = UIGraphicsGetCurrentContext();

    CGContextConcatCTM(c, CGAffineTransformMakeTranslation(-frame.origin.x, -frame.origin.y));
    [self.layer renderInContext:c];

    UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return screenshot;

}

@end

Ответ 2

Несколько различных способов сделать это:

  • укажите CGContextClipToRect для вашего контекста перед вызовом renderInContext;

  • Использование:

setNeedsDisplayInRect:

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

     - (void)setNeedsDisplayInRect:(CGRect)theRect

Это сделает рендеринг только в указанном прямоугольнике. Я не уверен, будет ли это работать согласно вашему требованию.

Я думаю, что первый вариант должен работать без проблем.