你多久没用Mac的TouchBar了?教你如何在这实现GPT跑马灯效果

前言

上面文章提到了我做的Mac客户端Ai Chat – 你问我答。恰好我的开发机子是19款的Macbook Pro (苹果最后一款支持Touch Bar的机器)。你们有多久没用过这个Bar了?本着捣鼓的精神,我研究了如何使用它以及在此实时返回GPT的返回内容,实现了一个跑马灯效果,以下是实现方案,效果如下

output.gif

实现方案

  • 如何返回一个自定义的TouchBar

TouchBar的开发实际上只要遵循苹果App Kit固定的API,可以非常简单的实现你想要的自定义Toubar。

第一步在ViewController 或者 Window下面重写makeTouchBar方法,新建你的TouchBar。

open override func makeTouchBar() -> NSTouchBar? {
let touchBar = NSTouchBar()
touchBar.delegate = self
touchBar.customizationIdentifier = .customBar
touchBar.defaultItemIdentifiers = [.textFieldItem]
return touchBar
}
open override func makeTouchBar() -> NSTouchBar? {





let touchBar = NSTouchBar()





touchBar.delegate = self





touchBar.customizationIdentifier = .customBar




touchBar.defaultItemIdentifiers = [.textFieldItem]




return touchBar



}
open override func makeTouchBar() -> NSTouchBar? { let touchBar = NSTouchBar() touchBar.delegate = self touchBar.customizationIdentifier = .customBar touchBar.defaultItemIdentifiers = [.textFieldItem] return touchBar }

然后重写public func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem?方法,构建你Toubar的UI,代码如下,由于Mac开发与iOS开发本质上没有太大区别,所以布局还是直接用SnapKit即可。

public func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
switch identifier {
case NSTouchBarItem.Identifier.textFieldItem:
let item = NSCustomTouchBarItem(identifier: .textFieldItem)
let textField = NSTextField(labelWithString: "? Say Something")
self.textField = textField
textField.isEditable = false
textField.isBordered = false
textField.textColor = .white
textField.maximumNumberOfLines = 1
textField.backgroundColor = NSColor.clear
textField.alignment = .center
let scrollView = NSScrollView()
scrollView.documentView = textField
scrollView.hasHorizontalRuler = true
self.scrollView = scrollView
item.view = scrollView
scrollView.snp.makeConstraints { make in
make.left.equalTo(item.view.snp.left).offset(0)
make.top.equalTo(item.view.snp.top).offset(0)
make.bottom.equalTo(item.view.snp.bottom).offset(0)
make.right.equalTo(item.view.snp.right).offset(0)
}
textField.snp.makeConstraints { make in
make.left.equalTo(item.view.snp.left).offset(0)
make.top.equalTo(item.view.snp.top).offset(0)
make.bottom.equalTo(item.view.snp.bottom).offset(0)
}
return item
case NSTouchBarItem.Identifier.buttonItem:
let item = NSCustomTouchBarItem(identifier: identifier)
let button = NSButton(title: "Send Message", target: self, action: #selector(sendButtonTapped(_:)))
button.bezelColor = NSColor.systemBlue
item.view = button
return item
default:
return nil
}
}
public func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {





switch identifier {





case NSTouchBarItem.Identifier.textFieldItem:





let item = NSCustomTouchBarItem(identifier: .textFieldItem)




let textField = NSTextField(labelWithString: "? Say Something")




self.textField = textField



textField.isEditable = false



textField.isBordered = false


textField.textColor = .white


textField.maximumNumberOfLines = 1


textField.backgroundColor = NSColor.clear


textField.alignment = .center


let scrollView = NSScrollView()


scrollView.documentView = textField


scrollView.hasHorizontalRuler = true


self.scrollView = scrollView


item.view = scrollView


scrollView.snp.makeConstraints { make in

make.left.equalTo(item.view.snp.left).offset(0)

make.top.equalTo(item.view.snp.top).offset(0)

make.bottom.equalTo(item.view.snp.bottom).offset(0)

make.right.equalTo(item.view.snp.right).offset(0)

}

textField.snp.makeConstraints { make in

make.left.equalTo(item.view.snp.left).offset(0)

make.top.equalTo(item.view.snp.top).offset(0)

make.bottom.equalTo(item.view.snp.bottom).offset(0)

}

return item

case NSTouchBarItem.Identifier.buttonItem:

let item = NSCustomTouchBarItem(identifier: identifier)

let button = NSButton(title: "Send Message", target: self, action: #selector(sendButtonTapped(_:)))

button.bezelColor = NSColor.systemBlue

item.view = button

return item

default:

return nil

}

}
public func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? { switch identifier { case NSTouchBarItem.Identifier.textFieldItem: let item = NSCustomTouchBarItem(identifier: .textFieldItem) let textField = NSTextField(labelWithString: "? Say Something") self.textField = textField textField.isEditable = false textField.isBordered = false textField.textColor = .white textField.maximumNumberOfLines = 1 textField.backgroundColor = NSColor.clear textField.alignment = .center let scrollView = NSScrollView() scrollView.documentView = textField scrollView.hasHorizontalRuler = true self.scrollView = scrollView item.view = scrollView scrollView.snp.makeConstraints { make in make.left.equalTo(item.view.snp.left).offset(0) make.top.equalTo(item.view.snp.top).offset(0) make.bottom.equalTo(item.view.snp.bottom).offset(0) make.right.equalTo(item.view.snp.right).offset(0) } textField.snp.makeConstraints { make in make.left.equalTo(item.view.snp.left).offset(0) make.top.equalTo(item.view.snp.top).offset(0) make.bottom.equalTo(item.view.snp.bottom).offset(0) } return item case NSTouchBarItem.Identifier.buttonItem: let item = NSCustomTouchBarItem(identifier: identifier) let button = NSButton(title: "Send Message", target: self, action: #selector(sendButtonTapped(_:))) button.bezelColor = NSColor.systemBlue item.view = button return item default: return nil } }

同意第一响应

open override var acceptsFirstResponder: Bool {
return true
}
open override var acceptsFirstResponder: Bool {





return true





}
open override var acceptsFirstResponder: Bool { return true }

就这样我们启动Mac应用我们的自定义Toubar就构建好了,默认它会返回一句内容?️ Say Something

  • 如何实现接受GPT流信息,并实现跑马灯效果

– 

Open AI,GPT流式返回我不多赘述,很多文章都有提到Flutter如何实现OpenAi流式返回,我的Mac客户端是Flutter编写,只需要把OpenAi的接口设置为流接口,然后HttpClient使用流的方式返回即可。然后自定义一个插件,从Flutter返回流信息到Mac原生刷新TouchBar。

跑马灯效果其实实现起来和iOS原生是一样的,我是基于一个ScrollView无限长度的Label,然后计算Label的宽 如果大于TouchBar的最大宽度,每次刷新文本时候,自动滚到Label的末尾来做的 代码如下。

从插件更新文本

OpenAiStreamResPlugin.shareInstance.responseStreamText = { [weak flutterViewController] text in
autoreleasepool {
flutterViewController?.addText(text: text)
}
}
OpenAiStreamResPlugin.shareInstance.responseStreamText = { [weak flutterViewController] text in





autoreleasepool {





flutterViewController?.addText(text: text)





}




}
OpenAiStreamResPlugin.shareInstance.responseStreamText = { [weak flutterViewController] text in autoreleasepool { flutterViewController?.addText(text: text) } }

跑马灯效果

func addText(text: String) {
if text.count == 0 {
self.textField?.stringValue = "? Say Something"
self.scrollView?.contentView()?.scroll(NSPoint(x: 0, y: 0))
return
}
var newText = text.trimmingCharacters(in: .whitespacesAndNewlines)
newText = newText.replacingOccurrences(of: "\n", with: "")
self.textField?.stringValue = newText
if let scrollView = self.scrollView {
self.textField?.sizeToFit()
let textF = self.textField!
if textF.frame.size.width > scrollView.frame.size.width {
self.scrollView?.contentView()?.scroll(NSPoint(x: textF.frame.size.width, y: 0))
}
}
}
func addText(text: String) {





if text.count == 0 {





self.textField?.stringValue = "? Say Something"





self.scrollView?.contentView()?.scroll(NSPoint(x: 0, y: 0))




return




}



var newText = text.trimmingCharacters(in: .whitespacesAndNewlines)



newText = newText.replacingOccurrences(of: "\n", with: "")


self.textField?.stringValue = newText


if let scrollView = self.scrollView {


self.textField?.sizeToFit()


let textF = self.textField!


if textF.frame.size.width > scrollView.frame.size.width {


self.scrollView?.contentView()?.scroll(NSPoint(x: textF.frame.size.width, y: 0))


}


}


}
func addText(text: String) { if text.count == 0 { self.textField?.stringValue = "? Say Something" self.scrollView?.contentView()?.scroll(NSPoint(x: 0, y: 0)) return } var newText = text.trimmingCharacters(in: .whitespacesAndNewlines) newText = newText.replacingOccurrences(of: "\n", with: "") self.textField?.stringValue = newText if let scrollView = self.scrollView { self.textField?.sizeToFit() let textF = self.textField! if textF.frame.size.width > scrollView.frame.size.width { self.scrollView?.contentView()?.scroll(NSPoint(x: textF.frame.size.width, y: 0)) } } }

就这样一个支持GPT实现返回信息的跑马灯TouchBar就完成了,是不是很简单?

output.gif

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYRe3uK3' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片