赞
踩
fyne将功能划分到不同的子包中:
fyne.io/fyne:提供所有fyne应用程序代码共用的基础定义,包括数据类型和接口;fyne.io/fyne/app:提供创建应用程序的 API;fyne.io/fyne/canvas:提供Fyne使用的绘制 API;fyne.io/fyne/dialog:提供对话框组件;fyne.io/fyne/layout:提供多种界面布局;fyne.io/fyne/widget:提供多种组件,fyne所有的窗体控件和交互元素都在这个子包中。package main import ( "fyne.io/fyne/app" "fyne.io/fyne/container" "fyne.io/fyne/widget" ) func test() { 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() } func main() { test() }

效果,当你点击
Hi!点击按钮时上面的文字变为了Welcome:
package main import ( "image/color" "math/rand" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) func test() { a := app.New() w := a.NewWindow("Canvas") rect := canvas.NewRectangle(color.White) text := canvas.NewText("Hello Text", color.Black) text.Alignment = fyne.TextAlignTrailing text.TextStyle = fyne.TextStyle{Italic: true} line := canvas.NewLine(color.Black) line.StrokeWidth = 4 // 绘制LoGo图 image := canvas.NewImageFromResource(theme.FyneLogo()) image.FillMode = canvas.ImageFillOriginal // 像素图 raster := canvas.NewRasterWithPixels( func(_, _, w, h int) color.Color { return color.RGBA{uint8(rand.Intn(255)), uint8(rand.Intn(255)), uint8(rand.Intn(255)), 0xff} }, ) gradient := canvas.NewHorizontalGradient(color.White, color.Transparent) container := fyne.NewContainerWithLayout( layout.NewGridWrapLayout(fyne.NewSize(150, 150)), rect, text, line, image, raster, gradient, ) w.SetContent(container) w.ShowAndRun() } func main() { test() }
效果图

窗体控件是一个Fyne应用程序的主要组成部分。它们能适配当前的主题,并且处理与用户的交互。
Label(标签)是一个简单的空间,用于字符串的展示。
package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/layout" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Label") l1 := widget.NewLabel("Name") // 可以识别转义字符 l2 := widget.NewLabel("Yu\nhandsome") container := fyne.NewContainerWithLayout(layout.NewVBoxLayout(), l1, l2) w.SetContent(container) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
效果
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KLvVuNf-1661592613756)(C:\Users\86136\AppData\Roaming\Typora\typora-user-images\image-20220827135430414.png)]](https://img-blog.csdnimg.cn/3fa28da09c7b4a5d85957d807787a198.png#pic_center)
package main import ( "fmt" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/layout" "fyne.io/fyne/theme" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Button") btn1 := widget.NewButton("text button", func() { fmt.Println("btn1 button clicked") }) btn2 := widget.NewButtonWithIcon("text button", theme.HomeIcon(), func() { fmt.Println("Home") }) container := fyne.NewContainerWithLayout(layout.NewVBoxLayout(), btn1, btn2) w.SetContent(container) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
在这个案例中我们创建两个按钮,两种共同之处是都需要传入按钮名称和按钮点击触发的执行函数。值得一提的是我们还可以加载外部的图标进行装饰。
效果

package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Button") content := widget.NewVBox( widget.NewLabel("The top row of VBox"), widget.NewHBox( widget.NewLabel("Label 1"), widget.NewLabel("Label 2"), ), ) content.Append(widget.NewButton("Append", func() { content.Append(widget.NewLabel("Append")) })) w.SetContent(content) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
盒子控件Box,其实就是一个容器类似于html中的div。不同的是在盒子创建时我们可选择widget.NewHBox()或widget.NewVBox()创建内部不同布局的盒子。在创建好Box盒子后,我们
效果

输入框(Entry)控件用于给用户输入简单的文本内容。我们可以调用widget.NewEntry()即可创建一个输入框控件。同时我们可以通过访问其Text字段来获得输入框中的内容。注册OnChange回调函数。每当内容有修改时,OnChange就会被调用。SetPlaceHolder()用来设置占位字符,设置字段MultilIne让输入框接受多行文本。此外,NewPasswordEntry()可创建一个密码输入框,输入的文本不会以明文显示。
package main import ( "fmt" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/layout" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Entry") input := widget.NewEntry() input.SetPlaceHolder("please enter name") input.OnChanged = func(content string) { fmt.Println("name", content) } passInput := widget.NewPasswordEntry() passInput.SetPlaceHolder("please enter password") line1 := widget.NewVBox(widget.NewLabel("Name"), layout.NewSpacer(), input) line2 := widget.NewVBox(widget.NewLabel("Password"), layout.NewSpacer(), passInput) loginBtn := widget.NewButton("Login", func() { fmt.Printf("name: %s, password: %s\n Login in", input.Text, passInput.Text) }) content := widget.NewVBox(line1, line2, loginBtn) w.SetContent(content) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
效果

这里的话主要是关于三种选择框的使用:
package main import ( "fmt" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/layout" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Entry") input := widget.NewEntry() input.SetPlaceHolder("please enter name") input.OnChanged = func(content string) { fmt.Println("name", content) } passInput := widget.NewPasswordEntry() passInput.SetPlaceHolder("please enter password") line1 := widget.NewVBox(widget.NewLabel("Name"), layout.NewSpacer(), input) line2 := widget.NewVBox(widget.NewLabel("Password"), layout.NewSpacer(), passInput) loginBtn := widget.NewButton("Login", func() { fmt.Printf("name: %s, password: %s\n Login in", input.Text, passInput.Text) }) sexRadio := widget.NewRadio([]string{"male", "female"}, func(value string) { fmt.Printf("sex %s\n", value) }) sexBox := widget.NewHBox(widget.NewLabel("Sex"), sexRadio) provinceSelect := widget.NewSelect([]string{"beijing", "zhejiang", "shanghai"}, func(value string) { fmt.Println("province:", value) }) provinceBox := widget.NewHBox(widget.NewLabel("Province"), layout.NewSpacer(), provinceSelect) content := widget.NewVBox(line1, line2, sexBox, provinceBox, loginBtn) w.SetContent(content) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
效果

表单控件Form用于对很多Label和输入控件进行布局。如果指定了OnSubmit或OnCancek函数,表单控件
package main import ( "fmt" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Entry") input := widget.NewEntry() passWord := widget.NewPasswordEntry() form := widget.NewForm( &widget.FormItem{Text: "Name", Widget: input}, &widget.FormItem{Text: "password", Widget: passWord}, ) form.OnSubmit = func() { fmt.Printf("Name: %s\nPassword: %s\n", input.Text, passWord.Text) } form.OnCancel = func() { fmt.Printf("Login end") } w.SetContent(form) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
效果

进度条(ProgressBar)用来表示任务的进度。例如文件下载的进度。创建当大widget.NewProgressBar(),默认最小值0.0,最大值为1.1,可通过Min/Max字段,调用SetValue()方法来控制进度,还有一种进度条是循环动画,表示任务在进行中。
package main import ( "time" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Entry") bar1 := widget.NewProgressBar() bar1.Min = 0 bar1.Max = 100 bar2 := widget.NewProgressBarInfinite() go func() { for i := 0; i <= 100; i++ { time.Sleep(time.Millisecond * 500) bar1.SetValue(float64(i)) } }() content := widget.NewVBox(bar1, bar2) w.SetContent(content) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
效果

标签容器(TabContainer)允许用户在不同的内容面板之间切换。标签可以是文本或图标。我们通过不同的方法创建不同位置的标签:
TabLocationBottom:显示在底部;TabLocationLeading:显示在顶部左边;TabLocationTrailing:显示在顶部右边。package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("TabContainer") label1 := widget.NewLabel("label1") label11 := widget.NewLabel("label11") label11.Hide() label2 := widget.NewLabel("label2") showCheck := widget.NewCheck("Hidden?", func(val bool) { if val { label11.Hide() } else { label11.Show() } }) b1 := widget.NewHBox( label1, label11, showCheck, ) b2 := widget.NewHBox( label2, ) tabs := widget.NewTabContainer( widget.NewTabItem("11", b1), widget.NewTabItem("22", b2), ) w.SetContent(tabs) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
效果

package main import ( "fmt" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/layout" "fyne.io/fyne/theme" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Toolbar") toolbar := widget.NewToolbar( widget.NewToolbarAction(theme.DocumentCreateIcon(), func() { fmt.Println("create new Doc") }), widget.NewToolbarSeparator(), widget.NewToolbarAction(theme.ContentCutIcon(), func() { fmt.Println("Cut") }), widget.NewToolbarAction(theme.ContentCopyIcon(), func() { fmt.Println("Copy") }), widget.NewToolbarAction(theme.ContentPasteIcon(), func() { fmt.Println("Paste") }), widget.NewToolbarSpacer(), widget.NewToolbarAction(theme.HelpIcon(), func() { fmt.Println("Display help") }), ) content := fyne.NewContainerWithLayout( layout.NewBorderLayout(toolbar, nil, nil, nil), toolbar, widget.NewLabel("show Toolbar"), ) w.SetContent(content) w.Resize(fyne.NewSize(150, 150)) w.ShowAndRun() } func main() { test() }
效果

下面我们通过扩展控件来让widget.Icon能够相应鼠标左键。
package main import ( "fmt" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/theme" "fyne.io/fyne/widget" ) type tappableIcon struct { widget.Icon } func newTappableIcon(res fyne.Resource) *tappableIcon { icon := &tappableIcon{} icon.ExtendBaseWidget(icon) icon.SetResource(res) return icon } type Tappable interface { Tapped(*fyne.PointEvent) } // 鼠标左键单机事件 func (t *tappableIcon) Tapped(e *fyne.PointEvent) { // 输出鼠标相对于串口的绝对位置(窗口的左上角),相对位置(容器的左上角) fmt.Println("tapped at", e) } func test() { a := app.New() w := a.NewWindow("Toolbar") w.SetContent(newTappableIcon(theme.FyneLogo())) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

布局(Layout)可以帮助我们在会使用控件的基础上,对控件的位置进行排版使之更加美观。
package main import ( "image/color" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/layout" ) func test() { a := app.New() w := a.NewWindow("Box Layout") h1 := fyne.NewContainerWithLayout( layout.NewHBoxLayout(), canvas.NewText("left", color.Black), layout.NewSpacer(), canvas.NewText("right", color.Black), ) h2 := fyne.NewContainerWithLayout( layout.NewHBoxLayout(), layout.NewSpacer(), canvas.NewText("left", color.Black), canvas.NewText("right", color.Black), ) w.SetContent(fyne.NewContainerWithLayout(layout.NewVBoxLayout(), h1, h2)) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

网格布局,我们通过layout.NewGridLayout(cols),传入每行的列数来创建。使用该布局时,当我们缩放界面时控件的大小会自动调整
package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) func test() { a := app.New() w := a.NewWindow("Grid Layout") img1 := canvas.NewImageFromResource(theme.FyneLogo()) img2 := canvas.NewImageFromResource(theme.FyneLogo()) img3 := canvas.NewImageFromResource(theme.FyneLogo()) w.SetContent(fyne.NewContainerWithLayout(layout.NewGridLayout(2), img1, img2, img3)) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

GridWrapLayout相当于时GridLayout的扩展版,我们可以在创建时指定每个子控件的size,当界面大小变化了这些子控件就会重新排列。
package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) func test() { a := app.New() w := a.NewWindow("Grid Layout") img1 := canvas.NewImageFromResource(theme.FyneLogo()) img2 := canvas.NewImageFromResource(theme.FyneLogo()) img3 := canvas.NewImageFromResource(theme.FyneLogo()) w.SetContent(fyne.NewContainerWithLayout(layout.NewGridWrapLayout(fyne.NewSize(100, 100)), img1, img2, img3)) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

从名字我们大致可以才出来,这是一种边框布局。当我们需要把控件设置在四个方向的边框上时可以使用,最典型的就是Toolbar的布局。
package main import ( "image/color" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/layout" ) func test() { a := app.New() w := a.NewWindow("Grid Layout") left := canvas.NewText("left", color.Black) right := canvas.NewText("right", color.Black) top := canvas.NewText("top", color.Black) bottom := canvas.NewText("bottom", color.Black) container := fyne.NewContainerWithLayout( layout.NewBorderLayout(top, bottom, left, right), top, bottom, left, right, ) w.SetContent(container) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

表单布局其实就是两列的GridLayout,但是做了一些微调。
package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/layout" "fyne.io/fyne/widget" ) func test() { a := app.New() w := a.NewWindow("Grid Layout") input1 := widget.NewEntry() input1.SetPlaceHolder("enter name") input2 := widget.NewEntry() input2.SetPlaceHolder("enter age") label1 := widget.NewLabel("Name") label2 := widget.NewLabel("age") container := fyne.NewContainerWithLayout( layout.NewFormLayout(), label1, input1, label2, input2, ) w.SetContent(container) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

CenterLayout就是将空间布局在容器的中心位置,按照传入的顺序,后面传入的控件可能会遮挡前面传入的控件。
package main import ( "image/color" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) func test() { a := app.New() w := a.NewWindow("Grid Layout") image := canvas.NewImageFromResource(theme.FyneLogo()) // 设置图片为填充模式,会尽可能占满容器 image.FillMode = canvas.ImageFillOriginal text := canvas.NewText("Fyne Logo", color.Black) container := fyne.NewContainerWithLayout( layout.NewCenterLayout(), image, text, ) w.SetContent(container) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

MaxLayout会让容器中的元素都显示为最大的尺寸。
package main import ( "image/color" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) func test() { a := app.New() w := a.NewWindow("Max Layout") image := canvas.NewImageFromResource(theme.FyneLogo()) text := canvas.NewText("Fyne Logo", color.Black) container := fyne.NewContainerWithLayout( layout.NewMaxLayout(), image, text, ) w.SetContent(container) w.Resize(fyne.NewSize(200, 200)) w.ShowAndRun() } func main() { test() }
效果

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。