开始使用
准备环境,把 Viva 加入 Go 模块,打开第一个窗口。
环境要求
- Go 1.26 或更新版本。
- macOS: Xcode 命令行工具。Viva 通过 cgo 调用 Cocoa 和 Metal。
- Linux: X11,以及系统自带的 XCB 和 Vulkan 加载库。Viva 在运行时加载它们,自身不捆绑任何一个。
- Windows: Win32,以及系统自带的 Direct3D 11 和 DirectWrite 库。
把 Viva 加入项目
Viva 的模块路径是 github.com/vivaui/viva:
mkdir hello && cd hello
go mod init example.com/hello
go get github.com/vivaui/viva
go get 不带版本号时取最新的正式版本,目前就是 v0.1.2。要固定版本就写明:go get github.com/vivaui/viva@v0.1.2。Viva 还没有到 1.0,所以小版本之间 go.mod 的 API 仍可能变化;升级前看一眼发版说明。
如果你是在 Viva 仓库里改框架本身、而不是使用它,改用 replace 指向检出目录:
go mod edit -require=github.com/vivaui/viva@v0.0.0 -replace=github.com/vivaui/viva=../viva
第一个窗口
package main
import (
"fmt"
"log"
"github.com/vivaui/viva/app"
"github.com/vivaui/viva/flex"
"github.com/vivaui/viva/ui"
)
// Identities are names in a tree, not numbers: the application declares the
// tree once and every control it paints is a name inside a feature of it.
var (
tree = ui.Tree{}
page = tree.Feature("hello")
click = tree.ID(page, "click")
)
type model struct {
clicks int
view flex.View
}
// newConfig describes the window. Keeping it in a function lets a test drive
// the same application without opening anything.
func newConfig(m *model) app.Config {
theme := ui.LightTheme()
config := app.Config{Tree: &tree, Title: "Hello", Width: 480, Height: 240}
config.Paint = func(canvas *ui.Canvas, size ui.Size) {
bounds := ui.Rect{Width: size.Width, Height: size.Height}
canvas.Fill(bounds, theme.Background)
m.view.Draw(canvas, theme, bounds, func(f *flex.Frame) {
f.Column().Fill().Pad(24).Gap(12).Children(func() {
// A button is handled where it is declared: Clicked is true for the
// one paint that delivers its click, and only then may state change.
if f.Button(click, fmt.Sprintf("Clicked %d times", m.clicks)).Clicked() {
m.clicks++
}
})
})
}
return config
}
func main() {
var canvas ui.Canvas
if err := app.RunCanvas(newConfig(&model{}), &canvas); err != nil {
log.Fatal(err)
}
}
用 go run . 运行。这个程序就是整个编程模型的缩影:
newConfig描述窗口。把它放进一个函数,测试就可以在不打开任何窗口的情况下驱动同一个应用。Paint根据你自己的状态(这里是clicks计数)描述界面。Viva 不保存这份状态的副本。flex.View根据描述来布局页面:一个带内边距的列,里面放一个按钮。不写任何坐标,所以标签变长或窗口改变大小时页面依然正常。按钮有稳定的标识click,是树中hellofeature 下的一个名字。- 一次点击完成时,运行时会多画一遍,
Clicked()只在这一遍里、且只对被点击的按钮为真;你的代码就在按钮旁边修改自己的状态,窗口随后重绘一次。其他所有绘制都是只读的。
除此之外什么都不会运行。你不点击时,应用不做布局、不向 GPU 提交任何东西,也没有被唤醒的定时器。
试试演示程序
如果你检出了 Viva 仓库,可以直接在里面看这些演示(它们不在别人安装的模块里运行):
go run ./cmd/showcase # 原生组件展示
go run ./cmd/viva list # viva add 可以复制进项目的组件
go run ./cmd/component-preview -component button -example variants
同样的组件也能在浏览器里运行。组件目录提供可交互的 WebAssembly 预览、每个示例的 Go 源码,以及运行它的原生命令。