首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用NSVisualEffectView向后兼容OSX < 10.10?

如何使用NSVisualEffectView向后兼容OSX < 10.10?
EN

Stack Overflow用户
提问于 2014-09-18 14:05:33
回答 3查看 3.8K关注 0票数 13

即将推出的OSX10.10(“约塞米蒂”)提供了一种新的视图,NSVisualEffectView,它支持通过窗口或窗口内的半透明。我对透过窗口的半透明感兴趣,所以我将在这个问题上集中讨论,但它也适用于窗内半透明。

在10.10中使用透窗半透明是微不足道的.只需在视图层次结构中的某个位置放置一个NSVisualEffectView,并将其设置为blendingModeNSVisualEffectBlendingModeBehindWindow。这就够了。

在10.10下,您可以在IB中定义NSVisualEffectView,设置它们的混合模式属性,然后关闭并运行。

然而,如果您想要向后兼容以前的OSX版本,您不能这样做。如果您试图在XIB中包含一个NSVisualEffectView,那么一旦加载XIB,您就会崩溃。

我想要一个“设置它,忘记它”的解决方案,它将提供半透明的运行时,在10.10以下,并简单地降级为一个不透明的视图运行时,在早期的操作系统版本。

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

我认为使用NSProxy对象可能是可能的。我是这么想的:

定义NSView的自定义子类(让我们称之为MyTranslucentView)。在所有init方法(initWithFrame和initWithCoder)中,我会丢弃新创建的对象,而创建具有私有实例变量(myActualView)的NSProxy子类。在初始阶段,它将决定将myActualView对象创建为NSVisualEffectView if OS>=10.10,以及OS<10.10下的普通NSView。

代理将把所有的消息转发给它的myActualView。

这将是相当数量的繁琐,低级别的代码,但我认为它应该能工作。

有人做过这样的事吗?如果是的话,你能给我指出正确的方向或者给我指点吗?

苹果是与约塞米蒂的协议比以前的贝塔更开放。我不认为我是违反了我的Beta谈论这一一般术语,但实际使用NSVisualEffectView的代码可能需要共享在NDA .

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-10-16 14:26:11

有一个非常简单但有点麻烦的解决方案:在应用程序启动时动态创建一个名为NSVisualEffectView的类。然后,您可以加载包含该类的nib,在OSX10.9和更早版本上具有优雅的回退功能。

下面是我的应用程序代表的摘录来说明这个想法:

AppDelegate.m

代码语言:javascript
复制
#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

您必须在OSX10.10SDK上编译它。

它是如何工作的?

当您的应用程序运行在10.9和更早版本时,[NSVisualEffectView class]将为NULL。在这种情况下,下面两行创建了一个NSView的子类,它没有任何方法,也没有ivars,名为NSVisualEffectView

因此,当AppKit现在从nib文件中解压缩NSVisualEffectView时,它将使用新创建的类。该子类的行为将与NSView相同。

,但是为什么不把所有东西都烧起来呢?

当视图被从nib文件中解压缩时,它使用NSKeyedArchiver。它的好处是它忽略了与NSVisualEffectView的属性/ ivars相对应的附加键。

还有什么我需要小心的吗?

  1. 在代码中访问NSVisualEffectView的任何属性(例如material)之前,请确保类响应选择器([view respondsToSelector:@selector(setMaterial:)])。
  2. [[NSVisualEffectView alloc] initWithFrame:]仍然不能工作,因为类名是在编译时解析的。要么使用[[NSClassFromString(@"NSVisualEffectView") alloc] initWithFrame:],要么只分配一个NSView (如果[NSVisualEffectView class]为NULL )。
票数 11
EN

Stack Overflow用户

发布于 2014-10-03 16:42:40

我只是在我的顶层视图中使用这个类别。

如果NSVisualEffects视图是可用的,那么它会在后面插入一个活跃的视图,一切都可以正常工作。

唯一需要注意的是,您有一个额外的子视图,所以如果您稍后要更改视图,您将不得不考虑到这一点。

代码语言:javascript
复制
@implementation NSView (HS)

-(instancetype)insertVibrancyViewBlendingMode:(NSVisualEffectBlendingMode)mode
{
    Class vibrantClass=NSClassFromString(@"NSVisualEffectView");
    if (vibrantClass)
    {
        NSVisualEffectView *vibrant=[[vibrantClass alloc] initWithFrame:self.bounds];
        [vibrant setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
        [vibrant setBlendingMode:mode];
        [self addSubview:vibrant positioned:NSWindowBelow relativeTo:nil];

        return vibrant;
    }

    return nil;
}

@end
票数 3
EN

Stack Overflow用户

发布于 2015-08-11 04:33:17

最后,我得到了@困惑的Vorlon's的变体,但是将子视图移到了视觉效果视图,如下所示:

代码语言:javascript
复制
@implementation NSView (Vibrancy)


- (instancetype) insertVibrancyView
{
    Class vibrantClass = NSClassFromString( @"NSVisualEffectView" );
    if( vibrantClass ) {
        NSVisualEffectView* vibrant = [[vibrantClass alloc] initWithFrame:self.bounds];
        [vibrant setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];

        NSArray* mySubviews = [self.subviews copy];
        for( NSView* aView in mySubviews ) {
            [aView removeFromSuperview];
            [vibrant addSubview:aView];
        }

        [self addSubview:vibrant];

        return vibrant;
    }

    return nil;
}

@end
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25914918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档