Go Gio 實戰:煮蛋計時器的實現 03— 按鈕
大家好,我是程序員幽鬼。
上篇文章介紹了空窗口的實現。今天看看如何控制窗口,比如標題、大小等。
01 目標
GUI 程序,按鈕是少不了的,對按鈕點擊事件的響應,是必須掌握的知識點。通過本文的學習,可以掌握 GUI 事件響應的編程方法。
本節效果如下:
A button
02 主要內容
本節將介紹許多新組件,不過不會太深入細節,而是專注於程序的整體結構。雖然只是增加按鈕,但需要導入不少相關新包,因此需要花點時間瞭解下。之後會看看如何聯合 operations
和widgets
來製作一個按鈕。
最後,我們談到了 Material Design[1],這是一個完善的用戶界面框架(Google 出品的),也可以在 Gio 中使用。
03 需要用的到包
本節會導入如下包:
import (
"gioui.org/app"
"gioui.org/font/gofont"
"gioui.org/io/system"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
)
對這些包做一個說明,其中 app
和 unit
之前有介紹過,因此介紹其他的包。
-
font/gofont[2] - Go 自己有一套高質量的 True Type 字體,這是對其進行封裝,導出給 gioui.org/text 包使用。關於官方的這套字體,可以閱讀 Go 官方的博文:https://go.dev/blog/go-fonts。
-
io/system[3] - 提供從窗口發送的高級事件。最重要的是
system.FrameEvent
。它實際上是執行以下兩項操作之一的操作列表:詳細說明如何處理輸入並描述要顯示的內容。 -
layout[4] - 定義佈局中的有用可變部分,例如_尺寸_、_約束_和_方向_。此外,它還包括稱爲 Flexbox[5] 的佈局概念。它被廣泛用於 Web 和用戶界面開發,詳情可以參考 Mozilla 上的介紹 [6]。
-
op[7] - Operations 或 ops 是 Gio 的核心。它們用於更新用戶界面。有一些操作用於繪製、處理輸入、更改窗口屬性、縮放、旋轉等。有趣的是還有宏 [8],可以記錄稍後要執行的操作。總之,這意味着操作列表是一個_可變堆棧_,你可以在其中控制流程。
-
widget[9] - 小部件提供 UI 組件的底層功能,例如狀態跟蹤和事件處理。鼠標是否懸停在按鈕上?是否被點擊過,如果有,點擊了多少次?
-
widget/material[10] - 雖然
widget
提供功能,但widget/material
定義了一個主題。請注意,該界面實際上分爲兩部分:這是爲了提高小部件的可重用性和靈活性。我們稍後會用到它。
默認看起來不錯,也是我們將使用的,但通過設置顏色、文本大小字體屬性等屬性也很容易調整。
-
注意:Gio 在名爲 gio-x[11] 的專用存儲庫中擴展了基本功能,其中正在開發更多材質組件 [12],包括導航欄和工具提示。
-
具有狀態的實際小部件
-
小部件的繪製,完全無狀態
04 功能實現
看看本文開頭提到的按鈕功能如何實現,代碼如下:
func main() {
go func() {
// 創建一個新窗口
w := app.NewWindow(
app.Title("煮蛋計時器"),
app.Size(unit.Dp(400), unit.Dp(600)),
)
// ops 表示 UI 上的操作
var ops op.Ops
// startButton 時候一個可點擊的小部件
var startButton widget.Clickable
// th 定義 material design(材料設計)的風格
th := material.NewTheme(gofont.Collection())
// 循環監聽窗口上的事件
for e := range w.Events() {
// 監聽事件的類型
switch e := e.(type) {
// 當應用程序需要重新渲染是發送該事件
case system.FrameEvent:
gtx := layout.NewContext(&ops, e)
btn := material.Button(th, &startButton, "Start")
btn.Layout(gtx)
e.Frame(gtx.Ops)
}
}
}()
app.Main()
}
05 代碼詳解
主要關注這次新增的內容。
1)設置了三個新變量
-
ops
從用戶界面定義操作,具體的作用說明,介紹 op 包時講解了。 -
startButton
是我們的按鈕,一個可點擊的小部件。 -
th
是材料設計主題,設置字體爲 gofonts。
2)事件循環代碼:
for e:= range w.Events()
是重點:
-
w.Events()
方法的返回值類型是:<-chan event.Event
,爲我們提供了傳遞事件的 channel。我們只是循環監聽。 -
event.Event
是一個接口。因此,在循環裏面,我們需要進行斷言,對不同的事件做不同的響應。 -
在這個例子中,我們只對事件
system.FrameEvent
進行處理。具體處理邏輯: -
請注意,我們如何輕鬆獲得所有鼠標懸停和點擊動畫。它們都是主題(theme)的一部分,很贊。
-
我們定義一個新的_圖形上下文_即
gtx
。它接收指向ops
的指針以及事件system.FrameEvent
。 -
btn
是實際的按鈕,material.Button
接收主題th
和指向startButton
小部件的指針。我們還定義了顯示的文本(注意,文本是純粹顯示在按鈕上的,而不是按鈕這個有狀態小部件的一部分。) -
btn.Layout(gtx)
表示按鈕btn
要求在上下文gtx
中顯示自己。這是關鍵。佈局不佈局按鈕,按鈕自己佈局。這非常方便,例如嘗試調整窗口大小。無論畫布的大小或形狀如何,按鈕都會重新調整自己。 -
最終,我們實際將操作
ops
從上下文gtx
發送到 FrameEvente
。
最後,記得實際動手運行看看。我們並沒有設置實際的按鈕點擊樣式,Gio 自動幫我們做了。
06 小結
本節雖然只是實現一個按鈕,但涉及到的知識點不少,關鍵代碼就幾行,但需要花些時間瞭解下相關 API 的用法,掌握使用 Gio 實現 GUI 的關鍵步驟和思路。
參考:https://jonegil.github.io/gui-with-gio/egg_timer/03_button.html。
參考資料
[1]
Material Design: https://material.io/
[2]
font/gofont: https://pkg.go.dev/gioui.org/font/gofont
[3]
io/system: https://pkg.go.dev/gioui.org/io/system
[4]
layout: https://pkg.go.dev/gioui.org/layout
[5]
Flexbox: https://pkg.go.dev/gioui.org/layout#Flex
[6]
Mozilla 上的介紹: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox
[7]
op: https://pkg.go.dev/gioui.org/op
[8]
宏: https://pkg.go.dev/gioui.org/op#MacroOp
[9]
widget: https://pkg.go.dev/gioui.org/widget
[10]
widget/material: https://pkg.go.dev/gioui.org/widget/material
[11]
gio-x: https://pkg.go.dev/gioui.org/x
[12]
更多材質組件: https://pkg.go.dev/gioui.org/x/component
歡迎關注「幽鬼」,像她一樣做團隊的核心。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/qATfomFe2o9adBuf_fXtZw