Skip to content

使用原生 UI 的窗口 ​

带有 Content 的窗口接受任何窗口的窗口选项, 例如其大小、StateKey、Frameless 和 Parent,以及菜单、对话框和 其他桌面 API。它没有页面:Page() 为 nil,并且忽略 URL 和 WindowOptions.Page。它的 Go 代码不需要绑定:视图直接调用 它。CapturePage 返回其所显示内容的 PNG。

go
mygo.NewWindow(mygo.WindowOptions{
	Title:    "Notes",
	Width:    900,
	Height:   600,
	StateKey: "main",
	Content:  ui.View(app.view),
})

标题栏 ​

使用 TitleBarStyle: mygo.TitleBarHidden 时,视图在窗口控件下方绘制 标题栏,就像页面通过 --mygo-titlebar-* CSS 变量所做的那样: c.TitleBar() 返回控件占据的空间,全屏时为零;DragWindow 让元素可以 拖动窗口,双击它们会像标题栏那样缩放或最小化:

go
bar := c.TitleBar()
ui.Row(c).Height(max(bar.Height, 32)).Padding(0, bar.Right+12, 0, bar.Left+12).DragWindow().Children(func() {
	ui.Text(c, "Inbox").Bold()
})

在 Frameless 窗口中,DragWindow 让元素移动窗口,双击该元素会 最大化窗口。

如果想由视图在自己想要的位置连窗口控件一起绘制,在隐藏标题栏的基础上 再加 HideWindowButtons: true:系统控件消失,c.TitleBar() 为零, 窗口保留标题栏区域的边缘(包括顶部边缘)用于调整大小。视图自己的按钮 调用 Minimize、Maximize、Unmaximize 和 Close。

缩放 ​

c.SetZoom(z) 缩放窗口的内容,就像浏览器缩放页面:视图在一个尺寸为 原来 1/z 的窗口中布局,再放大 z 倍显示。它不是把窗口的图像放大: 帧以屏幕分辨率乘以 z 绘制,所以文本、图标、矢量、图片及其边缘保持 原生该尺寸下同样的锐利,窗口的边框保持其像素尺寸不变。在缩放因子为 2 的屏幕上以 2 倍缩放,绘制出的帧相当于缩放因子为 4 的屏幕,字形也不 例外;不缩放时,什么都不变。缩放保持生效直到再次设置,范围在 0.25 到 5 之间;c.Zoom() 返回当前值,1 表示未缩放。

go
c.SetZoom(app.zoom) // 125% 就是 1.25,每帧设置或只设一次
width, height := c.Size() // 内容的尺寸:窗口尺寸除以缩放

视图看到的一切都是缩放过的:c.Size()、c.TitleBar()、Bounds 和 所有长度都以内容的 DIP 表示,窗口 DIP 是它们的 z 倍。设置了另一个 缩放值的帧会在显示前按新尺寸重新构建。离开内容的东西按窗口的 DIP 传递:指针命中缩放在其下方显示的内容,输入法在光标处组合文本,辅助 技术在元素显示的位置勾勒元素,上下文菜单和拖拽从指针下开始,webview 接收内容给它的盒子,MaximizeButton 在它显示的位置显示 Windows 的 吸附布局。触控板按手指移动的距离滚动内容;滚轮的每一"行"按未缩放的 距离滚动。窗口控件保持其尺寸:c.TitleBar() 是它们占据的空间(已 缩放),因此避开它们布局的标题栏会一直保持避开。

相比之下,变换的 Scale 是在内容自身的尺寸上缩放所绘制的内容:其 文本以未变换尺寸的位图绘制,再双线性采样(变换), 适合做动画,但缩放窗口时会发虚。

活力效果 ​

窗口的 Vibrancy 在其原生 UI 未绘制背景的地方显示:在 macOS 上如此, 在 Windows 11 22H2 及更高版本上,创建时带活力效果的窗口也如此。 c.Vibrancy() 告知它是否在显示:在其他地方,视图留为透明的部分不会 显示任何材质,所以应在那里绘制背景。根元素默认绘制主题的背景:把它 设为透明,并给需要背景的部分加上背景,就像不透明内容旁边的侧边栏那样:

go
if c.Vibrancy() {
	c.Root().Background(ui.Transparent)
}
ui.Row(c).Fill().AlignItems(ui.Stretch).Children(func() {
	sidebar := ui.Column(c).Width(240)
	if !c.Vibrancy() {
		sidebar.Background(c.Theme().Surface)
	}
	sidebar.Children(func() { app.sidebar(c) }) // 在材质之上
	ui.Column(c).Grow(1).Background(c.Theme().Background).Children(func() { app.content(c) })
})

在不透明背景之上、透明根元素之下的文本保留系统的亚像素抗锯齿 (ClearType);在材质之上则以灰度抗锯齿绘制。examples/vibrancy 在 这样的侧边栏中选择窗口的材质。

覆盖在其他应用之上的 Liquid Glass ​

VibrancyGlass 和 VibrancyGlassClear 用 macOS 26 的 Liquid Glass 填充窗口,系统结合窗口背后的内容来绘制它:其他应用的窗口、桌面。带 CornerRadius 的无边框窗口于是就像一块漂浮在其上的玻璃,适合启动器、 抬头显示或浮动工具栏:

go
hud := mygo.NewWindow(mygo.WindowOptions{
	Frameless:    true,
	Transparent:  true,
	AlwaysOnTop:  true,
	Vibrancy:     mygo.VibrancyGlassClear, // 在 Windows 11 上是亚克力
	CornerRadius: 18,
	Width:        360,
	Height:       64,
	Content:      ui.View(view), // 在 c.Vibrancy() 为真时其根元素透明
})
hud.SetActiveAppearance(true) // 保持在前方应用之上透明(macOS)

glass 插件也绘制 Liquid Glass,在所有平台上, 但结合的是窗口自身绘制的内容:工具栏覆盖在其下滚动的内容上。窗口的 玻璃显示的是应用没有任何窗口绘制的内容,而且只在系统支持的地方:在 macOS 26 之前它是弹出面板或 HUD 材质,在 Windows 11 上是亚克力,在 Linux 上没有,c.Vibrancy() 会告知这一点。

透明玻璃只有在被绘制为活动状态的窗口中才显得透明,即位于前景的应用的 关键窗口;否则系统会把它毛化,就像漂浮在用户所在应用之上的面板那样。 SetActiveAppearance 让窗口保持被绘制为活动状态,它使用一个私有的 AppKit 调用,未来的 macOS 版本可能会取消它,届时窗口将被像其他窗口 一样绘制:上架 Mac App Store 的应用应当不使用它。

关闭 ​

视图可以关闭自己的窗口,通过按钮的点击或其回调。窗口立即消失,无论是 通过 Destroy,还是通过没有被 OnClose 监听器阻止的 Close;视图的 其余部分照常构建,其 Context 仍有主题和窗口的尺寸。帧到此结束:不再 布局或绘制任何东西,其他回调也不会运行。先打开接管的窗口,因为应用会 在其最后一个窗口关闭时退出:

go
if ui.Button(c, "Done").Clicked() {
	app.showMain()
	win.Close()
}

不使用 webview ​

所有窗口都显示原生 UI 的应用不需要 webview:在 Linux 上只需要 GTK 3, 不需要 WebKitGTK;在 Windows 上不需要 WebView2 Runtime。