#performance #core-graphics #antialiasing #cglayer #blit
#Производительность #ядро-графика #сглаживание #cglayer #блиц
Вопрос:
В моем текущем проекте мне нужно нарисовать сложный фон в качестве фона для нескольких ячеек UITableView. Поскольку код для рисования этого фона довольно длинный и загружает процессор при выполнении в методе drawRect: ячейки, я решил отобразить его только один раз на CGLayer, а затем наложить его на ячейку, чтобы повысить общую производительность.
Код, который я использую для рисования фона для CGLayer:
(CGLayerRef)standardCellBackgroundLayer
{
static CGLayerRef standardCellBackgroundLayer;
if(standardCellBackgroundLayer == NULL)
{
CGContextRef viewContext = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, [UIScreen mainScreen].applicationFrame.size.width, PLACES_DEFAULT_CELL_HEIGHT);
standardCellBackgroundLayer = CGLayerCreateWithContext(viewContext, rect.size, NULL);
CGContextRef context = CGLayerGetContext(standardCellBackgroundLayer);
// Setup the paths
CGRect rectForShadowPadding = CGRectInset(rect, (PLACES_DEFAULT_CELL_SHADOW_SIZE / 2) PLACES_DEFAULT_CELL_SIDE_PADDING, (PLACES_DEFAULT_CELL_SHADOW_SIZE / 2));
CGMutablePathRef path = createPathForRoundedRect(rectForShadowPadding, LIST_ITEM_CORNER_RADIUS);
// Save the graphics context state
CGContextSaveGState(context);
// Draw shadow
CGContextSetShadowWithColor(context, CGSizeMake(0, 0), PLACES_DEFAULT_CELL_SHADOW_SIZE, [Skin shadowColor]);
CGContextAddPath(context, path);
CGContextSetFillColorWithColor(context, [Skin whiteColor]);
CGContextFillPath(context);
// Clip for gradient
CGContextAddPath(context, path);
CGContextClip(context);
// Draw gradient on clipped path
CGPoint startPoint = rectForShadowPadding.origin;
CGPoint endPoint = CGPointMake(rectForShadowPadding.origin.x, CGRectGetMaxY(rectForShadowPadding));
CGContextDrawLinearGradient(context, [Skin listGradient], startPoint, endPoint, 0);
// Restore the graphics state and release everything
CGContextRestoreGState(context);
CGPathRelease(path);
}
return standardCellBackgroundLayer;
}
Код для привязки слоя к текущему контексту:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawLayerAtPoint(context, CGPointMake(0.0, 0.0), [Skin standardCellBackgroundLayer]);
}
На самом деле это делает трюк довольно приятным, но единственная проблема, с которой я сталкиваюсь, заключается в том, что закругленные углы (проверьте статический метод). Очень неровные при наложении на экран. Это было не так, когда код рисования находился в исходном положении: в методе drawRect.
Как мне вернуть это сглаживание?
По какой-то причине следующие методы не оказывают никакого влияния на сглаживание:
CGContextSetShouldAntialias(context, YES);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetAllowsAntialiasing(context, YES);
Заранее спасибо!
Ответ №1:
Вы можете упростить это, просто используя UIGraphicsBeginImageContextWithOptions
и установив масштаб на 0.0
.
Извините за пробуждение старого сообщения, но я наткнулся на это, так что кто-то другой тоже может. Более подробную информацию можно найти в UIGraphicsBeginImageContextWithOptions
документации:
Если вы укажете значение
0.0
, масштабный коэффициент будет установлен на масштабный коэффициент главного экрана устройства.
В основном это означает, что если это дисплей retina, он создаст контекст retina, таким образом, вы можете указать 0.0
и обрабатывать координаты как точки.
Комментарии:
1. Отличный ответ! Не пробовал, но я приму это как более актуальный ответ, чем мой;)
Ответ №2:
Я собираюсь ответить на свой собственный вопрос, поскольку я понял это некоторое время назад. Вы должны создать контекст, учитывающий сетчатку. Неровности появлялись только на устройстве retina.
Чтобы противостоять этому поведению, вы должны создать контекст retina с помощью этого вспомогательного метода:
// Begin a graphics context for retina or SD
void RetinaAwareUIGraphicsBeginImageContext(CGSize size)
{
static CGFloat scale = -1.0;
if(scale < 0.0)
{
UIScreen *screen = [UIScreen mainScreen];
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.0)
{
scale = [screen scale]; // Retina
}
else
{
scale = 0.0; // SD
}
}
if(scale > 0.0)
{
UIGraphicsBeginImageContextWithOptions(size, NO, scale);
}
else
{
UIGraphicsBeginImageContext(size);
}
}
Затем в вашем методе рисования вызовите метод, указанный выше, следующим образом:
(CGLayerRef)standardCellBackgroundLayer
{
static CGLayerRef standardCellBackgroundLayer;
if(standardCellBackgroundLayer == NULL)
{
RetinaAwareUIGraphicsBeginImageContext(CGSizeMake(320.0, 480.0));
CGRect rect = CGRectMake(0, 0, [UIScreen mainScreen].applicationFrame.size.width, PLACES_DEFAULT_CELL_HEIGHT);
...
Комментарии:
1. Эй, @bitshiftcop, я попробовал ваш ответ, но он не работает, я не вижу никакого отрисованного рисунка. Можете ли вы помочь мне с этим.