Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(上)

Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(上)

本文档基于 5 个真实 Fyne 项目的实际开发代码编写,所有示例代码均来源于实战项目。

参考项目:

  • OnlineExamApp - 在线考试系统
  • FyneCamera - 摄像头调用
  • FyneWebView - WebView 集成
  • FundQuery - 基金查询系统
  • fynewh - Fyne 全组件教学项目

目录

  1. [Fyne 框架介绍](#Fyne 框架介绍 "#1-fyne-%E6%A1%86%E6%9E%B6%E4%BB%8B%E7%BB%8D")
  2. 开发环境搭建
  3. 项目结构组织
  4. [应用程序与窗口 (App & Window)](#应用程序与窗口 (App & Window) "#4-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E4%B8%8E%E7%AA%97%E5%8F%A3-app--window")
  5. [基础控件 (Widget)](#基础控件 (Widget) "#5-%E5%9F%BA%E7%A1%80%E6%8E%A7%E4%BB%B6-widget")
  6. [布局管理 (Layout)](#布局管理 (Layout) "#6-%E5%B8%83%E5%B1%80%E7%AE%A1%E7%90%86-layout")
  7. [容器 (Container)](#容器 (Container) "#7-%E5%AE%B9%E5%99%A8-container")
  8. [Canvas 画布绘图](#Canvas 画布绘图 "#8-canvas-%E7%94%BB%E5%B8%83%E7%BB%98%E5%9B%BE")
  9. [数据绑定 (Data Binding)](#数据绑定 (Data Binding) "#9-%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A-data-binding")
  10. [对话框 (Dialog)](#对话框 (Dialog) "#10-%E5%AF%B9%E8%AF%9D%E6%A1%86-dialog")
  11. [主题与自定义主题 (Theme)](#主题与自定义主题 (Theme) "#11-%E4%B8%BB%E9%A2%98%E4%B8%8E%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%BB%E9%A2%98-theme")
  12. [自定义控件 (Custom Widget)](#自定义控件 (Custom Widget) "#12-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6-custom-widget")
  13. [数据库集成 (SQLite)](#数据库集成 (SQLite) "#13-%E6%95%B0%E6%8D%AE%E5%BA%93%E9%9B%86%E6%88%90-sqlite")
  14. [HTTP 网络请求](#HTTP 网络请求 "#14-http-%E7%BD%91%E7%BB%9C%E8%AF%B7%E6%B1%82")
  15. 文件与系统操作
  16. 系统托盘
  17. 多窗口管理
  18. [移动端适配 (Android)](#移动端适配 (Android) "#18-%E7%A7%BB%E5%8A%A8%E7%AB%AF%E9%80%82%E9%85%8D-android")
  19. [CGO 与原生平台集成](#CGO 与原生平台集成 "#19-cgo-%E4%B8%8E%E5%8E%9F%E7%94%9F%E5%B9%B3%E5%8F%B0%E9%9B%86%E6%88%90")

1. Fyne 框架介绍

Fyne 是 Go 语言的一个跨平台 GUI 工具包,基于 OpenGL 渲染。特点:

  • 跨平台:Windows / macOS / Linux / iOS / Android 全支持
  • 声明式 API:代码简洁直观
  • 内置 Material Design 风格:美观的默认主题
  • 数据绑定支持:实现 UI 与数据分离
  • 可扩展:支持自定义控件、自定义主题、自定义布局
go 复制代码
// Fyne 核心包导入方式
import (
    "fyne.io/fyne/v2"                    // 核心类型定义
    "fyne.io/fyne/v2/app"                 // 应用程序入口
    "fyne.io/fyne/v2/container"           // 容器和布局
    "fyne.io/fyne/v2/widget"              // 标准控件
    "fyne.io/fyne/v2/canvas"              // 画布绘图
    "fyne.io/fyne/v2/theme"               // 主题图标和颜色
    "fyne.io/fyne/v2/layout"              // 独立布局
    "fyne.io/fyne/v2/data/binding"        // 数据绑定
    "fyne.io/fyne/v2/dialog"              // 对话框
    "fyne.io/fyne/v2/driver/desktop"      // 桌面特有功能
    "fyne.io/fyne/v2/driver/mobile"       // 移动端特有功能
    "fyne.io/fyne/v2/storage"             // 文件存储抽象
)

来源:以上导入方式在 5 个项目中均有使用,是标准的 Fyne 项目导入结构。


2. 开发环境搭建

2.1 安装 Fyne

bash 复制代码
# 安装 Fyne 核心库
go get fyne.io/fyne/v2

# 安装 Fyne 命令行工具(用于打包)
go install fyne.io/fyne/v2/cmd/fyne@latest

2.2 Windows 开发环境

以下代码在 Windows 10/11 上可直接运行(需安装 GCC):

go 复制代码
// 来源: fynewh/main.go - init函数中设置环境变量
package main

import "os"

func init() {
    // 设置 Fyne 主题(light 或 dark)
    os.Setenv("FYNE_THEME", "light")

    // 如需自定义字体(解决中文显示问题),设置:
    // os.Setenv("FYNE_FONT", "C:/Windows/Fonts/simkai.ttf")
}

说明init() 函数在包初始化时自动执行。os.Setenv("FYNE_THEME", "light") 设置应用主题为浅色模式。Windows 下如需显示中文,可使用 os.Setenv("FYNE_FONT", "字体路径") 指定支持中文的字体文件。


3. 项目结构组织

3.1 大项目推荐结构(OnlineExamApp 风格)

csharp 复制代码
project/
├── main.go                 # 程序入口
├── mainFrame.go            # 主界面框架
├── login.go                # 登录模块
├── api/                    # API 对接层
│   └── api.go
├── components/             # 自定义控件
│   ├── myButtonCircle.go
│   ├── myHyperlink.go
│   └── myNumberEntry.go
├── config/                 # 配置文件
│   └── config.go
├── model/                  # 数据模型
│   ├── user.go
│   └── ...
├── service/                # 业务逻辑层
│   └── service.go
├── theme/                  # 自定义主题
│   └── themeTtf.go
├── utils/                  # 工具函数
│   ├── sqlite.go
│   └── utils.go
└── sql/                    # SQL 脚本
    └── init.sql

3.2 中小项目结构(FundQuery / FyneCamera 风格)

bash 复制代码
project/
├── main.go                 # 程序入口 + 主界面
├── components/             # 自定义控件(可选)
├── utils/                  # 工具函数(可选)
└── model/                  # 数据模型(可选)

说明:OnlineExamApp 采用 MVC 分层架构,适合大型项目。FundQuery 和 FyneCamera 将逻辑集中在一个或少数几个文件中,适合小型项目。


4. 应用程序与窗口 (App & Window)

4.1 创建最简应用

go 复制代码
// 来源: fynewh/main.go
package main

import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/widget"
)

func main() {
    // 创建应用程序实例 ------ 每个Fyne程序从这里开始
    a := app.New()

    // 创建一个带标题的窗口
    w := a.NewWindow("Hello World")

    // 设置窗口内容为标签控件
    w.SetContent(widget.NewLabel("Hello,World!"))

    // 显示窗口并进入事件循环(阻塞当前协程)
    w.ShowAndRun()
}

说明

  • app.New() --- 创建 Fyne 应用程序实例,这是所有 Fyne 应用的起点。
  • a.NewWindow("标题") --- 创建新窗口,参数为窗口标题。
  • w.SetContent(obj) --- 设置窗口的内容区域,接受任何 fyne.CanvasObject
  • w.ShowAndRun() --- 显示窗口并启动事件循环,等效于 w.Show() + a.Run()

4.2 应用程序与窗口的高级设置

go 复制代码
// 来源: fynewh/main.go
func main() {
    // 创建带 ID 的应用 ------ ID 用于存储持久化偏好设置
    a := app.NewWithID("com.xxx.yyy")

    // 设置全局键值对 ------ 跨页面共享数据
    a.Preferences().SetString("userId", "1")
    a.Preferences().SetString("userName", "李梓诚")
    a.Preferences().SetString("userPassword", "123456789")

    // 自定义主题(详见第11章)
    mytheme := &MyTheme{}
    a.Settings().SetTheme(mytheme)

    // 创建主窗口
    w := a.NewWindow("Hello World")

    // 设置窗口初始大小 ------ 像素为单位
    w.Resize(fyne.Size{Width: 700, Height: 600})

    // 设置窗口是否固定大小 ------ true=固定,false=可调整
    // w.SetFixedSize(true)

    // 设置窗口全屏
    // w.SetFullScreen(true)

    // 添加系统托盘
    addSystemTray(a, w)

    // 为窗口添加键盘事件
    w.Canvas().SetOnTypedKey(func(k *fyne.KeyEvent) {
        // 监听键盘按键
        fmt.Println("退出当前窗口")
    })

    // 设置窗口内容并运行
    w.SetContent(vbox)
    w.ShowAndRun()
}

说明

  • app.NewWithID --- 带应用 ID 创建,ID 用于存储持久化设置(JSON 文件存储,跨启动保持)。
  • a.Preferences() --- 全局键值存储 API,支持 String/Int/Bool/Float 等类型。
  • w.Resize(size) --- 设置窗口初始尺寸,参数类型 fyne.Size{Width, Height}
  • w.Canvas().SetOnTypedKey() --- 注册全局键盘事件回调,接收 *fyne.KeyEvent

4.3 设置与关闭窗口拦截

go 复制代码
// 来源: fynewh/main.go
func setMainWindow(w fyne.Window) {
    // SetCloseIntercept 拦截窗口关闭事件
    // 可以在此实现"最小化到托盘"而不是直接退出
    w.SetCloseIntercept(func() {
        w.Hide()  // 隐藏窗口而非关闭
        // w.Close() // 真要关闭时调用
    })
}

说明SetCloseIntercept 拦截用户点击关闭按钮的行为。常用于实现"关闭窗口时最小化到系统托盘"功能。

4.4 读取全局偏好设置

go 复制代码
// 来源: fynewh/main.go
// 全局取值,可在任何地方通过 a.Preferences() 读取
func readPreferences(a fyne.App) {
    userId := a.Preferences().String("userId")
    userName := a.Preferences().String("userName")
    fmt.Printf("User: %s, ID: %s\n", userName, userId)
}

说明a.Preferences().String(key) 读取之前存储的字符串值。偏好数据自动持久化到磁盘(通常在 $HOME/.fyne/ 目录下)。

4.5 应用生命周期 (Lifecycle)

v2.0+ 引入生命周期 API,允许监听应用的前后台切换和启动/停止事件:

go 复制代码
// 来源: fyne demo v2.8.0 --- main.go
func main() {
    a := app.NewWithID("io.fyne.demo")

    // 应用启动完成后回调
    a.Lifecycle().SetOnStarted(func() {
        fyne.LogError("应用已启动", nil)
    })

    // 应用进入前台时回调(适合恢复暂停的操作)
    a.Lifecycle().SetOnEnteredForeground(func() {
        fyne.LogError("应用进入前台", nil)
    })

    // 应用退到后台时回调(适合暂停耗时操作、保存状态)
    a.Lifecycle().SetOnExitedForeground(func() {
        fyne.LogError("应用退到后台", nil)
    })

    // 应用即将退出时回调(最后一次清理资源的机会)
    a.Lifecycle().SetOnStopped(func() {
        fyne.LogError("应用即将退出", nil)
    })

    w := a.NewWindow("Demo")
    w.ShowAndRun()
}

生命周期顺序

复制代码
启动 → SetOnStarted → SetOnEnteredForeground
切换后台 → SetOnExitedForeground
切回来 → SetOnEnteredForeground
退出 → SetOnExitedForeground → SetOnStopped

4.6 窗口高级特性

go 复制代码
// 来源: fyne v2.8.0 widget/window.go, fyne_demo/advanced.go

// SetMaster --- 标记为主窗口(桌面端:关闭此窗口即退出应用)
w.SetMaster()

// SetOnClosed --- 窗口关闭后回调(v2.5+)
w.SetOnClosed(func() {
    // 所有窗口关闭后执行
    fmt.Println("窗口已关闭")
})

// 获取窗口是否为固定大小
if w.FixedSize() {
    fmt.Println("窗口大小固定")
}

4.7 全局工具函数

go 复制代码
// 来源: fyne demo v2.8.0 --- main.go, welcome.go, advanced.go
import "fyne.io/fyne/v2"

// fyne.Do --- 安全地在 UI 线程执行回调
// 如果当前已在 UI 线程,直接执行;否则排入 UI 事件队列
fyne.Do(func() {
    // 安全地更新 UI 组件
    label.SetText("updated from goroutine")
})

// fyne.LogError --- 记录错误日志(生产环境静默,debug 模式输出)
fyne.LogError("操作失败", err)

// 剪贴板操作
clipboard := fyne.CurrentApp().Driver().AllWindows()[0].Clipboard()
clipboard.SetContent("复制这段文字")       // 设置剪贴板内容
content, _ := clipboard.Content()        // 读取剪贴板内容

// 打开浏览器 URL(桌面端)
url, _ := url.Parse("https://fyne.io/")
fyne.CurrentApp().OpenURL(url)

// 获取应用元数据(v2.8.0)
md := fyne.CurrentApp().Metadata()
fmt.Println("App Name:", md.Name)
fmt.Println("App Version:", md.Version)
fmt.Println("App Build:", md.Build)

4.8 桌面快捷键

go 复制代码
// 来源: fyne demo v2.8.0 --- main.go
import "fyne.io/fyne/v2/driver/desktop"

// 自定义桌面快捷键(跨平台 modifier key)
w.Canvas().AddShortcut(
    &desktop.CustomShortcut{
        KeyName:  fyne.KeyF,
        Modifier: fyne.KeyModifierShortcutDefault, // Windows: Ctrl, macOS: Cmd
    },
    func(shortcut fyne.Shortcut) {
        fmt.Println("快捷键被触发")
    },
)

// 设备类型检测
if fyne.CurrentDevice().IsMobile() {
    // 移动端:调整布局以适配小屏幕
} else if fyne.CurrentDevice().IsBrowser() {
    // WebAssembly 环境
} else {
    // 桌面端
}

fyne.KeyModifierShortcutDefault (v2.4+) 解决了跨平台快捷键修饰键不一致的问题,Windows 自动映射为 Ctrl,macOS 映射为 Cmd。


5. 基础控件 (Widget)

5.1 标签 (Label)

go 复制代码
// 来源: fynewh/main.go
import "fyne.io/fyne/v2/widget"

// 创建简单标签
label := widget.NewLabel("Fyne控件测试")

// 设置自动换行
label.Wrapping = fyne.TextWrapWord

// 绑定数据(详见第9章)
lbl := widget.NewLabelWithData(db) // db 是 binding.String

说明

  • NewLabel(text) --- 创建静态文本标签。
  • .Wrapping --- 设置换行模式:
    • fyne.TextWrapOff --- 不换行(默认)
    • fyne.TextWrapWord --- 按单词边界换行
    • fyne.TextWrapBreak --- 在任意字符处可换行
  • NewLabelWithData(binding) --- 创建数据绑定的标签,文本随数据源自动更新。
  • NewLabelWithStyle(text, alignment, style) --- 创建带对齐和样式的标签(v2.4+):
    • fyne.TextAlignLeading / TextAlignCenter / TextAlignTrailing
    • fyne.TextStyle{Bold: true, Italic: true, Monospace: true}

5.2 按钮 (Button)

go 复制代码
// 来源: fynewh/widgetButton.go
import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/theme"
    "fyne.io/fyne/v2/widget"
)

func HboxButton() *fyne.Container {
    hbox := container.NewHBox()

    // 1. 创建普通按钮 ------ 参数为文字和点击回调
    btn1 := widget.NewButton("button click", func() {
        fmt.Println("button click")
    })
    // 设置按钮重要性样式 ------ HighImportance 为蓝色高亮
    btn1.Importance = widget.HighImportance
    // 设置按钮文字对齐方式
    btn1.Alignment = widget.ButtonAlignCenter
    hbox.Add(btn1)

    // 2. 创建带图标的按钮 ------ 使用内置主题图标
    btn2 := widget.NewButtonWithIcon("btn2", theme.CancelIcon(), func() {
        fmt.Println("btn2 CancelIcon")
    })
    hbox.Add(btn2)

    return hbox
}

说明

  • NewButton("文字", callback) --- 创建按钮,回调是 func() 类型。
  • NewButtonWithIcon("文字", icon, callback) --- 创建带图标的按钮。
  • .Importance --- 按钮重要性样式:
    • widget.LowImportance --- 低重要性(灰色)
    • widget.MediumImportance --- 中等(默认)
    • widget.HighImportance --- 高重要性(蓝色高亮)
  • .Alignment --- 文字对齐:
    • widget.ButtonAlignCenter --- 居中(默认)
    • widget.ButtonAlignLeading --- 左对齐
    • widget.ButtonAlignTrailing --- 右对齐

5.3 输入框 (Entry) 和密码框 (PasswordEntry)

go 复制代码
// 来源: fynewh/widgetEntry.go, fynewh/widgetForm.go
import (
    "fyne.io/fyne/v2/widget"
)

// 普通输入框
input := widget.NewEntry()

// 设置占位提示文字
input.SetPlaceHolder("请输入用户名")

// 密码输入框 ------ 输入内容显示为圆点
passWord := widget.NewPasswordEntry()

// 设置输入框宽度
input.Resize(fyne.NewSize(200, 40))

说明

  • NewEntry() --- 标准单行文本输入框。

  • .SetPlaceHolder("文字") --- 设置占位符提示。

  • NewPasswordEntry() --- 密码输入框,输入字符显示为

  • .Text --- 获取当前输入文本。

  • .OnChanged --- 文本变化回调函数。

  • .OnSubmitted --- 用户按 Enter 键提交时回调(v2.0+)。

  • .Validator --- 设置输入验证函数,返回 nil 表示合法(v2.5+):

    go 复制代码
    entry.Validator = func(s string) error {
        if len(s) < 3 { return fmt.Errorf("至少3个字符") }
        return nil
    }

5.4 多行文本输入框 (MultiLineEntry)

go 复制代码
// 来源: fynewh/demoMainShow.go
import "fyne.io/fyne/v2/widget"

// 创建多行输入框
text := widget.NewMultiLineEntry()

// 禁用手动输入 ------ 只读模式
text.Disable()

// 设置多行文本内容
text.SetText("程序完成:\n" + textInfo)

// 刷新显示
text.Refresh()

说明

  • NewMultiLineEntry() --- 支持多行输入/显示的文本框,自带滚动条。
  • .Disable() --- 禁用编辑,变为只读模式。
  • .SetText(text) --- 设置文本内容。
  • .Refresh() --- 手动刷新渲染。

5.5 下拉选择框 (Select)

go 复制代码
// 来源: fynewh/widgetSelect.go
import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/widget"
)

func HBoxSelect() *fyne.Container {
    lblMsg := widget.NewLabel("")

    // 创建下拉选择框:参数为选项列表和选择回调
    sel := widget.NewSelect([]string{"orange", "red", "blue", "yellow", "black"},
        func(s string) {
            lblMsg.SetText(s) // 选择后将选项文字显示在标签上
        })

    // 设置默认选中第 0 项(索引从 0 开始)
    sel.SetSelectedIndex(0)

    return container.NewHBox(sel, widget.NewSeparator(), lblMsg)
}

说明

  • NewSelect([]string{...}, callback) --- 创建下拉选择框。
  • .SetSelectedIndex(n) --- 设置默认选中项。
  • .Selected --- 获取当前选中项字符串。

5.6 可编辑下拉框 (SelectEntry)

go 复制代码
// 来源: fynewh/widgetSelectEntry.go
import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/widget"
)

func HBoxSelectEntry() *fyne.Container {
    opts := []string{"orange", "red", "blue", "yellow", "black"}

    // 创建可编辑下拉框 ------ 既可以选也可以输入
    selRoot := widget.NewSelectEntry(opts)
    // 按回车后触发
    selRoot.OnSubmitted = func(s string) {
        if s != "" {
            opts = append(opts, s) // 将输入值添加到选项
        }
        selRoot.SetOptions(opts) // 更新选项列表
    }

    // 子选择框 ------ 根据父选择框的选项动态变化
    selChild := widget.NewSelectEntry([]string{})
    selRoot.OnChanged = func(s string) {
        // 根据父级选项切换子级选项
        switch s {
        case "red":
            selChild.SetOptions([]string{"red1", "red2", "red3"})
        case "orange":
            selChild.SetOptions([]string{"orange1", "orange2", "orange3"})
        // ...
        }
    }

    return container.NewHBox(selRoot, widget.NewSeparator(), selChild)
}

说明

  • NewSelectEntry(opts) --- 创建可编辑下拉框,用户可以输入自定义值。
  • .OnSubmitted --- 用户按回车键时触发。
  • .OnChanged --- 选择项变化时触发。
  • .SetOptions(opts) --- 动态更新选项列表。

5.7 复选框 (Check)

go 复制代码
// 来源: fynewh/widgetCheck.go
import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/widget"
)

func HboxCheck() *fyne.Container {
    lblMsg := widget.NewLabel("")

    // 创建复选框:参数为文字和状态变化回调
    cb1 := widget.NewCheck("check1.orange", func(b bool) {
        if b {
            lblMsg.SetText("check1-selected") // 选中状态
        } else {
            lblMsg.SetText("check1-unselected") // 未选中状态
        }
    })
    // 设置默认状态为选中
    cb1.SetChecked(true)

    return container.NewHBox(cb1, widget.NewSeparator(), lblMsg)
}

说明

  • NewCheck("文字", func(bool){}) --- 创建复选框,回调参数的 bool 表示当前选中状态。
  • .SetChecked(true/false) --- 设置初始选中状态。

5.8 单选框 (RadioGroup)

go 复制代码
// 来源: fynewh/widgetRadio.go
import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/widget"
)

func HboxRadio() *fyne.Container {
    lblMsg := widget.NewLabel("")

    // 创建单选组:参数为选项列表和选择回调
    radio := widget.NewRadioGroup([]string{"orange", "red", "blue"}, func(s string) {
        lblMsg.SetText(s) // 显示当前选中值
    })
    // 设置默认选中第 0 项
    radio.SetSelected("orange")

    return container.NewHBox(radio, widget.NewSeparator(), lblMsg)
}

说明

  • NewRadioGroup([]string{...}, func(string){}) --- 创建单选组,回调参数是选中的值。
  • .SetSelected("value") --- 设置默认选中项。
  • .Selected --- 获取当前选中值。

5.9 列表 (List)

基本列表(显示字符串数组)
go 复制代码
// 来源: fynewh/widgetList.go
import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/widget"
)

func VBoxList(w fyne.Window) *fyne.Container {
    // 定义数据源
    listData := []string{"orange", "red", "blue", "yellow", "black"}

    // 创建列表:参数为数据长度和两个回调函数
    lst := widget.NewList(
        // 返回列表行数
        func() int {
            return len(listData)
        },
        // 创建每行的模板 ------ 返回一个可复用的画布对象
        func() fyne.CanvasObject {
            return widget.NewLabel("")
        },
        // 绑定数据到模板 ------ 对每一行调用
        func(id widget.ListItemID, object fyne.CanvasObject) {
            object.(*widget.Label).SetText(listData[id])
        },
    )

    // 选中行回调
    lst.OnSelected = func(id widget.ListItemID) {
        fmt.Println("Selected:", listData[id])
    }

    return container.NewVBox(lst)
}

说明

  • NewList(lenFn, createFn, updateFn) --- 创建列表控件。
    • lenFn --- 返回列表总行数。
    • createFn --- 创建每行的模板控件(Fyne 会复用这些控件)。
    • updateFn --- 根据行号更新模板内容,id 是行索引。
  • .OnSelected --- 行被选中时的回调。
  • .OnUnselected --- 行取消选中时的回调(v2.4+)。
  • .SetItemHeight(id, height) --- 设置指定行的高度(v2.4+)。
  • .Select(id) / .Unselect(id) --- 编程方式选中/取消选中行。
图标列表 (ListIcon)
go 复制代码
// 来源: fynewh/widgetListIcon.go
import "fyne.io/fyne/v2/theme"

func VBoxListIcon(w fyne.Window) *fyne.Container {
    lst := widget.NewList(
        func() int { return 5 },
        func() fyne.CanvasObject {
            // 每行模板:图标 + 标签
            return container.NewHBox(widget.NewIcon(theme.HomeIcon()), widget.NewLabel(""))
        },
        func(id widget.ListItemID, object fyne.CanvasObject) {
            // 找到第 2 个控件(标签)
            object.(*fyne.Container).Objects[1].(*widget.Label).SetText("Item" + strconv.Itoa(id))
        },
    )
    return container.NewVBox(lst)
}

说明 :图标列表与普通列表用法相同,只是 createFn 中返回的模板包含多个子控件。

相关推荐
光头闪亮亮1 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(下)
android·c++·go
Ch_champion2 小时前
2018年之前的Android 项目上使用的技术点(及第三方库)
android
龚礼鹏2 小时前
RK Android16 wifi 投屏失败问题排查
android
晓梦林4 小时前
[ACTF2020 新生赛]BackupFile学习笔记
android·笔记·学习
妙码生花4 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(三十六):多驱动上传接口
后端·go·ai编程
张人玉4 小时前
基于 Vue 3 + ECharts + Express + SQLite 构建的新能源汽车销量数据分析与可视化平台——新能源汽车销量数据分析系统
数据库·vue.js·sqlite·echarts
ITmaster07315 小时前
告别 IDE?Android CLI 来了,开发进入 AI Agent 时代
android·ide·人工智能
aaajj6 小时前
【Android】获取设备音频
android
清泓y7 小时前
UE移动开发技术面试题
android·面试·ue5·ue4·游戏程序