2016-01-27 45 views
1

我正试图把我自己的意见放在可可的NSPathControl上。为什么空的drawRect会干扰简单的动画?

enter image description here

在出价找出处理,当你鼠标悬停在控制组件,我组建了一个非常简单的示例应用程序,你得到了扩大合同动画的最佳方式。起初事情进展顺利 - 鼠标移入或移出包含路径成分的观点和你使用下面的代码得到一个简单的动画:

// This code belongs to PathView (not PathComponentView) 

override func mouseEntered(theEvent: NSEvent) { 

    NSAnimationContext.runAnimationGroup({ (ctx) -> Void in 
     self.animateToProportions([CGFloat](arrayLiteral: 0.05, 0.45, 0.45, 0.05)) 
    }, completionHandler: {() -> Void in 
      // 
    }) 
} 

// Animating subviews 

func animateToProportions(proportions: [CGFloat]) { 

    let height = self.bounds.height 
    let width = self.bounds.width 

    var xOffset: CGFloat = 0 
    for (i, proportion) in enumerate(proportions) { 
     let subview = self.subviews[i] as! NSView 
     let newFrame = CGRect(x: xOffset, y: 0, width: width * proportion, height: height) 
     subview.animator().frame = newFrame 
     xOffset = subview.frame.maxX 
    } 
} 

如在控制的下一步发展,而不是使用NSView我的路径组件实例,我开始用自己的NSView子类:

class PathComponentView: NSView { 

    override func drawRect(dirtyRect: NSRect) { 
     super.drawRect(dirtyRect) 
    } 
} 

虽然基本相同NSView,当我在动画中使用这个类,动画不再做什么它应该是 - 我的设置框架子视图几乎被忽略,整个ef功能很难看。如果我注释掉我的子类的drawRect:方法,事情就会恢复正常。任何人都可以解释发生了什么问题?为什么存在drawRect:干扰动画?

我在我的GitHub页面上放了一个demo project

回答

5

你已经在这里打破了一些规则,当你违反规则时,行为变得不确定。

在支持层的视图中,您不能直接修改图层。查看文档wantsLayer(这是你如何指定它的层支持):

在层支持的视图,通过视图做任何绘图缓存到底层对象。然后可以以比显式重绘视图内容更高性能的方式来操纵该缓存的内容。 AppKit自动创建底层对象(使用makeBackingLayer方法)并处理视图内容的缓存。 如果wantsUpdateLayer方法返回NO,则不应直接与底层对象交互。相反,请使用此类的方法对视图及其图层进行任何更改。如果wantsUpdateLayer返回YES,则可以在视图的updateLayer方法中修改图层,这是可以接受的(适当的)。

你做这样的判断:

subview.layer?.backgroundColor = color.CGColor 

这是 “直接交互[和]与底层的对象。”你不能这样做。当没有drawRect时,AppKit会跳过试图重画视图,只是使用核心动画来激活那里的内容,这会给你你所期望的(你在那里很幸运;不承诺这会起作用)。

但是当它看到你实际上实施了drawRect(它知道你做了,但它不知道里面是什么),那么它必须调用它来执行自定义绘图。确保drawRect填充矩形的每个像素是您的责任。你不能依赖后援层来为你做(这只是一个缓存)。你什么也没画,所以你看到的是默认的背景灰与缓存的颜色混合在一起。没有任何承诺,一旦我们走下了这条道路,所有的像素都会正确更新。

如果要操纵图层,则需要“图层托管视图”而不是“图层支持的视图”。您可以通过用您自己的自定义图层替换AppKit的缓存层来实现。

let subview = showMeTheProblem ? PathComponentView() : NSView() 
addSubview(subview) 
subview.layer = CALayer() // Use our layer, not AppKit's caching layer. 
subview.layer?.backgroundColor = color.CGColor 

虽然它可能是在这种情况下,不要紧,请记住,一个层支持的视图和一个层托管视图具有不同的性能特征。在分层视图中,AppKit将您的drawRect结果缓存到其缓存层,然后相当自动地应用动画(这允许在CALayer之前编写的现有AppKit代码获得一些很好的选择性入门性能改进,而不会有太多变化) 。在分层托管视图中,系统更像iOS。你没有得到任何神奇的缓存。只有一层,你可以使用Core Animation。

+0

感谢您提供这样一个详细,知识丰富的答案。据了解,我删除了直接操作该图层的任何代码。实际上,一旦我完成了这个工作,我仍然遇到问题,但被告知这个问题与我处理图层有关,我回头看了一下我用作模板的项目(''DMPathControl'' )。我注意到,* DM *将类似视图的''layerContentsRedrawPolicy'设置为''.OnSetNeedsDisplay''(默认为'DuringViewResize''),一旦我改变了这些事情,就像预期的那样开始工作。 –

相关问题