【问题标题】:NSScrollView: Override system display settings?NSScrollView:覆盖系统显示设置?
【发布时间】:2016-10-12 01:55:58
【问题描述】:

我有一个 NSScrollView,它被设置为:

MyNSScrollView.hasHorizontalScroller = YES;
MyNSScrollView.hasVerticalScroller = YES;
MyNSScrollView.autohidesScrollers = YES;
MyNSScrollView.scrollerStyle = NSScrollerStyleOverlay;

我注意到,如果没有触控板连接到 OS X,并且默认情况下,NSScrollView 将忽略我在代码中的设置并强制始终显示滚动条:

我只能将我的系统设置更改为“滚动时”或将hasHorizontalScroller等设置为NO以隐藏它,后者将禁用鼠标滚动,这不是结果我要。

如果用户没有触控板,默认情况下(自动基于鼠标或触控板)将始终显示滚动条,即使内容大小不超过帧大小。但是如果你有一个触控板,它将是覆盖样式,无论滚动条是否显示,它都在内容之上。

两者的区别在于“遗留”样式会占用滚动视图中的空间。如果您使用 visiableRect 值进行计算,或者您的内容需要通过约束保持一定的纵横比,这将是一个问题。

有没有办法在不禁用它们的情况下强制隐藏它们?

【问题讨论】:

  • 我建议你阅读你为自己写的东西。 “它会忽略我在程序中的设置并强制它们始终显示”=> 它是什么?你的申请?这些是什么?滚动条?
  • 有 2 个滚动条,水平和垂直,这就是为什么我说它们,因为除了这 2 个条之外我没有提到其他东西。如果听起来不够清晰,我很抱歉。
  • 忽略El Tomato,他最近有点脾气暴躁。
  • 与其忽略用户偏好,为什么不找到一种方法来支持滚动条?
  • 由于不同系统上的滚动条大小可能不同,可能会出现太多不可预知的情况。我正在考虑获取滚动框架并将其大小调整为零宽度/高度。

标签: objective-c macos cocoa nsscrollview nsscroller


【解决方案1】:

您还不清楚在什么情况下会出现什么症状。例如,该首选项窗格中“显示滚动条:”的正常设置是什么?您希望滚动条的行为是什么?总是可见的?只在滚动时显示?

无论如何,我认为问题在于您只是误解了autohidesScrollers 的作用。将其设置为 true 仅意味着当文档视图未超出剪辑视图(也称为内容视图)的边界时隐藏滚动条。那就是如果没有地方可以滚动,因为一切都已经显示出来了。

该属性与滚动条始终可见或仅在滚动或其他任何情况下可见无关。这是您无法以编程方式覆盖的系统设置。在用户会话中的所有应用中,所有滚动条的行为都相同。

【讨论】:

  • 如果用户没有触控板,默认情况下(自动基于鼠标或触控板)将始终显示滚动条,即使内容大小不超过帧大小。但是如果你有一个触控板,它将是覆盖样式,无论滚动条是否显示,它都在内容之上。 2 之间的区别在于“传统”样式将占用滚动视图中的空间。如果您使用 visiableRect 值进行计算,或者您的内容需要通过约束保持一定的纵横比,这将是一个问题。
  • 不,我没有误解autohidesScrollers 的用途。只是在默认的 OS X 设置下,没有触控板的用户将始终拥有滚动条,无论它是否可滚动。这就是我问这个问题的原因,因为我希望它应该“隐藏”不需要的滚动条。只有在代码中禁用滚动条才能在不需要时为仅鼠标用户完全隐藏这些条。
【解决方案2】:

您可以通过使用一些低级的 Objective-C 魔法(方法调配)来强制整个应用使用覆盖滚动条:

#import <Cocoa/Cocoa.h>
#import <objc/runtime.h>

static IMP old_preferredScrollerStyle = NULL;
static NSScrollerStyle new_preferredScrollerStyle(id self, SEL _cmd) {
    // Always prefer overlay style.
    return NSScrollerStyleOverlay;
}

static IMP old_setScrollerStyle = NULL;
static void new_setScrollerStyle(id self, SEL _cmd, NSScrollerStyle style) {
    // Call old implementation but always with overlay style.
    void(*oldImp)(id self, SEL _cmd, NSScrollerStyle style)
        = (void(*)(id, SEL, NSScrollerStyle))old_setScrollerStyle;
    oldImp(self, _cmd, NSScrollerStyleOverlay);
}

/// Force the overlay style scrollers for this app.
@interface NSScrollView (ForceOverlay)
@end

@implementation NSScrollView (ForceOverlay)

+ (void)load
{
    [super load];

    // Replace the preferred style. This sets the style for app startup and new NSScroller
    // and NSScrollView instances.
    Method originalMethod = class_getClassMethod(
        [NSScroller class],
        @selector(preferredScrollerStyle)
    );
    old_preferredScrollerStyle = method_setImplementation(
        originalMethod,
        (IMP)new_preferredScrollerStyle
    );

    // Replace the NSScrollView setter. This prevents the change to the legacy style, for example
    // when the user switches the system setting.
    originalMethod = class_getInstanceMethod(
        [NSScrollView class],
        @selector(setScrollerStyle:)
    );
    old_setScrollerStyle = method_setImplementation(
        originalMethod,
        (IMP)new_setScrollerStyle
    );
}

@end

【讨论】:

  • 根本不需要调酒。只需继承 NSScrollView 并覆盖 scrollerStyle
  • 当然。但是您需要确保 every 滚动视图使用您的子类。根据您项目的规模,这可能是不费吹灰之力或主要问题(例如,如果使用外部组件)。
猜你喜欢
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 1970-01-01
  • 2012-12-07
  • 2013-01-19
  • 1970-01-01
相关资源
最近更新 更多