fyne - 誰說用Go不能開發應用介面

轩脉刃發表於2024-03-20

fyne專案介紹

fyne 是一個純 Golang 的跨平臺 GUI 庫,跨平臺庫說實話,是有很多選擇的,Flutter、Electron、QT等。fyne 絕對不是一個很大眾的選擇。但是在我,一名後端程式設計師嘗試使用 Electron實現一個簡單的番茄時鐘,痛苦地在使用 js 如何在渲染程序和主程序之間傳遞資訊,如何在客戶端退到後臺的時候繼續進行倒數計時,vue 和哪個 electron 的庫版本相容的問題中進行掙扎的時候,我真的很希望能有一個純 Go 實現的 GUI 庫能開發 mac 的 app,而且想到這並不是不能做到的,都是使用底層的系統介面渲染,沒有那個語言更高貴對吧。於是,就找到了它,這就是 fyne。

再進一步瞭解 fyne 的時候,感覺進入了另外一個世界。fyne,它已經不僅僅是一個開源專案,它正在逐漸形成一個自己的生態。

fyne 的 github 開源地址是 https://github.com/fyne-io/fyne ,它的官網地址是 https://fyne.io/。 fyne 有一大堆的開源簇擁者,開源簇擁者會上傳他們自己開發的 app 到 https://apps.fyne.io/,簇擁者也為 fyne 開發一系列的擴充套件 https://github.com/fyne-io/fyne-x ,並且 fyne 官方會定期將一些好的擴充套件併入標準庫。不僅如此,fyne 在 2019 年開始舉辦 FyneConf 大會 https://conf.fyne.io/ ,到 2023 年已經5 屆了。

分析原始碼,fyne 是一個近 9w 行程式碼的專案,屬於一箇中等偏上的專案量了,有 1w 多行註釋,註釋量也足夠多了。

------------------------------------------------------------------------------------------------------------
File                                                                     blank        comment           code
------------------------------------------------------------------------------------------------------------
SUM:                                                                     17568          10438          89688
------------------------------------------------------------------------------------------------------------

好的專案和好的產品一樣,內部複雜,但是外部暴露簡單,這 9w 行程式碼我們不一定都能理解,但是隻要能理解下 fyne 宇宙中最核心的幾個結構及它們的方法,就能很快使用它,就能成為一名合格的使用者了。

fyne 核心資料結構

App

App 在 fyne 庫中fyne.App, 它是一個 interface,定義了一些圖形化應用程式的基本結構和功能。App是整個應用的最原始的存在。對,就是宇宙萬物中的一生二,二生四,四生萬物中的一,有了它,你就能擁有全世界。

我們使用下列兩種庫方法可以從 fyne 庫直接建立 fyne.App

func NewWithID(id string) fyne.App

func New() fyne.App

New 的底層實現我們暫且不論,這裡的 id 引數是什麼?它是代表當前 app 的一個唯一字串,我們一般填寫能唯一指定當前 app 的名字,諸如 “com.hade.toolbox” 的字串。如果不填寫,就會使用時間戳來生成一個 fake 的 id。這個 id 在 app 內部叫做 UniqueID,在建立快取,臨時檔案儲存等目錄的時候,會使用這個 id 來建立子目錄。這裡的 id 必須是全域性唯一的。

我們再看下App定義的介面有如下,這裡直接將註釋給出,

NewWindow(title string) Window: 建立一個新的視窗,並將其作為應用程式的一部分。第一個開啟的視窗被視為"主視窗",當關閉時應用程式將退出。
OpenURL(url *url.URL) error: 在預設瀏覽器中開啟指定的 URL。
Icon() Resource: 獲取應用程式的圖示,用於各種作業系統特定的顯示。這也是新視窗的預設圖示。
SetIcon(Resource): 設定應用程式使用的圖示資源。
Run(): 啟動應用程式的事件迴圈,並一直阻塞直到呼叫 Quit() 或最後一個視窗關閉。
Quit(): 退出應用程式,關閉所有開啟的視窗。在移動裝置上不執行任何操作,因為應用程式生命週期由作業系統管理。
Driver() Driver: 返回渲染該應用程式的驅動程式。通常不需要在日常工作中使用,主要用於內部功能。
UniqueID() string: 返回應用程式的唯一識別符號(如果已設定)。這必須在使用 Preferences() 函式時設定。
SendNotification(*Notification): 傳送一個系統通知,將在作業系統的通知區域顯示。
Settings() Settings: 返回全域性設定,確定主題等。
Preferences() Preferences: 返回應用程式首選項,用於儲存配置和狀態。
Storage() Storage: 返回特定於此應用程式的儲存處理程式。
Lifecycle() Lifecycle: 返回一個型別,允許應用程式鉤入生命週期事件。
Metadata() AppMetadata: 返回在編譯時設定的應用程式後設資料。
CloudProvider() CloudProvider: 返回當前應用程式的雲提供商(如果已由開發人員註冊或使用者選擇)。
SetCloudProvider(CloudProvider): 允許開發人員指定應用程式應如何與雲服務整合。

這個介面引出了 App 的幾個下級結構:

  • Window
  • Resource
  • Driver
  • Settings
  • Preferences
  • Storage
  • Lifecycle
  • AppMetadata
  • CloudProvider

這幾個下級結構就是玩轉 fyne 最需要了解的。

App -> Window

我們的應用 App 一般都會有好幾個視窗組成,當點選某個按鈕的時候,彈出一個視窗,這裡的視窗,在 fyne 庫中就叫做 Window 資料結構。

當然這些若干視窗的地位也不盡相同,第一個建立出來的視窗稱為主視窗,其他的視窗稱為子視窗。當主視窗關閉的時候,整個 app 也就關閉了。

fyne.Window 其實也是個介面,這個 Window 介面提供了建立、管理和控制應用程式視窗的基本功能,包括設定標題、全屏模式、大小調整、聚焦、內邊距、圖示、選單、生命週期回撥、拖放支援以及與畫布和剪貼簿的互動。

下面是對相關介面的詳細說明:

Title() string: 返回當前視窗的標題。這通常顯示在視窗裝飾中。
SetTitle(string): 更新視窗的標題。
FullScreen() bool: 返回視窗是否處於全屏模式。
SetFullScreen(bool): 設定視窗是否應處於全屏模式。
Resize(Size): 根據指定的內容大小調整視窗大小。由於各種桌面或平臺約束,實際大小可能與請求的不完全一致。
RequestFocus(): 嘗試提升並聚焦該視窗。這隻應在確定使用者希望此視窗從任何當前聚焦的視窗竊取焦點時呼叫。
FixedSize() bool: 返回視窗是否應禁用調整大小。
SetFixedSize(bool): 設定是否應將視窗大小固定。
CenterOnScreen(): 將視窗放置在當前視窗所在的顯示器中心。
Padded() bool: 返回視窗是否應有內邊距,以使元件不會觸及視窗邊緣。
SetPadded(bool): 設定視窗是否應有內邊距。用於全屏或基於圖形的應用程式可能很有用。
Icon() Resource: 返回視窗圖示,根據作業系統的不同會以各種方式使用,通常顯示在視窗邊框或任務切換器上。
SetIcon(Resource): 設定此視窗使用的圖示資源。如果未設定,則應返回應用程式圖示。
SetMaster(): 指示關閉此視窗應退出應用程式。
MainMenu() *MainMenu: 獲取視窗的頂級選單。
SetMainMenu(*MainMenu): 為此視窗新增頂級選單。渲染方式取決於載入的驅動程式。
SetOnClosed(func()): 設定在視窗關閉時執行的函式。
SetCloseIntercept(func()): 設定一個函式,在關閉視窗時執行,而不是關閉視窗。在攔截器中應顯式呼叫 Close() 來關閉視窗。
SetOnDropped(func(Position, []URI)): 設定一個視窗範圍的回撥函式,用於接收拖放的專案。
Show(): 顯示視窗。
Hide(): 隱藏視窗,但不會銷燬視窗或導致應用程式退出。
Close(): 關閉視窗。如果它是"主視窗",應用程式將退出。
ShowAndRun(): 顯示視窗並執行應用程式。這應該在 main() 函式的末尾呼叫,因為它會阻塞。
Content() CanvasObject: 返回此視窗的內容。
SetContent(CanvasObject): 設定視窗的內容。
Canvas() Canvas: 返回用於在視窗中呈現的畫布上下文。這可能有助於為視窗設定鍵處理程式。
Clipboard() Clipboard: 返回系統剪貼簿。

大部分介面都很容易理解,其中我們關注到 Window 的幾個下級資料結構:

  • MainMenu
  • CanvasObject
  • Canvas
  • Clipboard

同樣的,我們需要鑽入到這幾個下級資料結構瞭解。

Window -> MainMenu

MainMenu 層級往下,有 MainMenu,Menu,MenuItem 三個層級結構。

MainMenu 結構定義了啟用 Windows 視窗後,選單欄(桌面)顯示的內容。

Menu 結構定義了應用程式中標準選單的資訊。它可以用作主選單(從 MainMenu 下拉)或彈出式選單。

MenuItem 結構定義了選單中的單個專案。

簡要來說,MainMenu 就是整個選單欄,Menu 是下拉的一列,MenuItem 是一列中的單行。

  1. MainMenu 包含一個 *Menu 型別的切片 Items,代表頂級選單。
  2. Menu 包含一個 *MenuItem 型別的切片 Items,代表選單項。
  3. MenuItem包含以下欄位:
    • ChildMenu: 如果此選單項有子選單,則為該子選單的指標。
    • IsQuit: 如果設定為 true,則表示此選單項用於退出應用程式。
    • IsSeparator: 如果設定為 true,則表示此選單項應用作分隔符。
    • Label: 選單項的顯示標籤。
    • Action: 當選單項被點選時要執行的函式。
    • Disabled: 如果設定為 true,則表示此選單項應該被禁用。
    • Checked: 如果設定為 true,則表示此選單項應該被顯示為已選中狀態。
    • Icon: 選單項的圖示資源(如果有)。
    • Shortcut: 與此選單項關聯的快捷鍵(如果有)。

這三者的關係我們用如下類圖來表示:

classDiagram class MainMenu { +[]*Menu Items +Refresh() } class Menu { +string Label +[]*MenuItem Items +Refresh() } class MenuItem { +*Menu ChildMenu +bool IsQuit +bool IsSeparator +string Label +func() Action +bool Disabled +bool Checked +Resource Icon +Shortcut Shortcut } MainMenu "1" *-- "*" Menu : contains Menu "1" *-- "*" MenuItem : contains

以下是這三個資料結構每個介面的說明,略微枯燥,可具體使用再細看。

MainMenu 包含以下內容:

  1. Items: 一個 *Menu 型別的切片,代表頂級選單項。每個 Menu 代表一個下拉選單。

MainMenu 提供了以下方法:

  1. NewMainMenu(items ...*Menu) *MainMenu: 建立一個新的 MainMenu 例項,並傳入頂級選單項。
  2. Refresh(): 通知任何使用此結構的渲染選單更新它們的顯示。這對於在應用程式執行時動態更新選單很有用。

這個結構是 Fyne 庫中用於管理應用程式主選單的核心部分。它允許開發人員定義應用程式的頂級選單結構,並在執行時動態更新選單。這對於建立功能豐富的桌面應用程式非常有用。

Menu 結構定義了應用程式中標準選單的資訊。它可以用作主選單(從 MainMenu 下拉)或彈出式選單。

Menu 結構包含以下欄位:

  1. Label: 選單的標籤,在主選單中顯示。
  2. Items: 一個 *MenuItem 型別的切片,代表選單中的專案。

Menu 提供了以下方法:

  1. NewMenu(label string, items ...*MenuItem) *Menu: 建立一個新的 Menu 例項,並傳入標籤和選單項。
  2. Refresh(): 通知任何使用此選單的視窗或系統托盤更新其顯示。這對於在應用程式執行時動態更新選單很有用。

Menu 結構是 Fyne 庫中用於管理應用程式選單的核心部分。它允許開發人員定義應用程式中的各種選單,包括主選單和彈出式選單。這些選單可以包含各種選單項,如普通選單項、分隔線、子選單等。Refresh() 方法使開發人員能夠在應用程式執行時動態更新選單,從而提高使用者體驗。

MenuItem 結構定義了選單中的單個專案。它包含以下欄位:

  1. ChildMenu: 如果此選單項有子選單,則為該子選單的指標。
  2. IsQuit: 如果設定為 true,則表示此選單項用於退出應用程式。
  3. IsSeparator: 如果設定為 true,則表示此選單項應用作分隔符。
  4. Label: 選單項的顯示標籤。
  5. Action: 當選單項被點選時要執行的函式。
  6. Disabled: 如果設定為 true,則表示此選單項應該被禁用。
  7. Checked: 如果設定為 true,則表示此選單項應該被顯示為已選中狀態。
  8. Icon: 選單項的圖示資源(如果有)。
  9. Shortcut: 與此選單項關聯的快捷鍵(如果有)。

MenuItem 提供了以下方法:

  1. NewMenuItem(label string, action func()) *MenuItem: 建立一個新的 MenuItem 例項,並傳入標籤和點選時執行的操作。
  2. NewMenuItemSeparator() *MenuItem: 建立一個新的選單分隔線專案。

MenuItem 結構是 Fyne 庫中用於定義應用程式選單項的核心部分。它提供了豐富的功能,如子選單、快捷鍵、圖示和選中狀態等,使開發人員能夠建立功能強大的應用程式選單。這些選單項可以被新增到 Menu 結構中,以構建應用程式的選單層次結構。

其中 MenuItem 中的 Action 函式是我們最經常使用到的,點選某個按鈕的具體行為。

Window -> CanvasObject

CanvasObject 是 Fyne 庫中定義的一個介面,用於描述可以新增到畫布上的任何圖形物件。是的,任何圖形物件,畫布上的任何元素都是由一個 CanvasObject,或者由多個 CanvasObject 組成的。所有畫布上的元素都實現了 CanvasObject 介面。所以CanvasObject 定義的方法,是可以作用在任何元素上的。

CanvasObject 介面定義了以下方法:

  1. Geometry:
    • MinSize() Size: 返回該物件需要被繪製的最小尺寸。
    • Move(Position): 將該物件移動到相對於其父物件的給定位置。這隻應在物件不在使用佈局管理器的容器中時呼叫。
    • Position() Position: 返回該物件相對於其父物件的當前位置。
    • Resize(Size): 將該物件調整到給定大小。這隻應在物件不在使用佈局管理器的容器中時呼叫。
    • Size() Size: 返回該物件的當前大小。
  2. Visibility:
    • Hide(): 隱藏該物件。
    • Visible() bool: 返回該物件是否可見。
    • Show(): 顯示該物件。
  3. Refresh:
    • Refresh(): 如果該物件的內部狀態發生變化而需要重新繪製,則必須呼叫此方法。

以上是 CanvasObject 介面的定義,而對於一些更復雜的額外的物件,fyne 又定義了另外一些基礎介面,這些介面和 CanvasObject 結合起來,就能代表更為複雜的物件元素。

即按照 Golang 的介面鴨子模型,如果我們有具體實現像多個介面,那麼這個實現就有這兩個介面的能力。比如一個實現了 CanvasObject 和 Scrollable 兩個介面的元素,那麼它在畫布上就是可以被滾動的元素。fyne 真是把介面玩到飛起。

  • Disableable: 描述可以被禁用的 CanvasObject
  • DoubleTappable: 描述可以被雙擊的 CanvasObject
  • Draggable: 描述可以被拖動的 CanvasObject
  • Focusable: 描述可以響應焦點的 CanvasObject
  • Scrollable: 描述可以被滾動的 CanvasObject
  • SecondaryTappable: 描述可以響應二次點選(右擊或長按)的 CanvasObject
  • Shortcutable: 描述可以響應快捷鍵命令(退出、剪下、複製和貼上)的 CanvasObject
  • Tabbable: 描述需要接受 Tab 鍵按下事件的 CanvasObject
  • Tappable: 描述可以響應點選事件的 CanvasObject

理解了介面,我們再聊到 CanvasObject 的具體實現,這些實現才是我們具體程式碼中會用到的各個元素,使用好這些元素,你的 app 就能有各種各樣的展示效果。

  • Container 容器
  • Widget 系列
    • Accordion
    • Button
    • Card
    • Check
    • Entry
    • FileIcon
    • Form
    • Hyperlink
    • Icon
    • Label
    • Progress bar
    • RadioGroup
    • Select
    • SelectEntry
    • Separator
    • Slider
    • TextGrid
    • Toolbar
    • List
    • Table
    • Tree
    • AppTabs
    • Scroll
    • Split
  • Dialog 系列
    • Color
    • Confirm
    • FileOpen
    • Form
    • Information
    • Custom

這些元素對應的樣式,可以在官網的 doc 中找到:https://docs.fyne.io/,用的時候再挑。

Window -> Canvas

Canvas 介面定義了一個圖形畫布,可以在其上新增 CanvasObjectContainer。每個畫布都有一個縮放比例,在渲染過程中會自動應用。

為什麼有了 Windows 還有一個 Canvas 呢?

Canvas 理解為畫布,更像是 Windows 的宿主,我們可以有一個畫布放在 Windows 中,也可以有一個畫布放在 Image 圖片中,在這個圖片上進行繪製。

func TestPainter_paintImage(t *testing.T) {
	img := canvas.NewImageFromImage(makeTestImage(3, 3))

	c := test.NewCanvas()
	c.SetPadded(false)
	c.SetContent(img)
	c.Resize(fyne.NewSize(50, 50))
	p := software.NewPainter()

	target := p.Paint(c)
	test.AssertImageMatches(t, "draw_image_default.png", target)
}

Canvas 介面提供了管理畫布內容、焦點、事件、縮放和覆蓋層的功能,以及截圖和座標轉換等實用工具。它是 Fyne 庫中構建圖形使用者介面的核心元件之一。

Canvas 介面定義了以下功能:

  1. 內容管理:
    • Content() CanvasObject: 返回當前設定在畫布上的頂層 CanvasObject
    • SetContent(CanvasObject): 設定畫布的頂層 CanvasObject
    • Refresh(CanvasObject): 通知畫布重新繪製指定的 CanvasObject
  2. 焦點管理:
    • Focus(Focusable): 設定指定的 Focusable 物件為焦點。
    • FocusNext(): 聚焦下一個可聚焦的物件。
    • FocusPrevious(): 聚焦上一個可聚焦的物件。
    • Unfocus(): 取消當前焦點。
    • Focused() Focusable: 返回當前獲得焦點的物件。
  3. 尺寸和縮放:
    • Size() Size: 返回畫布的當前大小。
    • Scale() float32: 返回畫布當前使用的縮放比例。
  4. 覆蓋層管理:
    • Overlays() OverlayStack: 返回畫布的覆蓋層堆疊。
  5. 事件處理:
    • OnTypedRune() func(rune), SetOnTypedRune(func(rune)): 設定和獲取鍵入字元事件的處理函式。
    • OnTypedKey() func(*KeyEvent), SetOnTypedKey(func(*KeyEvent)): 設定和獲取鍵盤事件的處理函式。
    • AddShortcut(shortcut Shortcut, handler func(shortcut Shortcut)): 新增一個快捷鍵及其處理函式。
    • RemoveShortcut(shortcut Shortcut): 移除一個快捷鍵。
  6. 截圖:
    • Capture() image.Image: 捕獲畫布的當前內容並返回一個影像。
  7. 座標轉換:
    • PixelCoordinateForPosition(Position) (int, int): 返回給定位置在畫布上的畫素座標。
    • InteractiveArea() (Position, Size): 返回中央互動區域的位置和大小。

Window -> Clipboard

Clipboard 介面定義了系統剪貼簿的介面。它提供了以下兩個方法:

  1. Content() string: 返回當前剪貼簿的內容。
  2. SetContent(content string): 設定剪貼簿的內容。

這個介面為應用程式提供了與系統剪貼簿進行互動的方法。透過這個介面,開發人員可以:

  1. 從剪貼簿讀取文字內容,例如在貼上操作中使用。
  2. 將文字內容寫入到剪貼簿,例如在複製操作中使用。

Clipboard 介面是 Fyne 庫中用於與系統剪貼簿進行互動的核心元件。它為應用程式提供了一種標準的方式來訪問和管理剪貼簿內容,從而增強應用程式的複製貼上功能。

App -> Resource

Resource 介面定義了一個單一的二進位制資源,比如影像或字型。fyne 傾向於所有外部的資源,比如圖片, 字型等都編譯在程式碼中,被定義一個唯一的標識名稱,擁有對應的位元組陣列內容,在使用的時候,就不用使用各種路徑去載入,而是直接到記憶體中載入。

fyne 還提供了一個 bundle 命令,我們可以用 fyne 的工具對任何 png,freetype 進行打包成為一個變數,我們稱這個變數為 StaticResource。

StaticResource 是 Resource 介面的具體實現,他們提供了一種標準的方式來管理應用程式中包含的二進位制資源。開發人員可以使用這些介面從檔案系統或 URL 載入資源,並在應用程式中使用這些資源,而無需關心底層的檔案系統或網路操作。這有助於提高應用程式的可維護性和跨平臺性。

這或許也是我喜歡 fyne 的原因之一,和 golang 的語言如出一轍,所有東西都是靜態,避免任何的動態載入。不要再去拼湊各種動態檔案路徑,載入等邏輯,真是輕鬆的一匹。

照例對照原始碼列一下介面和結構的定義。

Resource 介面提供了以下方法:

  1. Name() string: 返回資源的唯一名稱,通常與生成它的檔名匹配。
  2. Content() []byte: 返回資源的位元組內容,不進行任何壓縮,但保留資源本身的任何壓縮。

StaticResource 結構包含以下欄位:

  1. StaticName string: 資源的名稱。
  2. StaticContent []byte: 資源的位元組內容。

StaticResource 提供了以下方法:

  1. Name() string: 返回資源的名稱。
  2. Content() []byte: 返回資源的位元組內容。

App -> Driver

Driver 介面定義了 Fyne 渲染驅動程式的抽象概念。任何實現這個介面的驅動程式都必須提供以下方法:

  1. 視窗管理:
    • CreateWindow(string) Window: 建立一個新的 UI 視窗。
    • AllWindows() []Window: 返回包含所有應用程式視窗的切片。
  2. 文字渲染:
    • RenderedTextSize(text string, fontSize float32, style TextStyle) (size Size, baseline float32): 返回渲染給定文字所需的大小和基線高度。
  3. 畫布關聯:
    • CanvasForObject(CanvasObject) Canvas: 返回與給定 CanvasObject 關聯的畫布。
    • AbsolutePositionForObject(CanvasObject) Position: 返回給定 CanvasObject 相對於畫布左上角的絕對位置。
  4. 裝置管理:
    • Device() Device: 返回應用程式當前執行的裝置。
  5. 事件迴圈:
    • Run(): 啟動驅動程式的主事件迴圈。
    • Quit(): 關閉驅動程式和開啟的視窗,然後退出應用程式。
  6. 動畫管理:
    • StartAnimation(*Animation): 註冊一個新的動畫並請求啟動它。
    • StopAnimation(*Animation): 停止一個動畫並從驅動程式中登出。

Driver 介面是 Fyne 庫中非常重要的元件,它定義了渲染引擎的核心功能。透過實現這個介面,開發人員可以為特定的作業系統或執行環境提供定製的渲染驅動程式,從而使 Fyne 應用程式能夠在不同平臺上執行。

在 fyne 中,預設的驅動是 OpenGL(gLDriver)。fyne 使用的 openGL 的驅動也是使用開源庫:github.com/go-gl/glfw/v3.3/glfw。這個開源庫是 cgo 實現的,呼叫作業系統底層的GLFW (OpenGL Friendly Windowing)。而GLFW (OpenGL Friendly Windowing) 是一個開源的、跨平臺的、輕量級的 C 庫,用於建立和管理 OpenGL、OpenGL ES 和 Vulkan 圖形上下文以及視窗。它主要用於遊戲和其他視覺應用程式的開發。

所以這也就是 fyne 能一次開發,mac,android,window 都可執行的底氣所在。

App -> Settings

Settings 介面提供了一種標準的方式來配置 Fyne 應用程式的外觀和行為。開發人員可以透過實現該介面來定義應用程式的預設設定,並允許使用者透過 UI 介面或其他方式進行更改。

這些設定對於確保應用程式在不同平臺和使用者偏好下都能提供一致的體驗非常重要。例如,主題和縮放設定可以確保應用程式在不同螢幕尺寸和解析度下保持良好的視覺效果。

Settings 介面是 Fyne 應用程式配置管理的核心,確保應用程式能夠適應不同的使用者需求和環境。

Settings 介面它包含以下功能:

  1. 主題管理:
    • Theme() Theme: 獲取當前使用的主題。
    • SetTheme(Theme): 設定使用的主題。
    • ThemeVariant() ThemeVariant: 獲取主題的首選變體(如淺色或深色)。
  2. 縮放設定:
    • Scale() float32: 獲取應用程式的縮放比例。
  3. 主色設定:
    • PrimaryColor() string: 獲取使用者首選的主色。
  4. 變更監聽:
    • AddChangeListener(chan Settings): 新增一個監聽器,當設定發生變化時會被通知。
  5. 構建型別:
    • BuildType() BuildType: 獲取應用程式的構建型別(標準、除錯或釋出)。
  6. 動畫設定:
    • ShowAnimations() bool: 獲取是否應該顯示動畫的設定。

App -> Preferences

Preferences 介面定義了一組用於儲存和載入應用程式使用者首選項的方法。首選項就是使用者進入這個 app 後的一些設定值。這些首選項值在一個終端是會進行持久化儲存的,並且在 App 關閉又重新開啟的時候,是還會持續生效。它也支援了多種的資料型別。

它提供了以下功能:

  1. 基本資料型別讀寫:
    • Bool(key string) bool: 讀取指定鍵的布林值。
    • BoolWithFallback(key string, fallback bool) bool: 讀取指定鍵的布林值,如果不存在則返回回退值。
    • SetBool(key string, value bool): 儲存指定鍵的布林值。
    • 類似的方法還有 FloatIntString
  2. 列表資料型別讀寫:
    • BoolList(key string) []bool: 讀取指定鍵的布林值列表。
    • BoolListWithFallback(key string, fallback []bool) []bool: 讀取指定鍵的布林值列表,如果不存在則返回回退列表。
    • SetBoolList(key string, value []bool): 儲存指定鍵的布林值列表。
    • 類似的方法還有 FloatListIntListStringList
  3. 刪除值:
    • RemoveValue(key string): 刪除指定鍵的值。
  4. 變更監聽:
    • AddChangeListener(func()): 新增一個回撥函式,當值發生變化時會被呼叫。
    • ChangeListeners() []func(): 獲取所有已註冊的變更監聽器。

App -> Storage

Storage 介面定義了 Fyne 應用程式內部檔案儲存的相關功能。

Storage 介面提供了一個抽象層,用於管理應用程式自身的檔案儲存。它確保每個 Fyne 應用程式都有一個獨立的沙箱儲存區域,用於儲存應用程式相關的檔案,而不會與其他應用程式的檔案產生衝突。

這個介面的實現會根據不同的作業系統平臺採用不同的儲存機制,比如在 Windows 上可能使用應用程式資料目錄,在 Android 上可能使用內部儲存空間等。但無論採用何種儲存方式,開發者都可以使用統一的 Storage 介面進行檔案操作。

透過使用 Storage 介面,Fyne 應用程式可以保證在不同平臺上都能以一致的方式訪問和管理應用程式檔案,提高了跨平臺的可移植性。同時,這也確保了應用程式的檔案儲存受到沙箱機制的保護,提高了安全性。

它提供了以下主要功能:

  1. 根 URI 訪問:
    • RootURI() URI: 獲取應用程式的根檔案儲存 URI。這個 URI 代表了應用程式獨有的檔案儲存沙箱。
  2. 檔案建立:
    • Create(name string) (URIWriteCloser, error): 建立一個新的檔案,並返回一個可寫入的 URIWriteCloser 物件。
  3. 檔案開啟:
    • Open(name string) (URIReadCloser, error): 開啟一個現有的檔案,並返回一個可讀取的 URIReadCloser 物件。
  4. 檔案儲存:
    • Save(name string) (URIWriteCloser, error): 開啟或建立一個檔案並返回一個可寫入的 URIWriteCloser 物件。
  5. 檔案刪除:
    • Remove(name string) error: 刪除指定名稱的檔案。
  6. 列出檔案:
    • List() []string: 返回當前儲存中所有檔案的名稱列表。

總之, Storage 介面是 Fyne 框架中用於管理應用程式內部檔案儲存的核心元件。它抽象了底層的儲存細節,為上層應用程式提供了一致的檔案操作 API。

App -> Lifecycle

透過 Lifecycle 介面可以在不同階段為應用程式設定行為。

  1. 前後臺切換鉤子:
    • SetOnEnteredForeground(func()): 用於設定一個回撥函式,在應用程式從後臺切換到前臺並獲得焦點時會被呼叫。
    • SetOnExitedForeground(func()): 用於設定一個回撥函式,在應用程式失去輸入焦點並切換到後臺時會被呼叫。
  2. 啟動/停止鉤子:
    • SetOnStarted(func()): 用於設定一個回撥函式,在應用程式啟動並開始執行時會被呼叫。
    • SetOnStopped(func()): 用於設定一個回撥函式,在應用程式停止執行時會被呼叫。

透過這些鉤子函式,開發者可以在應用程式的生命週期關鍵時刻執行相應的邏輯,比如:

  • 當應用程式進入前臺時,可以恢復動畫、重新載入資料等。
  • 當應用程式進入後臺時,可以暫停耗電的操作、儲存當前狀態等。
  • 當應用程式啟動時,可以進行一些初始化操作。
  • 當應用程式停止時,可以執行清理工作、儲存使用者資料等。

App -> AppMetadata

AppMetadata 是 Fyne 框架中用於描述應用程式元資訊的資料結構。它包含了以下幾個重要的屬性:

  1. 應用程式 ID:
    • ID string: 應用程式的唯一識別符號,通常用於各種應用程式分發平臺。
  2. 應用程式名稱:
    • Name string: 應用程式的人類可讀名稱。
  3. 應用程式版本:
    • Version string: 應用程式的版本號,通常遵循語義化版本控制規範。
    • Build int: 應用程式的構建編號,有時會附加在版本號後面。
  4. 應用程式圖示:
    • Icon Resource: 如果存在的話,包含了應用程式在構建時打包的圖示資源。
  5. 釋出模式:
    • Release bool: 表示該二進位制檔案是否是在釋出模式下構建的。
  6. 自定義後設資料:
    • Custom map[string]string: 包含了開發者在 FyneApp.toml 檔案中或編譯命令列上定義的自定義後設資料。

AppMetadata 結構體的作用是為 Fyne 應用程式提供一種標準化的方式來描述自身的元資訊。這些資訊通常會被用於以下場景:

  1. 應用程式分發:
    應用程式 ID、名稱、版本號等資訊通常會被應用程式分發平臺使用,例如 App Store、Google Play 等。
  2. 應用程式徽標:
    應用程式圖示資訊會被用於在作業系統介面和應用商店中顯示應用程式的圖示。
  3. 應用程式配置:
    自定義的後設資料可以被應用程式使用,用於儲存一些額外的配置資訊。
  4. 應用程式更新:
    版本號和構建編號資訊可以幫助使用者跟蹤應用程式的更新情況。

總之, AppMetadata 是 Fyne 框架中用於描述應用程式元資訊的核心資料結構,它為開發者提供了一種標準化的方式來定義應用程式的各種屬性,從而更好地支援應用程式的分發、展示和配置等需求。

App -> CloudProvider

CloudProvider 是 Fyne 框架中用於定義和管理雲服務提供商的介面。它主要提供了以下功能:

  1. 提供者資訊獲取:
    • ProviderDescription() string: 獲取雲服務提供商的詳細描述資訊。
    • ProviderIcon() Resource: 獲取與該雲服務關聯的圖示資源。
    • ProviderName() string: 獲取雲服務提供商的名稱。
  2. 生命週期管理:
    • Cleanup(App): 當雲服務提供商不再被使用時,會被呼叫來執行清理工作。
    • Setup(App) error: 當雲服務提供商第一次被使用時,會被呼叫進行初始化設定。如果初始化失敗,可以返回一個錯誤,以退出雲服務設定流程。

透過 CloudProvider 介面,Fyne 應用程式可以與不同的雲服務提供商進行整合,並提供統一的使用者體驗。具體的整合方式包括:

  1. 使用者偏好同步:
    • CloudProviderPreferences 介面定義了同步使用者偏好設定到雲端的功能。
  2. 文件同步:
    • CloudProviderStorage 介面定義了同步應用程式文件到雲端的功能。

當應用程式開發者選擇使用雲服務提供商時,只需要實現 CloudProvider 介面以及可選的 CloudProviderPreferencesCloudProviderStorage 介面,就可以為應用程式提供雲同步功能。

Fyne 框架會負責管理不同雲服務提供商的生命週期,並提供統一的 API 供應用程式使用。這使得應用程式開發者可以專注於業務邏輯的實現,而不需要過多地關注雲服務的整合細節。

總之, CloudProvider 是 Fyne 框架中用於整合和管理雲服務提供商的核心元件,它為應用程式提供了跨雲服務的統一抽象,簡化了雲服務整合的開發工作。

fyne 總結

fyne 是一個對於後端 Golang 開發者極其友好的 GUI 庫,對於後端開發人員,功能開發並不是難事,而前端頁面繪製可能會難倒大部分開發者,fyne 提供了一種使用程式碼就能很好繪製介面的方法,這對於這個人群來說,是一個福音。

這裡主要列了 fyne 的核心資料結構,當然每個結構裡面的方法和具體實現都需要花時間琢磨。我自己用 fyne 開發了一個番茄始終,當你自己用 go 繪製了介面,用 go 開啟協程進行倒數計時,用go 在 mac 的 tab 欄增加倒數計時顯示的時候,你才會感嘆到 fyne 的強大。

相關文章