CAPluginLayer和CABackdropLayer

最初发表在我的(新的)杂物房中。

私有标头中隐藏着很多很酷的CoreAnimation好吃的东西,但是确实吸引了我的三个私有CALayer类: CAProxyLayerCALayerHostCABackdropLayerCAPluginLayerCALayerHost设计与CARemoteLayerClient/Server相似,因此我将在以后的文章中介绍这两个类。 我对CAProxyLayer了一些实验,因为它用于视觉效果(想想NS/UIVisualEffectView ),或者我不知道正确的常量或没有正确使用它,但是我无法使它可靠地工作而没有麻烦windowserver 。 我将使用代码示例来讨论其余两个。

这个名字很怪异,但是看起来它是为支持windowserver插件而设计的-甚至还有一个vtable,但是到目前为止,仅支持com.apple.WindowServer.CGSWindow 。 这是一个代码示例:

 let layer = CAPluginLayer() 
layer.frame = CGRect(x: 50, y: 50, width: 200, height: 200)
layer.pluginType = "com.apple.WindowServer.CGSWindow"
layer.pluginId = UInt64(self.window.windowNumber)
layer.pluginGravity = kCAGravityResizeAspect
//layer.pluginFlags = 0x4 // display without a shadow

因此,最大的CAPluginLayer是,现在您只能使用CAPluginLayer实时镜像窗口(其所有UI更改和交互都反映在图层内容中)。 您可以像设置pluginGravity一样设置pluginGravity ,并且唯一已知的pluginFlags值为0x4 ,Dock使用pluginFlags值来显示没有阴影的窗口。

pluginId实际上是指windowNumber (或_realWindowNumber具体取决于您的窗口类型,但这通常不必担心),并且实际上可以是*屏幕上可用的任何窗口! 没错–您可以镜像任何窗口,而不仅仅是自己应用程序的窗口。 为了娱乐,我使用CGWindowListCopyWindowInfo来获取最前面的窗口(不是我自己的应用程序),并使用该ID将其镜像到我的应用程序层中。 在这一点上可能会得出结论,如果我可以看到ANY应用程序窗口的内容,则将是一个严重的安全违规,但事实并非如此。 使用Xcode UI层次结构捕获工具,您将看不到图层内部的任何内容,这是因为CAPluginLayerCAPluginLayer渲染(因此需要layerUsesCoreImageFiltersfalse )。

Dock使用它来显示最小化的窗口,而AppKit使用它来管理全屏窗口过渡中的工具栏(在该过渡中,工具栏和标题栏实际上已移入固定在屏幕菜单栏的新窗口中)。 在您自己的应用程序中,假设您已经在使用长时间运行的XPC守护程序,则如果您不想使用CGSWindow*函数或创建虚假的窗口屏幕截图层,则可以请求该守护程序无缝地对Windows进行动画处理。并对其进行动画处理。 您可以将窗口的windowNumber发送到守护程序,该守护程序将使用屏幕大小为NSWindow且内部带有CAPluginLayer的守护程序(确保将pluginFlags设置为0x0 !)并对该层进行动画处理。 这种方法有很多问题,但是尝试一下很有趣!

CABackdropLayer用于在iOS( UIVisualEffectView )上显示图层混合,而在macOS( NSVisualEffectView )上仅显示窗口内图层混合。 这是一个代码示例:

 let layer = CABackdropLayer() 
layer.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
layer.allowsHitTesting = true
layer.groupName = "group_name_here"
layer.windowServerAware = true
let blur = CAFilter(type: kCAFilterGaussianBlur)!
blur.setValue(true, forKey: "inputNormalizeEdges")
blur.setValue(30.0, forKey: "inputRadius")
let saturate = CAFilter(type: kCAFilterColorSaturate)!
saturate.setValue(1.8, forKey: "inputAmount")
layer.filters = [blur, saturate]
layer.name = "backdrop"
layer.scale = 0.25
layer.bleedAmount = 0.2

使用CABackdropLayer ,请确保将windowServerAware设置为true ,并将其父视图上的layerUsesCoreImageFilters设置为false ,否则效果将不起作用(因为它也在layerUsesCoreImageFilters呈现)。 CAFilter的任何组合都可以在CABackdropLayer ,因为我尝试过的所有尝试都没有使我失败,但是在代码示例中,我复制了macOS Sierra饱和的充满活力的灯光外观(尽可能接近)。 我认为scale很重要,因为我相信它是基础内容的采样大小,将其设置为2.0会使渲染速度变慢。 我也不知道为什么,但是groupName总是设置在背景图层上,并且总是唯一的。 它与windowserver渲染有关,因为有一个属性使其成为“全局唯一”名称。

我建议不要在NSVisualEffectView使用CABackdropLayer ,因为除非使用AppKit类,否则很多边缘情况都无法正确处理,但对于教育性练习或带有一些有趣的滤镜组合的vibrantDark (也许不是vibrantDark就是这样)。不能为您做这件事吗?)它会产生一些很好的融合效果。