8

在 macOS 11 中,Apple 引入了一个新的 NSToolbarItem NSSearchToolbarItem,当焦点切换到工具栏项时,它会自动调整大小以适应打字。

在此处输入图像描述 在此处输入图像描述

Apple 在这里表示这与旧版本的 macOS 向后兼容:https ://developer.apple.com/wwdc20/10104 (11:50 分钟)

但是,NSSearchToolbarItem在 macOS 10.13 (High Sierra) 上使用 from interface builder 启动我的应用程序时,我的应用程序会因以下应用程序特定信息而崩溃:

*** 由于未捕获的异常“NSInvalidUnarchiveOperationException”而终止应用程序,原因:“*** -[NSKeyedUnarchiver decodeObjectForKey:]:无法为键(NS.objects)解码类(NSSearchToolbarItem)的对象;该类可以在源代码或未链接的库中定义,以 NSException 类型的未捕获异常终止

在 10.15 上启动它可以正常工作。我还不能测试 10.14。

Thomas Tempelmann 于 7 月 6 日更新

事实证明,这是旧 Xcode 12 版本的错误,现在已在 Xcode 12.5.1 中修复。

我打开了一个赏金,因为在 High Sierra 上运行时,工具栏内的 NSSegmentedControls 的大小不正确有一个看似相关的问题,但事实证明这是一个单独的问题(可以通过手动重置工具栏minSizemaxSize控制的frame.size)。

因此,解决方案是使用 Xcode 12.5.1 或更高版本。

4

2 回答 2

2

在没有任何代码的情况下在情节提要中添加项目可以正常工作,我刚刚测试过。所以可能你在代码中做错了什么。或者它已在最新的 XCode 中修复。

到目前为止,我发现这只适用于 Catalina,即使在 Mojave 上也会崩溃。根据@ThomasTempelmann 的说法,它在 XCode 12.5.1 中更好,但我还没有测试过。

于 2020-12-26T18:23:57.590 回答
1

有两种方法可以解决这个问题:

1. 使用 Xcode 12.5.1 或更高版本

使用 Xcode 12.5.1 或更高版本构建应用程序,这似乎已修复与 10.14 之前系统的兼容性。

2.添加NSSearchToolbarItemin代码

如果您希望仍然能够使用旧 Xcode 版本(即 Xcode 11 和更早版本)打开项目,则不能将新的 NSSearchToolbarItem 放入情节提要中,否则旧 Xcode 版本将拒绝打开它。

在这种情况下,您将继续使用NSToolbarItem带有NSSearchField控件的经典版本。NSSearchToolbarItem挑战是在运行 macOS 11 或更高版本时将其替换为。

我尝试了几种方法,例如从工具栏中显式删除经典搜索工具栏项目,然后添加新的,并实现委托功能来提供它。虽然这样可行,但在让用户自定义工具栏时会引起麻烦:然后对话框将继续显示旧的搜索项和新的搜索项。解决这个问题的唯一方法是访问私有函数(_setAllowedItems_setDefaultItems),但我对此并不满意。

我终于找到了这个相当的解决方案:

  1. 创建一个新的自定义类,我们将其命名为SmartSearchToolbarItem,并使其成为NSToolbarItem.
  2. 在情节提要中,将 Search Field 的类从 更改NSToolbarItemSmartSearchToolbarItem
  3. 将以下代码添加到SmartSearchToolbarItem实现中:
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 101600
@interface NSSearchToolbarItem : NSObject
- (instancetype)initWithItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier;
@end
#endif

@implementation SmartSearchToolbarItem

-(instancetype)initWithItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier
{
    self = [super initWithItemIdentifier:itemIdentifier];   // this is necessary even if we won't use it, or we'll crash in Big Sur
    Class cls = NSClassFromString(@"NSSearchToolbarItem");
    if (cls) {
        self = (id) [[cls alloc] initWithItemIdentifier:itemIdentifier];
    }
    return self;
}

这不仅会自动将经典搜索项替换为 Big Sur 中的新搜索项,以后还会使用连接的 IBActions 和 IBOutlets,这是我不太了解的部分。因此,无需在代码中复制和属性。

修复分段控件

如果您的工具栏中碰巧有分段控件,那么您还需要此代码来调整它们的大小作为位置,因为它们在 Big Sur 与早期的 macOS 系统上具有不同的宽度(10.15 和 10.14 会很好,但如果你也支持 10.13,你肯定需要这个):

- (void)fixSegmentedToolbarItemWidths // call this from `viewWillAppear`
{
    if (@available(macOS 10.14, *)) {
        // no need to set the sizes here
    } else {
        BOOL didChange = NO;
        for (NSToolbarItem *item in self.view.window.toolbar.items) {
            NSControl *control = (NSControl*)item.view;
            if ([control isKindOfClass:NSSegmentedControl.class]) {
                [control sizeToFit];
                NSRect frame = control.frame;
                const int padding = 2;
                item.minSize = NSMakeSize(frame.size.width+padding, item.minSize.height);
                item.maxSize = item.minSize;
                didChange = YES;
            }
        }
        if (didChange) {
            [self.view.window.toolbar validateVisibleItems];
        }
    }
}

示例代码

Github页面

于 2021-07-06T15:16:47.440 回答