如何使用 EventChannels 将颜色选择从原生 macOS 颜色选择器流式传输到 Flutter?
How can I stream the selection of colors from the native macOS color picker to Flutter using EventChannels?
我正在尝试向 macos_ui 添加一项功能,允许用户启动本机 macOS 颜色选择器并通过 EventChannel
流回他们的颜色选择。
我可以启动选择器(Cocoa 的 NSColorPanel
),但颜色选择没有流回。当我通过 XCode 运行 示例应用程序时,我可以看到颜色选择已注册,但它们似乎没有通过 EventChannel
流回 Flutter。处理这个问题的正确方法是什么?考虑到这些事件发生在本机 macOS 视图中,甚至可以将这些事件流式传输回 Flutter 吗?
这是我目前的 Swift 代码:
MacosUIPlugin.swift
import Cocoa
import FlutterMacOS
public class MacOSUiPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
private let colorPanelProvider: ColorPanelProvider
private var eventSink: FlutterEventSink?
init(colorPanelProvider: ColorPanelProvider) {
self.colorPanelProvider = colorPanelProvider
super.init()
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "dev.groovinchip.macos_ui",
binaryMessenger: registrar.messenger)
let colorSelectionChannel = FlutterEventChannel(
name: "dev.groovinchip.macos_ui/color_panel",
binaryMessenger: registrar.messenger)
let colorPanelProvider = ColorPanelProvider()
let instance = MacOSUiPlugin(colorPanelProvider: colorPanelProvider)
colorSelectionChannel.setStreamHandler(instance)
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "color_panel":
colorPanelProvider.openPanel()
result(true)
default:
result(FlutterMethodNotImplemented)
}
}
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("listening to MacosUIPluginEvents")
eventSink = events
//colorPanelProvider.startStream()
return nil
}
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
}
extension NSColor {
var hexString: String {
let red = Int(round(self.redComponent * 0xFF))
let green = Int(round(self.greenComponent * 0xFF))
let blue = Int(round(self.blueComponent * 0xFF))
let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
return hexString as String
}
}
ColorPanelProvider.swift
import FlutterMacOS
class ColorPanelProvider: NSObject, FlutterStreamHandler {
var eventSink: FlutterEventSink?
let colorPanel = NSColorPanel.shared
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("listening to ColorPanelProvider events")
eventSink = events
return nil
}
func openPanel() {
colorPanel.setTarget(self)
colorPanel.setAction(#selector(startStream))
colorPanel.makeKeyAndOrderFront(self)
colorPanel.isContinuous = true
startStream()
}
@objc private func currentColor() -> String {
print("currentColor: \(colorPanel.color.asFlutterHexString)")
return colorPanel.color.asFlutterHexString
}
@objc public func startStream() {
print("starting ColorPanelProvider stream")
NotificationCenter.default.addObserver(
self,
selector: #selector(currentColor),
name: NSColorPanel.colorDidChangeNotification,
object: colorPanel)
eventSink?(currentColor())
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
}
extension NSColor {
var asFlutterHexString: String {
let red = Int(round(self.redComponent * 0xFF))
let green = Int(round(self.greenComponent * 0xFF))
let blue = Int(round(self.blueComponent * 0xFF))
let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
return hexString.replacingOccurrences(of: "#", with: "0xFF") as String
}
}
您一直在正确的轨道上,但有一些事情需要修正。有三件事:
- 在
MacosUIPlugin.swift
中,您需要在 register
函数中收听 colorChannelProvider
而不是 instance
。所以你需要更改以下行
colorSelectionChannel.setStreamHandler(instance)
对此:
colorSelectionChannel.setStreamHandler(colorChannelProvider)
- 在
ColorPanelProvider.swift
中,您可以听到 startStream
中的颜色变化。虽然这是执行此操作的正确方法,但您必须提交发送这些更改的 colorPanel
,以便函数可以使用 colorPanel.color
访问颜色。函数签名应如下所示:
@objc public func startStream(colorPanel: NSColorPanel)
- 当您将
startStream
方法注册为从 openPanel()
中的 colorPanel
接收更新的目标时,您需要对其进行设置,以便正确调用它。因此,将方法的第二行更改为如下所示,并且一切正常:
colorPanel.setAction(#selector(startStream(colorPanel:)))
希望这会解决所有问题。如果还有问题,请告诉我。
我正在尝试向 macos_ui 添加一项功能,允许用户启动本机 macOS 颜色选择器并通过 EventChannel
流回他们的颜色选择。
我可以启动选择器(Cocoa 的 NSColorPanel
),但颜色选择没有流回。当我通过 XCode 运行 示例应用程序时,我可以看到颜色选择已注册,但它们似乎没有通过 EventChannel
流回 Flutter。处理这个问题的正确方法是什么?考虑到这些事件发生在本机 macOS 视图中,甚至可以将这些事件流式传输回 Flutter 吗?
这是我目前的 Swift 代码:
MacosUIPlugin.swift
import Cocoa
import FlutterMacOS
public class MacOSUiPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
private let colorPanelProvider: ColorPanelProvider
private var eventSink: FlutterEventSink?
init(colorPanelProvider: ColorPanelProvider) {
self.colorPanelProvider = colorPanelProvider
super.init()
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "dev.groovinchip.macos_ui",
binaryMessenger: registrar.messenger)
let colorSelectionChannel = FlutterEventChannel(
name: "dev.groovinchip.macos_ui/color_panel",
binaryMessenger: registrar.messenger)
let colorPanelProvider = ColorPanelProvider()
let instance = MacOSUiPlugin(colorPanelProvider: colorPanelProvider)
colorSelectionChannel.setStreamHandler(instance)
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "color_panel":
colorPanelProvider.openPanel()
result(true)
default:
result(FlutterMethodNotImplemented)
}
}
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("listening to MacosUIPluginEvents")
eventSink = events
//colorPanelProvider.startStream()
return nil
}
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
}
extension NSColor {
var hexString: String {
let red = Int(round(self.redComponent * 0xFF))
let green = Int(round(self.greenComponent * 0xFF))
let blue = Int(round(self.blueComponent * 0xFF))
let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
return hexString as String
}
}
ColorPanelProvider.swift
import FlutterMacOS
class ColorPanelProvider: NSObject, FlutterStreamHandler {
var eventSink: FlutterEventSink?
let colorPanel = NSColorPanel.shared
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("listening to ColorPanelProvider events")
eventSink = events
return nil
}
func openPanel() {
colorPanel.setTarget(self)
colorPanel.setAction(#selector(startStream))
colorPanel.makeKeyAndOrderFront(self)
colorPanel.isContinuous = true
startStream()
}
@objc private func currentColor() -> String {
print("currentColor: \(colorPanel.color.asFlutterHexString)")
return colorPanel.color.asFlutterHexString
}
@objc public func startStream() {
print("starting ColorPanelProvider stream")
NotificationCenter.default.addObserver(
self,
selector: #selector(currentColor),
name: NSColorPanel.colorDidChangeNotification,
object: colorPanel)
eventSink?(currentColor())
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
}
extension NSColor {
var asFlutterHexString: String {
let red = Int(round(self.redComponent * 0xFF))
let green = Int(round(self.greenComponent * 0xFF))
let blue = Int(round(self.blueComponent * 0xFF))
let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
return hexString.replacingOccurrences(of: "#", with: "0xFF") as String
}
}
您一直在正确的轨道上,但有一些事情需要修正。有三件事:
- 在
MacosUIPlugin.swift
中,您需要在register
函数中收听colorChannelProvider
而不是instance
。所以你需要更改以下行
colorSelectionChannel.setStreamHandler(instance)
对此:
colorSelectionChannel.setStreamHandler(colorChannelProvider)
- 在
ColorPanelProvider.swift
中,您可以听到startStream
中的颜色变化。虽然这是执行此操作的正确方法,但您必须提交发送这些更改的colorPanel
,以便函数可以使用colorPanel.color
访问颜色。函数签名应如下所示:
@objc public func startStream(colorPanel: NSColorPanel)
- 当您将
startStream
方法注册为从openPanel()
中的colorPanel
接收更新的目标时,您需要对其进行设置,以便正确调用它。因此,将方法的第二行更改为如下所示,并且一切正常:
colorPanel.setAction(#selector(startStream(colorPanel:)))
希望这会解决所有问题。如果还有问题,请告诉我。