如何使用NSVisualEffectView向后兼容OSX< 10.10? [英] How to use NSVisualEffectView backwards-compatible with OSX < 10.10?

查看:102
本文介绍了如何使用NSVisualEffectView向后兼容OSX< 10.10?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

即将面世的OSX 10.10("Yosemite")提供了一种新型的视图NSVisualEffectView,它支持窗口内或窗口内半透明.我对窗口透明性最感兴趣,因此在这个问题中我将重点关注它,但是它也适用于窗口内透明性.

The upcoming OSX 10.10 ("Yosemite") offers a new type of view, NSVisualEffectView, which supports through-the-window or within-the-window translucency. I'm mostly interested in through-the-window translucency, so I'm going to focus on that in this question, but it applies to within-the-window translucency as well.

在10.10中使用窗口透明性是微不足道的.您只需在视图层次结构中的某个位置放置NSVisualEffectView并将其设置为blendingModeNSVisualEffectBlendingModeBehindWindow.这就是全部.

Using through-the-window translucency in 10.10 is trivial. You just place an NSVisualEffectView somewhere in your view hierarchy and set it's blendingMode to NSVisualEffectBlendingModeBehindWindow. That's all it takes.

在10.10以下,您可以在IB中定义NSVisualEffectView,设置其混合模式属性,然后开始运行.

Under 10.10 you can define NSVisualEffectViews in IB, set their blending mode property, and you're off and running.

但是,如果要与早期OSX版本向后兼容,则不能这样做.如果您尝试在XIB中包含NSVisualEffectView,则当您尝试加载XIB时就会崩溃.

However, if you want to be backwards-compatible with earlier OSX versions, you can't do that. If you try to include an NSVisualEffectView in your XIB, you'll crash as soon as you try to load the XIB.

我想要一个设置后忘了"的解决方案,当在10.10下运行时将提供半透明性,而在较早的OS版本上运行时将退化为不透明的视图.

I want a "set it and forget it" solution that will offer translucency when run under 10.10 and simply degrade to an opaque view when run on earlier OS versions.

到目前为止,我要做的是在XIB中使有问题的视图成为普通的NSView,然后添加检查[NSVisualEffectView class] != nil的代码(由awakeFromNib调用),并在定义类时创建NSVisualEffectView的一个实例,将当前视图的所有子视图移到新视图,然后将其安装到位.这行得通,但是每次我需要半透明视图时,都必须编写自定义代码.

What I've done so far is to make the view in question a normal NSView in the XIB, and then add code (called by awakeFromNib) that checks for [NSVisualEffectView class] != nil, and when it's the class is defined, I create an instance of the NSVisualEffectView, move all my current view's subviews to the new view, and install it in place. This works, but it's custom code that I have to write every time I want a translucent view.

我在想使用NSProxy对象是可能的.这就是我的想法:

I'm thinking this might be possible using an NSProxy object. Here's what I'm thinking:

定义NSView的自定义子类(我们称其为MyTranslucentView).在所有init方法(initWithFrame和initWithCoder)中,我将丢弃新创建的对象,而是创建一个具有私有实例变量(myActualView)的NSProxy子类.在初始时间,如果OS> = 10.10,它将决定将myActualView对象创建为NSVisualEffectView,并在OS< 10.10下将其创建为普通NSView.

Define a custom subclass of NSView (let's call it MyTranslucentView). In all the init methods (initWithFrame and initWithCoder) I would throw away the newly created object and instead create a subclass of NSProxy that has a private instance variable (myActualView). At init time it would decide to create the myActualView object as an NSVisualEffectView if OS>=10.10, and a normal NSView under OS<10.10.

代理会将 ALL 邮件转发到myActualView.

The proxy would forward ALL messages to it's myActualView.

这将是相当繁琐的底层代码,但我认为它应该可以工作.

This would be a fair amount of fussy, low-level code, but I think it should work.

有人做过这样的事情吗?如果是这样,您能指出我正确的方向还是给我任何指示?

Has anybody done something like this? If so, can you point me in the right direction or give me any pointers?

与优胜美地a相比,通过与优胜美地a的Beta协议,苹果更为开放.我不认为我是通过一般性的说法来违反我的Beta NDA,但是使用NSVisualEffectView的实际代码可能需要在NDA下共享...

Apple is MUCH more open with the Beta agreement with Yosemite a than with previous Betas. I don't think I'm violating my Beta NDA by talking about this in general terms, but actual code using NSVisualEffectView would probably need to be shared under NDA...

推荐答案

有一个非常简单但有点怪异的解决方案:在应用启动时,只需动态创建一个名为NSVisualEffectView的类即可.然后,您可以加载包含该类的笔尖,并在OS X 10.9和更早版本上进行优美的回退.

There is a really simple, but somewhat hacky solution: Just dynamically create a class named NSVisualEffectView when your app starts. Then you can load nibs containing the class, with graceful fallback on OS X 10.9 and earlier.

以下是我的应用程序委托的摘要,以说明这个想法:

Here's an extract of my app delegate to illustrate the idea:

AppDelegate.m

#import "AppDelegate.h"
#import <objc/runtime.h>

@implementation PGEApplicationDelegate
-(void)applicationWillFinishLaunching:(NSNotification *)notification {
    if (![NSVisualEffectView class]) {
        Class NSVisualEffectViewClass = objc_allocateClassPair([NSView class], "NSVisualEffectView", 0);
        objc_registerClassPair(NSVisualEffectViewClass);
    }
}
@end

您必须根据OS X 10.10 SDK进行编译.

You have to compile this against the OS X 10.10 SDK.

它如何工作?

当您的应用程序在10.9和更早版本上运行时,[NSVisualEffectView class]将为NULL.在这种情况下,以下两行将创建名称为NSVisualEffectViewNSView子类,该子类没有方法且没有ivars.

When your app runs on 10.9 and earlier, [NSVisualEffectView class] will be NULL. In that case, the following two lines create a subclass of NSView with no methods and no ivars, with the name NSVisualEffectView.

因此,当AppKit现在从nib文件取消归档NSVisualEffectView时,它将使用您新创建的类.该子类的行为与NSView相同.

So when AppKit now unarchives a NSVisualEffectView from a nib file, it will use your newly created class. That subclass will behave identically to an NSView.

但是,为什么所有的一切都不如火如荼?

从nib文件取消存档视图时,将使用NSKeyedArchiver.有趣的是,它只是忽略了与NSVisualEffectView的属性/ivars相对应的其他键.

When the view is unarchived from the nib file, it uses NSKeyedArchiver. The nice thing about it is that it simply ignores additional keys that correspond to properties / ivars of NSVisualEffectView.

我还有其他需要注意的地方吗?

  1. 在代码中访问NSVisualEffectView的任何属性(例如material)之前,请确保该类响应选择器([view respondsToSelector:@selector(setMaterial:)])
  2. [[NSVisualEffectView alloc] initWithFrame:]仍然无法正常工作,因为在编译时已解析了类名.使用[[NSClassFromString(@"NSVisualEffectView") alloc] initWithFrame:],或者如果[NSVisualEffectView class]为NULL,则仅分配NSView.
  1. Before you access any properties of NSVisualEffectView in code (eg material), make sure that the class responds to the selector ([view respondsToSelector:@selector(setMaterial:)])
  2. [[NSVisualEffectView alloc] initWithFrame:] still wont work because the class name is resolved at compile time. Either use [[NSClassFromString(@"NSVisualEffectView") alloc] initWithFrame:], or just allocate an NSView if [NSVisualEffectView class] is NULL.

这篇关于如何使用NSVisualEffectView向后兼容OSX&lt; 10.10?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆