Графика iOS Core: рисуйте ТОЛЬКО тени CGPath

Я рисую простой путь в iOS 5 с Core Graphics:

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(   path, NULL, center.x   , topMargin   );
CGPathAddLineToPoint(path, NULL, center.x+20, topMargin+50);
CGPathAddLineToPoint(path, NULL, center.x   , topMargin+40);
CGPathAddLineToPoint(path, NULL, center.x-20, topMargin+50);
CGPathAddLineToPoint(path, NULL, center.x   , topMargin   );

Теперь я хочу заполнить его в режиме наложения так:

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0.4] setFill];
CGContextAddPath(context, path);
CGContextSetBlendMode (context, kCGBlendModeOverlay);
CGContextFillPath(context);

Что дает мне именно ожидаемый результат. Но затем я хочу создать эффект тиснения. Я думал об использовании белой и черной тени, чтобы добиться такого эффекта:

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(1, 1), 1.0, highlightColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(-1, -1), 1.0, shadowColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

Проблема в том, что тени не рисуются, когда альфа установлен на 0.
Теперь вопрос: есть ли способ рисовать только тени без цвета заливки, но с полной альфа-версией? Могу ли я как-нибудь предотвратить прорисовку внутренней части моего пути? Или, возможно, существует более простой способ рисования двух теней для одного пути?

2 ответа

Решение

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

CGContextSaveGState(context);
CGRect boundingRect = CGContextGetClipBoundingBox(context);
CGContextAddRect(context, boundingRect);
CGContextAddPath(context, path);
CGContextEOClip(context);

[[UIColor blackColor] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(1, 1), 1.0, highlightColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(-1, -1), 1.0, shadowColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

CGContextRestoreGState(context);

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

Проблема в том, что тени не рисуются, когда альфа установлена ​​на 0.

Да, тень зависит от альфа-значения формы для рендеринга.

Теперь вопрос: есть ли способ рисовать только тени без цвета заливки, но в полной альфе? Могу ли я как-то предотвратить отрисовку внутренней части моего пути? Или, возможно, есть более простой способ нарисовать две тени для одного пути?

Вы можете нарисовать только тень без рендеринга основной фигуры. Идея такова:

  1. добавить дополнительную ширину смещения к тени, смещение должно быть достаточно большим, то есть ширина контекста/холста. Чтобы тень была отделена от основной формы.
  2. Переместите контекст с таким же отрицательным смещением по горизонтали, чтобы основная фигура была перемещена за пределы области визуализации, а тень переместилась назад.

Для слоя только с тенью вы, вероятно, захотите использоватьbeginTransparencyLayer(auxiliaryInfo:)иsaveGState()чтобы поместить рисунок в отдельный контекст.

Вот сравнение:

Для фрагмента кода вы можете проверить мой ответ на другой вопрос здесь: https://stackoverflow.com/a/74844890/3164091

Другие вопросы по тегам