将屏幕外 CGLayer 传送到当前上下文时出现锯齿状路径
Posted
技术标签:
【中文标题】将屏幕外 CGLayer 传送到当前上下文时出现锯齿状路径【英文标题】:Jaggy paths when blitting an offscreen CGLayer to the current context 【发布时间】:2011-10-11 15:31:53 【问题描述】:在我当前的项目中,我需要绘制一个复杂的背景作为几个 UITableView 单元格的背景。由于在单元格的 drawRect: 方法中执行时用于绘制此背景的代码很长且占用大量 CPU 资源,因此我决定仅将其渲染到 CGLayer 一次,然后将其 blit 到单元格以提高整体性能。
我用来为 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;
将图层blit到当前上下文的代码:
- (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
documentation:
如果指定值
0.0
,则比例因子设置为比例 设备主屏幕的因素。
基本上意味着,如果它是一个视网膜显示器,它将创建一个视网膜上下文,这样您就可以指定0.0
并将坐标视为点。
【讨论】:
很好的答案!没有尝试过,但我会接受这个比我的答案更新的答案;)【参考方案2】:我要回答我自己的问题,因为我前段时间想通了。 您应该创建一个视网膜感知上下文。锯齿状只出现在视网膜设备上。
为了应对这种行为,您应该使用这个辅助方法创建一个视网膜上下文:
// 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);
...
【讨论】:
嘿@bitshiftcop,我试过你的答案,但它不起作用,我没有看到任何绘图。你能帮我解决这个问题吗?以上是关于将屏幕外 CGLayer 传送到当前上下文时出现锯齿状路径的主要内容,如果未能解决你的问题,请参考以下文章