xcode 如何更改NSSwitch的色彩?

ctzwtxfj  于 2023-03-09  发布在  其他
关注(0)|答案(3)|浏览(251)

NSS交换机现在看起来很苍白:

我正在尝试在iOS上更改色调颜色,如下所示:

但是IB上没有像iOS上那样的色调部分。
所以我在代码中试试运气:

@IBOutlet weak var alwaysConnectedSwitch: NSSwitch!

override func viewWillAppear() {
    super.viewWillAppear()
    self.alwaysConnectedSwitch.layer?.backgroundColor = CGColor.init(gray: 1, alpha: 1)
}

但是self.alwaysConnectedSwitch.layer似乎为零,因此没有设置任何内容。

l5tcr1uw

l5tcr1uw1#

如果你真的需要改变风格,我推荐一个第三方自定义控件,让你自定义外观,因为你的愿望;可以在here中找到一些可行的建议。从10.15开始,NSSwitch根本没有你想要的定制。如果你不关心细节,现在就停止阅读😅
也就是说,剖析NSSwitch的组件是很有趣的。与许多可可控件不同,该控件没有支持NSCell。文档明确指出:
NSSwitch不使用NSCell的示例来提供其功能。cellClass类属性和cell示例属性都返回nil,并且它们忽略设置非nil值的尝试。
因此,它是一个相当现代的控件,由绘制内容的层组成。有3个NSWidgetView是私有的NSView子类。

这些视图大多使用-[NSView updateLayer],根据通过-[NSWidgetView setWidgetDefinition:]提供的内容将所需值绘制到其支持CALayer中。此方法传递定义NSWidgetView应如何绘制到层中的值字典。最后视图的字典示例:

{
    kCUIPresentationStateKey = kCUIPresentationStateInactive;
    kCUIScaleKey = 2;
    kCUIUserInterfaceLayoutDirectionKey = kCUIUserInterfaceLayoutDirectionLeftToRight;
    size = regular;
    state = normal;
    value = 0;
    widget = kCUIWidgetSwitchFill;
}

不幸的是,这意味着样式主要由widget = kCUIWidgetSwitchFill;所示的预定义字符串决定。它涉及到如何根据系统颜色(暗/亮)或高亮颜色绘制填充颜色或禁用颜色。颜色与NSAappearance绑定,并且没有明确的方法来覆盖其中的任何一个。
一个(不推荐,千万不要这样做)解决方案是去掉对NSWidgetView的updateLayer调用,并在您需要的情况下进行您自己的附加层定制。

/// Swizzle out NSWidgetView's updateLayer for our own implementation
class AppDelegate: NSObject, NSApplicationDelegate {

    /// Swizzle out NSWidgetView's updateLayer for our own implementation
    func applicationWillFinishLaunching(_ notification: Notification) {
        let original = Selector("updateLayer")
        let swizzle = Selector("xxx_updateLayer")
        if let widgetClass = NSClassFromString("NSWidgetView"),
            let originalMethod = class_getInstanceMethod(widgetClass, original),
            let swizzleMethod = class_getInstanceMethod(NSView.self, swizzle) {
            method_exchangeImplementations(originalMethod, swizzleMethod)
        }
    }
}

extension NSView {
    @objc func xxx_updateLayer() {
        // This calls the original implementation so all other NSWidgetViews will have the right look
        self.xxx_updateLayer()

        guard let dictionary = self.value(forKey: "widgetDefinition") as? [String: Any],
            let widget = dictionary["widget"] as? String,
            let value = (dictionary["value"] as? NSNumber)?.intValue else {
            return
        }

        // If we're specifically dealing with this case, change the colors and remove the contents which are set in the enabled switch case
        if widget == "kCUIWidgetSwitchFill" {
            layer?.contents = nil;
            if value == 0 {
                layer?.backgroundColor = NSColor.red.cgColor;
            } else {
                layer?.backgroundColor = NSColor.yellow.cgColor;
            }
        }
    }
}

同样,不要这样做!你一定会打破在未来,苹果将拒绝这在应用程序商店提交,你更安全的自定义控件,做正是你想要的,而不与私人API的麻烦。

jtw3ybtb

jtw3ybtb2#

自从引入SwiftUINSHostingView以来,您可以利用SwiftUI ViewsAppKit/UIKit的完美集成。

  • 首先用Toggle@ObservedObject属性创建一个简单的SwiftUI视图,@ObservedObject属性代表视图控制器,你可以指定任何颜色。
struct SwitchView: View {
    @ObservedObject var model : ViewController

    var body: some View {
        Toggle("Switch", isOn: $model.isOn)
            .toggleStyle(.switch)
            .tint(.orange)
    }
}
  • NSViewController中采用ObservableObject,导入SwiftUI,添加@Published属性isOn,为NSView添加IBOutlet,并对NSHostingView进行延迟初始化
import SwiftUI

class ViewController : NSViewController, ObservableObject {

    @IBOutlet weak var switchView: NSView!

    @Published var isOn = false

    lazy var toggleView = NSHostingView(rootView: SwitchView(model: self))
  • 在界面构建器中,在画布中拖动NSView,调整其大小并将其连接到switchView
  • 要将宿主视图附加到IBOutlet,请添加泛型方法attachHostingView并在awakeFromNib中调用它
override func awakeFromNib() {
      super.awakeFromNib()
      attachHostingView(toggleView, to: switchView)
}

fileprivate func attachHostingView<V : View>(_ hostingView: NSHostingView<V>, to superView: NSView) {
    hostingView.translatesAutoresizingMaskIntoConstraints = false
    superView.addSubview(hostingView)
    NSLayoutConstraint.activate([
        hostingView.leadingAnchor.constraint(equalTo: superView.leadingAnchor),
        hostingView.trailingAnchor.constraint(equalTo: superView.trailingAnchor),
        hostingView.topAnchor.constraint(equalTo: superView.topAnchor),
        hostingView.bottomAnchor.constraint(equalTo: superView.bottomAnchor),
    ])
}
  • 当开关改变状态时,有三个选项可用于执行操作:isOndidSet属性观察器、Combine框架或SwiftUI视图中的onChange修饰符调用视图控制器中的自定义方法。

就是这样。尽情享受您选择的浅色切换。

kd3sttzy

kd3sttzy3#

我不太明白你到底面临着什么样的问题,但这对我很有效:

override func viewDidLoad() {
    super.viewDidLoad()

    zzz.layer!.backgroundColor = NSColor.systemRed.cgColor
    zzz.layer!.masksToBounds = true
    zzz.layer!.cornerRadius = 10

这个产量

您可能希望播放/调整其他边框设置,如borderWidth或borderColor

相关问题