本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法
go代码展示为Go 1.16 及更高版本, ide为goland2021.2
1.入门
1.1 介绍
基本环境
Fyne 需要存在 3 个基本元素,Go 工具(至少 1.12 版)、一个 C 编译器(用于连接系统图形驱动程序)和一个系统图形驱动程序。说明因您的操作系统而异,请选择下面的相应选项卡以获取安装说明。
请注意,这些步骤只是开发所必需的——您的 Fyne 应用程序不需要为最终用户进行任何设置或依赖安装!
window
- MSYS2 与 MingW-w64 - msys2.org
- Cygwin - cygwin.com
linux
- Debian / Ubuntu:
sudo apt-get install golang gcc libgl1-mesa-dev xorg-dev
- Fedora:
sudo dnf install golang gcc libXcursor-devel libXrandr-devel mesa-libGL-devel libXi-devel libXinerama-devel libXxf86vm-devel
下载安装
使用 Go 模块(Go 1.16 及更高版本需要)时,您需要先设置模块,然后才能使用包。如果您没有使用模块或者您已经初始化了模块,则可以跳过此步骤进行下一步。
#创建项目
cd myapp
go mod init MODULE_NAME
#下载 Fyne
go get fyne.io/fyne/v2
下载运行fyne演示 ( fyne_demo )
go run fyne.io/fyne/v2/cmd/fyne_demo
1.2 hello world
一个简单的应用程序首先使用 app.New() 创建一个应用程序实例,然后使用 app.NewWindow() 打开一个窗口。然后定义一个小部件树,在窗口上使用 SetContent() 将其设置为主要内容。然后通过在窗口上调用 ShowAndRun() 来显示应用程序 UI。
package main
import (
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/widget"
)
func main() {
a := app.New()
w := a.NewWindow("Hello World")
w.SetContent(widget.NewLabel("Hello World!"))
w.ShowAndRun()
}
使用go run .
查看效果
默认深色风格, 如果您更喜欢浅色主题,则只需设置环境变量FYNE_THEME=light
1.3 应用和事件 (RunLoop)
为了使 GUI 应用程序正常工作,它需要运行一个事件(有时称为 runloop)来处理用户交互和绘图事件。在 Fyne 中,这是使用App.Run()
orWindow.ShowAndRun()
函数开始的。必须从main()
函数中设置代码的末尾调用其中之一。
一个应用程序应该只有一个运行循环,因此您应该只Run()
在代码中调用一次。再次调用它会导致错误。
package main
import (
"fmt"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/widget"
)
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Hello")
myWindow.SetContent(widget.NewLabel("Hello"))
myWindow.Show()
myApp.Run()
tidyUp()
}
func tidyUp() {
fmt.Println("Exited")
}
对于桌面运行时,可以通过调用直接退出App.Quit()
应用程序(移动应用程序不支持此功能) - 通常在开发人员代码中不需要。关闭所有窗口后,应用程序也将退出。另请参阅Run()
在应用程序退出之前不会调用之后执行的函数。
1.4 更新内容
代码更新 GUI 的内容
//第一步是将要更新的小部件分配给变量。
clock := widget.NewLabel("")
w.SetContent(clock)
//将标签的内容设置为当前时间 Time.Format
formatted := time.Now().Format("Time: 03:04:05")
clock.SetText(formatted)
后台运行更新 GUI 的内容
大多数应用程序都需要在后台运行进程,例如下载数据或响应事件。为了模拟这一点,我们将扩展上面的代码以每秒运行一次。
与大多数 go 代码一样,我们可以创建一个 goroutine(使用go
关键字)并在那里运行我们的代码。如果我们将文本更新代码移动到一个新函数中,它可以在初始显示以及定期更新的计时器上调用。通过结合 goroutine 和 time.Tick
内部的 for 循环,我们可以每秒更新标签。
go func() {
for range time.Tick(time.Second) {
updateTime(clock)
}
}()
将此代码放在ShowAndRun
或Run
调用之前很重要,因为它们在应用程序关闭之前不会返回。所有这些一起,代码将每秒运行并更新用户界面,创建一个基本的时钟小部件。完整代码如下:
package main
import (
"time"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/widget"
)
func updateTime(clock *widget.Label) {
formatted := time.Now().Format("Time: 03:04:05")
clock.SetText(formatted)
}
func main() {
a := app.New()
w := a.NewWindow("Clock")
clock := widget.NewLabel("")
updateTime(clock)
w.SetContent(clock)
go func() {
for range time.Tick(time.Second) {
updateTime(clock)
}
}()
w.ShowAndRun()
}
1.5 窗口处理
窗口是使用该函数创建的,App.NewWindow()
并且需要使用该Show()
函数显示。辅助方法ShowAndRun()
onfyne.Window
允许您同时显示窗口和运行应用程序。
默认情况下,窗口的大小将通过检查MinSize()
函数来显示其内容(在后面的示例中会详细介绍)。Window.Resize()
您可以通过调用该方法来设置更大的尺寸。传入fyne.Size
其中包含使用设备独立像素的宽度和高度,例如,默认情况下使窗口为正方形,我们可以:
w.Resize(fyne.NewSize(100, 100))
请注意,桌面环境可能具有导致窗口小于请求的限制。移动设备通常会忽略这一点,因为它们仅全屏显示。
如果您希望显示第二个窗口,您只能调用该Show()
函数。 如果您想在应用程序启动时打开多个窗口Window.Show()
,拆分也很有帮助。App.Run()
下面的示例显示了如何在启动时加载两个窗口。
package main
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/widget"
)
func main() {
a := app.New()
w := a.NewWindow("Hello World")
w.SetContent(widget.NewLabel("Hello World!"))
w.Show()
w2 := a.NewWindow("Larger")
w2.SetContent(widget.NewLabel("More content"))
w2.Resize(fyne.NewSize(100, 100))
w2.Show()
a.Run()
}
当两个窗口都关闭时,上述应用程序将退出。如果您的应用程序被安排成一个窗口是主窗口而其他窗口是辅助视图,您可以将一个窗口设置为“主”窗口,以便在该窗口关闭时应用程序退出。为此,请使用 上的SetMaster()
功能Window
。
可以随时创建窗口,我们可以更改上面的代码,使第二个窗口 ( w2
) 的内容是一个打开新窗口的按钮。您还可以从更复杂的工作流程加载窗口,但要小心,因为新窗口通常会出现在当前活动内容之上。
w2.SetContent(widget.NewButton("Open new", func() {
w3 := a.NewWindow("Third")
w3.SetContent(widget.NewLabel("Third"))
w3.Show()
}))
1.6 单元测试
Fyne 的 API 旨在简化测试应用程序。通过将组件逻辑与其渲染定义分离,我们可以加载应用程序而无需实际显示它们并完全测试功能。
我们可以通过扩展我们的Hello World 应用程序来演示单元测试,以包含空间供用户输入他们的名字以迎接问候。我们首先更新用户界面,使其具有两个元素,一个Label
用于问候语,一个Entry
用于名称输入。container.NewVBox
我们使用(一个垂直的盒子容器)显示它们,一个在另一个之上。更新后的用户界面代码如下所示:
func makeUI() (*widget.Label, *widget.Entry) {
return widget.NewLabel("Hello world!"),
widget.NewEntry()
}
func main() {
a := app.New()
w := a.NewWindow("Hello Person")
w.SetContent(container.NewVBox(makeUI()))
w.ShowAndRun()
}
为了测试这个输入行为,我们创建了一个定义函数TestGreeter
的新文件(名称结尾 _test.go
将其标记为测试) 。
package main
import (
"testing"
)
func TestGreeting(t *testing.T) {
}
我们可以添加一个初始测试来验证初始状态,为此我们测试从 makeUI 返回的 Label 的 Text 字段和错误。 将以下代码添加到您的测试方法中:
out, in := makeUI()
if out.Text != "Hello world!" {
t.Error("Incorrect initial greeting")
}
该测试将通过 - 接下来我们添加到测试中以验证欢迎程序。我们使用辅助测试场景的 Fynefyne.io/fyne/v2/test
包,调用test.Type
模拟用户输入。以下测试代码将检查输入用户名时输出是否更新(请务必添加导入):
test.Type(in, "Andy")
if out.Text != "Hello Andy!" {
t.Error("Incorrect user greeting")
}
您可以使用 - 运行所有这些测试go test .
,就像任何其他测试一样。这样做你现在会看到FAIL——因为我们没有添加欢迎逻辑。将函数更新makeUI
为以下代码:
func makeUI() (*widget.Label, *widget.Entry) {
out := widget.NewLabel("Hello world!")
in := widget.NewEntry()
in.OnChanged = func(content string) {
out.SetText("Hello " + content + "!")
}
return out, in
}
这样做你会看到测试通过了。您还可以运行完整的应用程序(使用go run .
)并在字段Entry
中输入名称时查看问候语更新。另请注意,这些测试都在不显示窗口或窃取鼠标的情况下运行 - 这是 Fyne 单元测试设置的另一个好处。
1.7 打包
打包一个用于分发的图形应用程序可能很复杂。值得庆幸的是,“fyne”应用程序有一个“package”命令可以自动处理这个问题。只需指定目标操作系统和任何所需的元数据(例如图标)即可生成相应的包。.icns 或 .ico 的图标转换将自动完成,因此只需提供一个 .png 文件 :)。
go install fyne.io/fyne/v2/cmd/fyne@latest
#macOS
fyne package -os darwin -icon myapp.png
#linux 和 Windows
fyne package -os linux -icon myapp.png
fyne package -os windows -icon myapp.png
1.8 移动端应用打包和分发
首先,您需要安装更多的开发工具来完成移动打包。adb
对于 Android 构建,您必须安装 Android SDK 和 NDK 并设置适当的环境,以便可以在命令行上找到工具(例如)。要构建 iOS 应用程序,您需要在 macOS 计算机上安装 Xcode 以及命令行工具可选包。
fyne package -os android -appID com.example.myapp -icon mobileIcon.png
fyne package -os ios -appID com.example.myapp -icon mobileIcon.png
要在手机或模拟器上安装 android 应用程序,只需调用
adb install myapp.apk
要在iOS模拟器上安装,您可以使用如下命令行工具:
xcrun simctl install booted myapp.app
macOS 应用商店
先决条件:
- 运行 macOS 和 Xcode 的 Apple mac
- 苹果开发者账号
- Mac App Store 应用证书
- Mac App Store 安装程序证书
- App Store 中的 Apple Transporter 应用程序
-
设置您的应用程序/版本,以便在 AppStore Connect上上传构建。
-
打包完成的应用发布:
fyne release -appID com.example.myapp -appVersion 1.0 -appBuild 1 -category games
-
将
.pkg
拖到 Transporter 上,然后点击“交付”。 -
返回 AppStore Connect 网站,选择要发布的版本并提交审核。
谷歌商店(安卓)
先决条件:
- Google Play 管理中心帐户
- 分发密钥库( android 文档中的创建说明)
-
设置您的应用程序/版本,以便在 Google Play 控制台上上传。关闭“播放应用签名”选项,因为我们自己管理它。
-
打包完成的应用发布:
fyne release -os android -appID com.example.myapp -appVersion 1.0 -appBuild 1
- 将
.apk
文件拖入 Play 管理中心应用版本页面的构建放置区 - 开始推出新版本。
1.9 应用元数据
命令的 v2.1.0 版本开始,fyne
我们支持元数据文件,该文件允许您将有关您的应用程序的信息存储在存储库中。此文件是可选的,但有助于避免必须记住每个包和发布命令的特定构建参数。
该文件应该FyneApp.toml
在您运行fyne
命令的目录中命名(这通常是main
包)。该文件的内容如下:
Website = "https://example.com"
[Details]
Icon = "app.png"
Name = "测试元数据app"
ID = "com.example.app"
Version = "1.0.0"
Build = 2
2.0 交叉编译
由于 Linux 系统能够轻松地交叉编译到 macOS 和 Windows,Fyne 开发人员推荐的工具是fyne-cross。它受到xgo的启发,并使用构建在golang-cross映像之上的docker映像,其中包括 Windows 的 MinGW 编译器和 macOS SDK,以及 Fyne 要求。
fyne-cross 允许为以下目标构建二进制文件并创建分发包:
GOOS | GOARCH |
---|---|
darwin | amd64 |
darwin | 386 |
linux | amd64 |
linux | 386 |
linux | arm64 |
linux | arm |
windows | amd64 |
windows | 386 |
android | amd64 |
android | 386 |
android | arm64 |
android | arm |
ios | |
freebsd | amd64 |
freebsd | arm64 |
要求
- go >= 1.13
- docker
安装
go get github.com/fyne-io/fyne-cross
用法
fyne-cross <command> [options]
The commands are:
darwin Build and package a fyne application for the darwin OS
linux Build and package a fyne application for the linux OS
windows Build and package a fyne application for the windows OS
android Build and package a fyne application for the android OS
ios Build and package a fyne application for the iOS OS
freebsd Build and package a fyne application for the freebsd OS
version Print the fyne-cross version information
Use "fyne-cross <command> -help" for more information about a command.
通配符
该arch
标志支持通配符,以防要针对指定 GOOS 的所有支持的 GOARCH 进行编译
fyne-cross windows -arch=*
等同于
fyne-cross windows -arch=amd64,386