【问题标题】:Mavericks issue: flickering when replacing subviews小牛问题:替换子视图时闪烁
【发布时间】:2014-01-06 22:40:56
【问题描述】:

在我的应用中,有一些区域我想为视图设置动画。但是,我不想让视图 layer-backed 。因此,我创建了第二个视图(我们称之为动画视图),它承载了一个层,然后我对其进行动画处理。当然,为了让动画视图看起来像实际视图,我首先将视图渲染为图像,然后将其设置为动画视图根层的内容。完成所有这些后,我将视图替换为动画视图。在这一点上,我可以使用 CALayer 动画的所有功能,而无需支持实际的视图层。这是我一直在描述的代码(我会在一分钟内解决我的问题):

// Creating an animationView
NSView* animationView = [[NSView alloc] initWithFrame: self.bounds];
animationView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
animationView.layer = [CALayer layer];
[animationView setWantsLayer: YES];

// Snapshotting the actual view
NSBitmapImageRep* imageRep = [view bitmapImageRepForCachingDisplayInRect: view.bounds];
[view cacheDisplayInRect: view.bounds toBitmapImageRep: imageRep];
NSImage* image = [[NSImage alloc] initWithSize: [imageRep size]];

[image addRepresentation: imageRep];

// Replacing the view with animationView
NSDisableScreenUpdates();

[CATransaction begin];
[CATransaction setDisableActions:YES];
layer.contents = image;
[CATransaction commit];

[self replaceSubview: view with: animationView];

NSEnableScreenUpdates();

// Animate animationView
// ...

这在 10.8 上完美运行,并且在 10.9 上的动画也播放得很好,但是在 10.9 上,替换视图时只有可见的闪烁。即使在使用 NS[Disable|Enable]ScreenUpdates 之后,我也遇到了这个问题。我还尝试在// Animate animationView 之后删除整个动画代码,这样就不会播放动画,并且我确保闪烁不是来自动画,而是实际上来自替换视图的动作。闪烁仍然存在。我真的不明白为什么操作系统版本之间存在差异......为什么会发生这种情况?

【问题讨论】:

    标签: objective-c cocoa animation calayer osx-mavericks


    【解决方案1】:

    听起来小牛队有些疯狂。你试过了吗:

    [self.window disableFlushWindow];
    [self replaceSubview: view with: animationView];
    [self.window enableFlushWindow];
    

    另外,我注意到您在这里替换了子视图“视图”,但您正在用“自我”的内容替换“视图”。什么是“观点”?

    另外,您不需要同时调用两者:

    animationView.layer = [CALayer layer];
    [animationView setWantsLayer: YES];
    

    另外,只需调用:

    [CATransaction setDisableActions:YES];
    

    【讨论】:

    • 不,我还没有尝试过,但我会的,谢谢你的建议。我稍后会告诉你它是怎么回事。对自我/观点的混乱感到抱歉,我的错误:我有自我的地方实际上是有观点的。另外,感谢有关 CATransaction 的提示!从文档中错过了。
    • 另外,关于setWantsLayer 方法调用,文档指出:To create a layer-hosting view, you must call setLayer: and supply your layer object before you call the setWantsLayer: method; the order of these method calls is crucial. 我认为这意味着需要按特定顺序调用这两种方法。你是说我只需拨打setLayer
    • 对,但是如果你只是要将它设置为一个通用的 CALayer,你最好只调用“animationView.wantsLayer = YES”并让 AppKit 机器创建一个自定义层为你。这些文档适用于您想要使用自定义图层子类(如 CATiledLayer)时。
    • 啊啊啊,我明白了!这是有道理的,是的。感谢您澄清这一点!
    【解决方案2】:

    请尝试替换主队列中的子视图(在这种情况下使用 GCD 和块)。这可能会解决您的问题。

    dispatch_sync(dispatch_get_main_queue(), ^{
        // Your action here
    });
    

    【讨论】:

    • 整个代码在主线程上运行(点击按钮时运行),所以这不是问题的根源。
    • 好的,将尝试重现此问题并很快回来:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多