You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

fyne.io组件定位故障:Move方法无法生效

Fyne文本组件定位问题求助

我正在使用Fyne开发一款简易天气应用,遇到了文本组件定位的问题。表单组件已成功实现距窗口边缘的定位,但下方的结果组件无法通过Move方法调整位置。

主文件代码

package main

import (
    "fmt"
    "weather-app/ui"
    "weather-app/utils"

    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/container"
)

func main() {
    prova, err := utils.MakeRequest("palermo", "it")

    if err != nil {
        panic(err)
    } else {
        fmt.Println(prova.Weather[0])
        fmt.Println(prova.Main)
        fmt.Println(prova.Sys)
        fmt.Println(prova.Dt)
    }

    app := app.New()
    window := app.NewWindow("Current Weather")

    customForm := ui.GenerateCustomForm()
    apiResults := ui.ShowApiResults("Cinisi", "20 °C")

    wrapper := container.NewGridWithRows(
        2,
        customForm,
        apiResults,
    )

    window.Resize(fyne.NewSize(445, 400))
    window.SetContent(wrapper)

    window.ShowAndRun()
}

UI模块代码

package ui

import (
    "fmt"
    "image/color"

    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/canvas"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/layout"
    "fyne.io/fyne/v2/widget"
)

func onSubmitFunc(city, country string) {
    fmt.Println("submit")
}

func GenerateCustomForm() *fyne.Container {
    //creating widgets
    cityEntry := widget.NewEntry()
    countrEntry := widget.NewEntry()
    button := widget.NewButton("Search", func() { onSubmitFunc(cityEntry.Text, countrEntry.Text) })

    //set placeholder in text input
    cityEntry.SetPlaceHolder("City")
    countrEntry.SetPlaceHolder("Country (optional)")

    //setting size
    cityEntry.Resize(fyne.NewSize(250, 40))
    countrEntry.Resize(fyne.NewSize(150, 40))
    button.Resize(fyne.NewSize(160, 40))

    //positioning
    cityEntry.Move(fyne.NewPos(10, 10))
    countrEntry.Move(fyne.NewPos(cityEntry.Size().Width+25, 10))
    button.Move(fyne.NewPos(10, 25))

    customForm := container.New(
        layout.NewVBoxLayout(),
        container.NewWithoutLayout(
            cityEntry,
            countrEntry,
        ),
        container.NewWithoutLayout(
            button,
        ),
    )

    return customForm
}

func ShowApiResults(city, temp string) *fyne.Container {
    text := canvas.NewText("Current weather in "+city, color.White)
    text.TextSize = 18

    temperature := canvas.NewText(temp, color.White)
    temperature.TextSize = 50

    //sample image
    r, _ := fyne.LoadResourceFromURLString("http://openweathermap.org/img/wn/09d@2x.png")
    image := canvas.NewImageFromResource(r)
    image.FillMode = canvas.ImageFillContain
    image.Resize(fyne.NewSize(100, 100))

    //wrap the components to have them on the same line
    tempAndImg := container.New(
        layout.NewGridLayout(2),
        temperature,
        image,
    )

    tempAndImg.Move(fyne.NewPos(20, 0)) //DOESN'T WORK

    apiResults := container.New(
        layout.NewVBoxLayout(),
        text,
        tempAndImg,
    )

    //i tried also this:
    //apiResults.Move(fyne.NewPos(20, 0)) --- but nothing

    return apiResults
}

我刚接触Fyne框架,恳请各位开发者帮忙解决该问题。


解决方案

问题根源

Fyne中,带布局的容器(如VBoxLayout、GridLayout)会自动管理子组件的位置和大小,手动调用Move方法的设置会被布局容器的计算结果覆盖。你之前的表单组件能生效,是因为它们被放在了NewWithoutLayout创建的无布局容器里,这种容器不会干预子组件的手动定位。

两种解决思路

思路1:用无布局容器手动定位(适合完全自定义位置)

把apiResults改成无布局容器,手动设置每个组件的位置:

func ShowApiResults(city, temp string) *fyne.Container {
    text := canvas.NewText("Current weather in "+city, color.White)
    text.TextSize = 18
    text.Move(fyne.NewPos(20, 10)) // 手动设置位置

    temperature := canvas.NewText(temp, color.White)
    temperature.TextSize = 50
    temperature.Move(fyne.NewPos(20, 40))

    //sample image
    r, _ := fyne.LoadResourceFromURLString("http://openweathermap.org/img/wn/09d@2x.png")
    image := canvas.NewImageFromResource(r)
    image.FillMode = canvas.ImageFillContain
    image.Resize(fyne.NewSize(100, 100))
    image.Move(fyne.NewPos(120, 40))

    // 使用无布局容器
    apiResults := container.NewWithoutLayout(
        text,
        temperature,
        image,
    )

    return apiResults
}

思路2:用布局容器添加边距(更符合Fyne最佳实践)

如果只是需要给组件添加左侧边距,推荐用layout.NewPaddingLayout或者嵌套容器,让布局自动处理位置:

func ShowApiResults(city, temp string) *fyne.Container {
    text := canvas.NewText("Current weather in "+city, color.White)
    text.TextSize = 18

    temperature := canvas.NewText(temp, color.White)
    temperature.TextSize = 50

    //sample image
    r, _ := fyne.LoadResourceFromURLString("http://openweathermap.org/img/wn/09d@2x.png")
    image := canvas.NewImageFromResource(r)
    image.FillMode = canvas.ImageFillContain
    image.Resize(fyne.NewSize(100, 100))

    tempAndImg := container.New(
        layout.NewGridLayout(2),
        temperature,
        image,
    )

    // 组合文本和温度图片容器
    content := container.New(
        layout.NewVBoxLayout(),
        text,
        tempAndImg,
    )
    // 使用PaddingLayout添加左侧20的边距,参数为上、右、下、左的边距值
    apiResults := container.New(layout.NewPaddingLayout(fyne.NewSize(0,0,0,20)), content)

    return apiResults
}

额外建议

  • 尽量避免手动Move和Resize组件,Fyne的布局系统是为了适配不同窗口尺寸和平台设计的,手动定位会导致窗口缩放时组件位置错乱。
  • 表单部分的实现也可以改用布局容器(比如GridLayout或HBoxLayout)替代手动定位,这样更符合框架设计理念,也能更好地适配不同屏幕。

内容的提问来源于stack exchange,提问作者Saverio Randazzo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 17:05:21