Go语言开源跨平台GUI框架Fyne小教程|架构篇
  iwbGD3gmtxyT 2023年11月24日 14 0

Go语言开源跨平台GUI框架Fyne小教程|架构篇_GO语言

一、窗体结构(Geometry)

Fyne应用程序基于每个窗口1个画布。每个画布都有一个根CanvasObject,它可以是一个小部件(Gadget),也可以是许多子对象的容器(Container),这些子对象的大小和位置由Layout控制。

位置(Position)

每个画布的原点位于左上角(0,0)。UI的每个元素都可以根据输出设备进行缩放;因此,相关API没有描述像素或精确度量。例如,在120DPI显示器上,位置(10,10)可能是从原点向右和向下的10个像素,但在HiDPI(或“Retina”)显示器上,这可能更接近20个像素。

CanvasObject引用的每个位置都是相对于其父对象的。这对布局算法很重要,但对Tappable.Tapped(PointEvent)处理程序等需求情况下的开发人员也很重要。在这里,X/Y坐标将从按钮的左上角计算,而不是从整个画布计算。这是为了让代码尽可能地自包含。

像素大小(Pixel size)

像其他基于矢量的GUI库一样,Fyne坐标需要基于一些基准监视器分辨率。所有缩放都与该值相关。对于Fyne环境来说,标准分辨率为120DPI。这意味着,在fyne.Size这个函数中,当您的显示器为120DPI且比例值均设置为1时,大小将为1px。如上所述,对于HiDPI屏幕,实际DPI可能接近240,而在移动设备上,它甚至可能是360或更高。为了处理这种复杂性,Fyne框架在内部管理缩放问题,这样你的应用程序看起来总是合适的大小。如果用户将比例设置为更小,那么他们的应用程序将始终具有比正常字体、按钮等更小的字体,当他们指定更大的字体时,您的应用程序会根据需要进行缩放。

Material Design标准(Fyne正是在此标准的启示下设计出跨平台屏幕缩放机制)相比,我们可以看到他们的基准DPI为160,尽管数学上相似,但实际数字会有所不同。这意味着,Fyne中与设备无关的大小使用较小的数字来表示相同的物理大小。例如,在标准的Material Design(例如Android)应用程序中,Fyne中高度为18的图标的大小为24。这在构建应用程序时并不重要,但在与设计师或Material Design专家合作时可能很重要。

像素大小方面的一个问题是,当您开始加载位图图像时。通常情况下,这些比例是适当的,但如果指定FillMode=fyne.FillOriginal,则由于像素密度的原因,不同设备上的实际图像大小会有所不同。通常,此功能将在Scroll容器中使用。Fyne还定义了canvas.Raster,它将精确地按照输出设备的像素密度绘制像素。这使您的代码能够在不知道运行设备细节的情况下以尽可能高的输出分辨率绘制。如果出于某种原因,您需要“像素完美”定位,则需要CanvasObject.Size() 乘以Canvas.Scale()

二、缩放(Scaling)

Fyne完全使用矢量图形构建。这意味着,用Fyne编写的应用程序可以漂亮地扩展到任何大小(而不仅仅是整数增量)。这对移动设备和高端计算机上高密度显示器的日益普及是一个巨大的好处。默认比例值是根据您的操作系统计算的——在某些系统上,这是用户配置,而在其他系统上,则是根据屏幕的像素密度(DPI-每英寸点数)计算的。如果Fyne窗口被移动到另一个屏幕,它将重新缩放并相应地调整窗口大小!我们称之为“自动缩放”,它的设计目的是在更改监视器时保持应用程序用户界面的大小不变。

您可以使用fyne_settings应用程序或使用FYNE_SCALE环境变量设置特定比例来调整应用程序的大小。这些值可以使内容比系统默认设置值大一些或小一些,例如,使用“1.5”会使内容大50%,设置0.8会使内容小20%。

Go语言开源跨平台GUI框架Fyne小教程|架构篇_Fyne_02

三、窗口部件(Widgets)

Fyne工具包中的小工具旨在实现干净愉快的用户交互,遵循标准主题,支持快速的应用程序开发、可靠的测试和轻松的维护。有各种各样的设计考虑因素促进了这一雄心,我们在本页中对此进行了探讨。

行为API

关于标准小部件,您会注意到的一点是,API完全是关于行为和状态的,但很少控制元素的实际外观。这是经过设计的。它使我们的代码和应用程序开发人员的代码能够专注于小部件的行为,这样它的渲染过程就可以留给其他代码了。这使得测试变得更加容易,事实上,完整的应用程序可以在内存中通过单元测试运行,而无需渲染应用程序。

您可以扩展现有的小部件来添加新的行为,而无需担心它是如何呈现的。也可以编写自己的组件,应用程序不限于使用所提供的小部件集。在构建自己的小部件时,您会注意到渲染细节与状态是完全独立的——这是上面提到的设计的一部分。WidgetRenderer(渲染Widget的代码)通常保存对它将要渲染的小部件的引用,以访问状态或其他信息。当小部件状态发生变化时,会调用Refresh()-然后会要求渲染器刷新,它应该更新显示以反映新状态。建议使用当前主题的自定义小部件,但可以选择在需要的地方指定自己的尺寸、颜色和图标。

内容填充

标准小部件使用主题指定的填充来在其图形组件周围留出适当的空间。小部件包使用标准的高度和基线来确保所提供的布局在默认情况下能够很好地对齐。如果您正在构建一个自定义小部件,建议您遵循这些准则。

主题的价值。Padding()在布局中用于分隔容器的元素,它在应用程序的各个部分周围创建了一个一致的空间。然而,有些小部件的内容应该从扩展区的边缘插入。以Entry为例,它有一个背景和一个延伸到边缘的边框,但它的内容应该是插入的。因此,我们已经标准化了用于插入的间距,以便对齐匹配。

小部件的标准插入或内容填充被定义为主题。内侧衬垫()。填充的标准值为4,内部填充为8。您可以在“标签和条目”中看到(文本)内容是如何插入的,这样它们的内容在相邻放置时将水平和垂直对齐。

Go语言开源跨平台GUI框架Fyne小教程|架构篇_架构_03

建议自定义窗口小部件包含类似的尺寸,以便它们与标准窗口小部件一起使用。

四、组织和包装

Fyne项目分为多个GO开发包,每个包提供不同类型的功能。它们所在路径展示如下:

(一)fyne.io/fyne/v2

说明:此包提供了所有Fyne代码通用的基本定义,包括数据类型和接口。

更具体地说,这个包fyne描述了任何fyne应用程序中可用的对象和组件。所有位于此包中的对象都可以在不渲染的情况下创建、操作和测试(为了速度)。您的main包应该使用此应用程序包创建一个具有默认驱动程序的应用程序,该驱动程序将呈现您的UI。

因此,一个简单但典型的Fyne应用程序看起来应该如下所示:

package main

import "fyne.io/fyne/v2/app"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/widget"

func main() {
	a := app.New()
	w := a.NewWindow("Hello")

	hello := widget.NewLabel("Hello Fyne!")
	w.SetContent(container.NewVBox(
		hello,
		widget.NewButton("Hi!", func() {
			hello.SetText("Welcome :)")
		}),
	))

	w.ShowAndRun()
}



(二)fyne.io/fyne/v2/app

说明:app包提供启动一个新的应用程序的API支持。通常你只需要调用app.New() 或者 app.NewWithID()

(三)fyne.io/fyne/v2/canvas

说明:canvas包提供了Fyne中的所有绘图API。完整的Fyne工具包由这些原始的图形类型组成。

(四)fyne.io/fyne/v2/container

说明:container包提供用于布置和组织应用程序的容器。

(五)fyne.io/fyne/v2/data/binding

说明:这个绑定包包含将数据源绑定到小部件(gadget)的方法。

(六)fyne.io/fyne/v2/data/validation

说明:此验证包提供了用于验证小部件内部数据的工具。

(七)fyne.io/fyne/v2/dialog

说明:对话框包包含确认、错误和文件保存/打开等对话框。

(八)fyne.io/fyne/v2/layout

说明:布局包提供了各种布局实现以供使用容器(简单情况下也可以不使用容器)时的使用场景。

(九)fyne.io/fyne/v2/storage

说明:存储包提供存储访问和管理功能。

(十)fyne.io/fyne/v2/test

说明:使用这个测试包中提供的工具函数可以更容易地测试基于Fyne框架开发的应用程序包。

(十一)fyne.io/fyne/v2/widget

说明:大多数图形应用程序都是使用小部件集合创建的。Fyne中的所有小部件和交互元素都在这个包中。

五、几个问题

(一)移动和调整大小的问题

Q: 如何将小部件移动到其他位置或调整其大小?

A: Fyne应用程序中元素的位置和大小由它们所在容器的布局控制。如果UI的元素太小,请考虑使用不同的布局或容器。

一个新的Window将自动扩展,根据传递给SetContent()的任何元素以填充其大小。每次向其中添加容器时,它都会根据布局划分可用空间。像HBox和VBox这样的布局会在一个维度或另一个维度上将内容收缩到其MinSize()指定尺寸以封装内容。像Max或Border这样的布局也将自动扩展其空间以填充空间。通过编写自定义布局,您实现可以完全控制容器中的项目。

Q: 为什么我的图像显得这么小?

A: 使用完全可扩展的用户界面工具包(如Fyne)的困难之一是坐标系与设备无关。这允许应用程序以正确的分辨率或像素密度绘制,以根据连接的硬件获得最佳结果。这对基于像素的图像意味着,它们的大小可能会根据编译时未知的细节而变化。

由于这种复杂性,使用canvas.NewImageFromFile()或类似的调用将会没有尺寸大小问题,导致其非常小或默认情况下显示为隐藏。当放置在适当的布局中时,图像将根据其FillMode属性进行拉伸。如果您希望图像始终设置为特定大小(或更大),可以调用image.SetMinSize(),并为图像指定与设备无关的大小。

(二)容器和布局问题

Q: 如何手动控制元素的位置

A: 在某些情况下,您可能希望完全控制容器中元素的位置和大小。要做到这一点,您可以创建一个没有布局的容器。container.NewWithoutLayout()函数将创建一个用于手动定位的容器——您应该向该构造函数传递一个要在此容器中管理的图形元素列表。

一旦设置好,就可以对每个元素使用Move()和Resize()来根据需要定位它。在执行此操作时,请注意,它不会随着可用空间的变化而调整,也没有明确的最小尺寸。若要添加其中任何一个功能,您应该将手动定位替换为自定义布局。

(三)定制

Q: 如何更改标签小部件的文本颜色?

A: 所有的标准小部件都使用当前的主题定义来设置颜色、字体和大小。若要更改应用程序,请考虑使用自定义主题

如果您的应用程序需要不同颜色的文本,您可以使用canvas.Text类型。这允许直接设置文本的颜色和大小。这样做时要小心,因为用户可以在浅色或深色主题变体之间进行选择,所以应该同时使用这两种变体进行测试。

Q: 如何从我的输入小部件中删除背景色?

A: 输入背景由主题InputBackground颜色设置。你可以把它换成color.Transparent以删除所有输入背景框。无法编辑单个输入元素的样式——主题API旨在提供可定制但一致的设计。

(四)主题API

Q: 如何使用v2.0.0之前编写的自定义主题?

A: 随着时间的推移,您应该考虑更新以使用新主题API。但是,可以使用一个简单的适配器,该适配器允许在过渡期间使用旧主题。你会发现theme.FromLegacy函数,该函数可以使旧主题实例适应新的API。

myTheme := &myOldThemeType{}
updated := theme.FromLegacy(myTheme)
app.Settings().SetTheme(updated)

在这种模式下使用主题时没有性能惩罚,但在未来的版本中,此API将被删除。


六、小结

本篇概要地归纳了Fyne框架中主要的构成组件以及各个包的主要功能。然后,回答了Fyne开发中与界面有关的几个基本问题。有关细节的GUI设计技巧,并没有给出具体的介绍,读者可自行结合有限的官方源码及示例进行归纳。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月24日 0

暂无评论

iwbGD3gmtxyT