Electron 自定义托盘实战——桌面计算器

Electron 默认的托盘(Tray)提供了菜单能力,但是并不能让用户自定义窗口视图,有很大的局限性。我们经常看到 Mac 上很多原生应用,点击托盘之后可以弹出下拉窗口,那 Electron 能不能实现这个呢?其实是可以的,今天就带领大家一起实现一个「桌面计算器」。

首先,我们需要写一个无边框的 BrowserWindow 来加载计算器界面:

let win, tray
function createTrayWindow() {const width = 300const height = 420win = new BrowserWindow({width,height,frame: false,resizable: false,show: false,movable: false,minimizable: false,maximizable: false,})win.loadFile(path.join(__dirname, '../renderer/calculator.html'))
} 

注意这里 BrowserWindow 默认设置为不显示(show: false),只有当用户点击托盘图标的时候,才展示这个窗口。

这里的难点在于:托盘的位置是不固定的,要让窗口刚好显示在托盘图标的下方,那么每次点击托盘的时候,要实时计算一下托盘的位置。好在 Tray 有个 API 可以获取到图标的位置:

tray.getBounds() // 返回 { x, y, width, height } 

该方法会返回一个矩形(Rectangle)对象,包含以下信息:

  • x:托盘的 x 坐标
  • y:托盘的 y 坐标
  • width:托盘的宽度
  • height:托盘的高度

接下来,我们创建一个托盘,并为其绑定 click 事件:

const tray = new Tray(path.join(__dirname, 'calculatorTemplate.png'))
tray.on('click', () => {const trayBounds = tray.getBounds()win.setPosition(trayBounds.x + trayBounds.width / 2 - width / 2, trayBounds.height)if (win.isVisible()) {win.hide()} else {win.show()}
}) 

创建 Tray 实例的时候,需要提供一个 image 参数,可以是本地图片的绝对路径,也可以是 NativeImage 的实例。关于 NativeImage 类后面会详细讲,本节先用普通图片文件来创建托盘。在 macOS 下,设置托盘的图片名称必须以 Template 结尾,一般需要提供 16x16(72dpi) 和 32x32@2x(144dpi) 的两个图片,例如:

需要特别注意的是:模板图像必须由黑色和透明通道组成。使用模板图像作为菜单栏图标的好处是,它可以适应浅色和深色菜单栏。在 Windows 系统上则不需要按照这种命名规则了,建议在 Windows 上使用 ico 格式的图片,视觉效果会更好一点。

上面最关键的代码在于这一行,用于控制托盘出现的位置:

win.setPosition(trayBounds.x + trayBounds.width / 2 - width / 2 , trayBounds.height) 

由于 BrowserWindow 的宽高已经固定下来了,如果要让窗口正好位于托盘图标的中间正下方,就要算好偏移量,窗口的坐标计算逻辑为:

  • x 坐标:托盘中心位置的 x 坐标减去窗口的宽度
  • y 坐标:托盘底部的 y 坐标(即托盘高度)

这样基础的效果就出来了:

不过此时窗口的显示和隐藏完全由托盘的点击事件控制,当用户切换到其他应用时,表现效果和普通的 BrowserWindow 一样,层级在当前聚焦的应用下方:

但托盘窗口更好的交互是:当窗口失去焦点的时候,自动隐藏。这也很简单,只要为窗口增加 blur 事件即可:

win.on('blur', () => {win.hide()
}) 

这样程序就丝滑多了:

不过还有一个不容易发觉的不完美的地方:Mac 是支持多桌面的,用户可以通过四指左右滑动的方式左右切换桌面:

你会发现上面的计算器窗口在切换桌面之后不见了,计算器窗口只会出现在首次展示的桌面上,在其他桌面再点托盘图标,会自动切回第一个桌面,这种体验是很不好的:

不过,要修复这个问题也非常简单啦,只需要一行代码即可:

win.setVisibleOnAllWorkspaces(true) 

对,就是字面意思:在所有工作空间上都展示。最后在打包的时候还有一点需要注意:一般的纯托盘应用,是不带 dock 图标的,打包的时候在 info.plist 里面添加 LSUIElement 配置项可解决这个问题:

<plist version="1.0"><dict><key>LSUIElement</key><integer>1</integer></dict>
</plist> 

具体的添加方法依赖于应用打包方式,以 electron-packager 为例,配置项为:

"mac": {"extendInfo": {"LSBackgroundOnly": 1,"LSUIElement": 1}
} 

留给读者的思考题

上面的代码只适合在 macOS 系统运行,请将其移植到 Windows 系统上。

注意:在 Mac 和 Windows 上,托盘的位置是不一样的,Windows 默认是左下角,但是 Windows 系统上的任务栏的位置是可以让用户自定义的:

位置可以选择上下左右四个:

你要考虑到这四种场景下托盘窗口的显示位置才行,聪明的你是否有思路了呢?不妨在评论区交流!

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

猜你喜欢

转载自blog.csdn.net/qq_53225741/article/details/129597377
今日推荐