CoreGraphics - 仅混合视图的*部分*

Posted

技术标签:

【中文标题】CoreGraphics - 仅混合视图的*部分*【英文标题】:CoreGraphics - Blending only *part* of a view 【发布时间】:2012-05-11 22:29:39 【问题描述】:

我最近看到了一篇关于使用 UITableViewCells 提高滚动性能的精彩文章:http://engineering.twitter.com/2012/02/simple-strategies-for-smooth-animation.html -- 虽然在这篇文章中可以找到许多很棒的技巧,但有一个特别让我感兴趣:

Twitter for iPhone 4.0 中的推文在微妙的纹理背景之上有一个投影。这提出了一个挑战,因为混合成本很高。 我们通过将阴影区域与单元格的内容区域分开来减少核心动画必须考虑不透明的区域来解决这个问题。

使用 ios 模拟器,点击 Debug - Color Blended Layers 会显示如下内容:

用红色标记的区域是混合的,绿色区域是不透明的。伟大的。这篇文章没有提到的是:我该如何实现这个?我的理解是 UIView 要么不透明,要么不透明。在我看来,实现这一点的唯一方法是使用子视图,但文章明确指出这是一个幼稚的实现

相反,我们的推文单元格包含一个没有子视图的视图;一个drawRect:绘制一切。

那么我该如何区分不透明的部分,以及我的单个 drawRect: 方法中不包含的部分?

【问题讨论】:

向他们发送电子邮件或推文,提出问题:p 在您得到答案时向 SO 报告 :) 通过 Twitter 与他们联系:bit.ly/LK7lvs -- 希望我们能得到正确的答案:) @nick 你收到回复了吗?我真的很感兴趣。这是一个很棒的问题,我很想知道是否有办法让视图的一部分变得透明。 很遗憾我没有。 【参考方案1】:

在您展示的示例中,我不相信他们通过视图显示背景。我认为他们正在模拟核心图形中的背景。换句话说,在每个单元格中,他们为背景绘制了浅灰色。然后他们绘制阴影(使用透明度),最后在顶部绘制其余的不透明内容。我可能是错的,但我不相信您可以使部分视图透明。如果是这样,我会对它非常非常感兴趣,因为我一直使用核心图形,但我避免使用圆角,因为为它混合整个视图似乎并不值得。

更新

在进行了更多研究并查看了 Apple 的文档后,我认为只有部分视图不透明是不可能的。此外,在阅读了 Twitter 的博客文章后,我认为他们并不是在说他们这样做了。请注意,当他们说:

相反,我们的推文单元格包含一个没有子视图的视图;一个drawRect:绘制一切。

他们专门谈论UILabelUIImageView。换句话说,他们不是使用那些视图,而是直接使用 Core Graphics 绘制图像。至于 UILabel,我个人使用 Core Text,因为它有更多的字体支持,但他们也可能使用更简单的东西,比如 NSString 的 drawAtPoint:withFont: 方法。但他们试图传达的主要观点是,单元格的 内容 都是一张 CG 绘图。

然后他们转到一个新部分:避免混合。在这里,他们强调要避免混合:

从单元格的内容区域分割阴影区域。

做到这一点的唯一方法是使用不同的视图。他们可以使用两种方法,但首先请注意,单元格分隔符本身就是叠加层(由 tableView 提供)。第一种方法是在单元格内使用多个视图。第二种方法是通过将适当的视图插入 UIScrollView 来覆盖/覆盖单元格后面/上方的阴影/混合视图。鉴于他们之前关于每个单元格只有一个 view/drawRect 的声明,这可能就是他们正在做的事情。每种方法都会有其挑战,但我个人认为将单元格拆分为 3 个视图(阴影、内容、阴影)会更容易。这将使处理第一个/最后一个单元格情况变得更加容易。

【讨论】:

当然我可以绘制渐变色和透明色,但是在 Tweet 单元格中,阴影位于边缘并让背景显示出来。这意味着我将它们绘制到的视图是不透明的,否则您会看到阴影后面的黑色背景而不是它们后面的视图。 我不认为它们是通过背景显示的。我认为他们正在模拟他们的单元格视图中的背景。我会更新我的答案来解释。 文章指出:“推文在微妙的纹理背景之上有一个阴影。这提出了一个挑战,因为混合成本很高。” -- 如果他们只是模拟背景,那么他们根本不需要混合任何东西,当你切换“颜色混合图层”时,整个单元格视图将是绿色的。 您可能需要与他们联系(如果他们愿意)。可以在单元格视图中轻松创建“微妙的纹理背景”。但是,该背景将随视图滚动。如果您找到答案,请发布它。我对此很感兴趣。 @nick 我已经做了一些研究并更新了我的答案。不幸的是,我认为不可能只使视图的一部分不透明。我希望是这样(它会让我的生活更轻松)。我也不认为他们声称他们这样做,乍一看似乎就是这样(请参阅我的更新答案)。【参考方案2】:

我不得不按照这些思路猜测一些东西http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadows/dq_shadows.html

  CGContextRef context = UIGraphicsGetCurrentContext();

UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:10.0f];

CGContextSaveGState(context);
CGRect leftRect = CGRectZero;
CGContextClipToRect(context, leftRect );
CGContextSetBlendMode(context, kCGBlendModeNormal);
// draw shadow

//    Call the function CGContextSetShadow, passing the appropriate values.
//    Perform all the drawing to which you want to apply shadows.
CGContextSetShadowWithColor(context, CGSizeMake(1.0f, 1.0f), 10.0f, [UIColor blackColor].CGColor);
CGContextAddPath(context, path.CGPath);
CGContextDrawPath(context, kCGPathStroke);


CGContextRestoreGState(context);

CGContextSaveGState(context);
CGRect middleSection = CGRectZero;
CGContextClipToRect(context, middleSection);
CGContextSetFillColorWithColor(context, self.backgroundColor.CGColor);
CGContextFillRect(context, self.bounds);
// draw opaque
CGContextSetBlendMode(context, kCGBlendModeCopy); 

CGContextRestoreGState(context);

【讨论】:

在上面的 Tweet 单元格中,阴影位于视图的左右两侧,位于另一个背景视图的顶部。我可以使用这段代码来绘制阴影,但除非我这样做[cell setOpaque:NO],否则阴影后面会有黑色背景。我想要的是让背景视图显示出来。 渲染背景图像,向左剪切/渲染阴影,向右剪切/渲染阴影,渲染前景。 你也可能想要 kCGBlendModeScreen 而不是普通的混合。 我会对此进行调查并报告。谢谢。【参考方案3】:

我的意见是:不要让 Core Animation 使用各种 layer properties 来绘制阴影。只需在两侧绘制一个预渲染的图像,这实际上是一个阴影。在stretch draw 中考虑单元格的可变高度可能会奏效。

编辑: 如果背景是素色的,则可以将预渲染阴影应用到两侧,而不会影响视觉吸引力。

如果不适用,tableview 必须缩小到没有阴影的大小。然后可以混合阴影而不需要对每个单元格进行混合,而只是“在顶部”。它真的不滚动。这仅在阴影没有任何“纹理”时才有效,否则人们会注意到它只是应用在顶部。

【讨论】:

如何绘制阴影并不重要。为了让背景通过它显示,整个视图必须设置为不透明。 这很重要,我想我可能描述得不够恰当。如果背景是静态的,您就不必混合,因此已经与静态背景混合的预渲染阴影只是在不混合的情况下进行绘制。请查看我的编辑。 是的,我意识到这个特殊的例子可以在没有混合的情况下完成。请参阅上面关于仅模拟背景的 Aaron 评论。我的问题不是“我如何创建这个单元格”,有几种方法可以做到。我想知道他们如何能够只混合视图的一部分而不将整个视图标记为不透明,并且不使用子视图。在其他无法绘制静态背景的情况下,学习如何做到这一点非常有价值。

以上是关于CoreGraphics - 仅混合视图的*部分*的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UITableViewController 中混合“自定义部分标题视图”和“常规标题”?

有关iOS使用CoreGraphics部分机型出现背景红块问题

将静态字符串与视图参数混合

与核心图形的加法混合

如何在 iPhone 中混合来自不同视图的颜色

setNeedsDisplayInRect:导致整个视图被更新