[GIO] 如何在Golang中使列表中的所有小部件大小一致?

[GIO] 如何在Golang中使列表中的所有小部件大小一致? 我有一个列表,里面包含一些小部件,我希望它们都具有相同的大小。在Gio中如何实现?

最小可验证示例(列表中的按钮):

package main

import (
	"log"

	"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"
)

func main() {
	go func() {
		w := app.NewWindow(app.Title("MCVE"),
			app.Size(unit.Dp(400), unit.Dp(400)))
		if err := loop(w); err != nil {
			log.Fatal(err)
		}
	}()
	app.Main()
}

func loop(w *app.Window) error {
	th := material.NewTheme(gofont.Collection())
	labels := []string{"B1", "Button2"}
	buttons := make([]widget.Clickable, len(labels))
	widgets := make([]layout.Widget, len(labels))
	var ops op.Ops
	for {
		e := <-w.Events()
		switch e := e.(type) {
		case system.DestroyEvent:
			return e.Err
		case system.FrameEvent:
			gtx := layout.NewContext(&ops, e)
			layout.Flex{Axis: layout.Vertical, Spacing: layout.SpaceAround}.Layout(gtx,
				layout.Rigid(func(gtx layout.Context) layout.Dimensions {
					return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
						list := &layout.List{
							Axis:      layout.Vertical,
							Alignment: layout.Middle,
						}
						for i, label := range labels {
							widgets[i] = material.Button(th, &buttons[i], label).Layout
						}
						return list.Layout(gtx, len(widgets), func(gtx layout.Context, i int) layout.Dimensions {
							return layout.UniformInset(unit.Dp(0)).Layout(gtx, widgets[i])
						})
					})
				}),
				layout.Rigid(func(gtx layout.Context) layout.Dimensions {
					return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
						return material.H6(th, "Info").Layout(gtx)
					})
				}),
			)
			e.Frame(gtx.Ops)
		}
	}
	return nil
}

更多关于[GIO] 如何在Golang中使列表中的所有小部件大小一致?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

你是说文档还不够清楚吗? 😂 … 开玩笑的

更多关于[GIO] 如何在Golang中使列表中的所有小部件大小一致?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我是在调侃文档……不是说你。我觉得文档有点让人沮丧。

我只是觉得它还有很多不足之处。我打算这几天好好深入研究一下这个库。

我理解笑话 😛

好吧,他们至少尝试提供了一些东西 - https://gioui.org/doc/architecture

在Gio中使列表中的所有小部件大小一致,可以通过layout.Stacklayout.Rigid约束来实现。以下是两种解决方案:

方案1:使用layout.Stack强制统一尺寸

// 在列表布局函数中修改
return list.Layout(gtx, len(widgets), func(gtx layout.Context, i int) layout.Dimensions {
    // 使用Stack强制所有按钮具有相同的最小尺寸
    return layout.Stack{}.Layout(gtx,
        layout.Expanded(func(gtx layout.Context) layout.Dimensions {
            // 设置最小约束
            minSize := gtx.Constraints.Min
            minSize.X = gtx.Constraints.Max.X // 使用最大可用宽度
            minSize.Y = gtx.Dp(50) // 设置统一高度为50dp
            gtx.Constraints.Min = minSize
            
            return layout.UniformInset(unit.Dp(10)).Layout(gtx, widgets[i])
        }),
    )
})

方案2:使用自定义约束包装器

// 创建统一尺寸的包装函数
func uniformSize(gtx layout.Context, minWidth, minHeight unit.Dp, w layout.Widget) layout.Dimensions {
    // 保存原始约束
    original := gtx.Constraints
    
    // 设置新的最小约束
    gtx.Constraints.Min = layout.Pt(
        gtx.Dp(minWidth),
        gtx.Dp(minHeight),
    )
    
    // 执行小部件布局
    dims := w(gtx)
    
    // 恢复原始约束
    gtx.Constraints = original
    
    return dims
}

// 在列表中使用
return list.Layout(gtx, len(widgets), func(gtx layout.Context, i int) layout.Dimensions {
    return uniformSize(gtx, 200, 50, func(gtx layout.Context) layout.Dimensions {
        return layout.UniformInset(unit.Dp(10)).Layout(gtx, widgets[i])
    })
})

方案3:使用layout.Rigid和统一约束(推荐)

// 修改列表布局部分
for i, label := range labels {
    widgets[i] = func(btn *widget.Clickable, lbl string) layout.Widget {
        return func(gtx layout.Context) layout.Dimensions {
            // 设置统一的约束
            gtx.Constraints.Min = layout.Pt(
                gtx.Dp(150), // 统一最小宽度
                gtx.Dp(40),  // 统一最小高度
            )
            
            return material.Button(th, btn, lbl).Layout(gtx)
        }
    }(&buttons[i], label)
}

// 列表布局保持不变
return list.Layout(gtx, len(widgets), func(gtx layout.Context, i int) layout.Dimensions {
    return layout.UniformInset(unit.Dp(5)).Layout(gtx, widgets[i])
})

完整修改后的示例

package main

import (
    "log"

    "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"
)

func main() {
    go func() {
        w := app.NewWindow(app.Title("统一尺寸按钮"),
            app.Size(unit.Dp(400), unit.Dp(400)))
        if err := loop(w); err != nil {
            log.Fatal(err)
        }
    }()
    app.Main()
}

func loop(w *app.Window) error {
    th := material.NewTheme(gofont.Collection())
    labels := []string{"B1", "Button2", "按钮3", "Longer Button Text"}
    buttons := make([]widget.Clickable, len(labels))
    widgets := make([]layout.Widget, len(labels))
    
    var ops op.Ops
    for {
        e := <-w.Events()
        switch e := e.(type) {
        case system.DestroyEvent:
            return e.Err
        case system.FrameEvent:
            gtx := layout.NewContext(&ops, e)
            
            // 创建统一尺寸的小部件
            for i, label := range labels {
                widgets[i] = func(btn *widget.Clickable, lbl string) layout.Widget {
                    return func(gtx layout.Context) layout.Dimensions {
                        // 设置统一的最小尺寸约束
                        gtx.Constraints.Min = layout.Pt(
                            gtx.Dp(180), // 统一最小宽度
                            gtx.Dp(45),  // 统一最小高度
                        )
                        return material.Button(th, btn, lbl).Layout(gtx)
                    }
                }(&buttons[i], label)
            }
            
            layout.Flex{Axis: layout.Vertical, Spacing: layout.SpaceAround}.Layout(gtx,
                layout.Rigid(func(gtx layout.Context) layout.Dimensions {
                    return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
                        list := &layout.List{
                            Axis:      layout.Vertical,
                            Alignment: layout.Middle,
                        }
                        return list.Layout(gtx, len(widgets), func(gtx layout.Context, i int) layout.Dimensions {
                            return layout.UniformInset(unit.Dp(5)).Layout(gtx, widgets[i])
                        })
                    })
                }),
            )
            e.Frame(gtx.Ops)
        }
    }
}

关键点:

  1. 通过修改gtx.Constraints.Min设置统一的最小尺寸
  2. 使用闭包包装小部件以保持状态
  3. layout.Pt()函数用于创建尺寸点
  4. gtx.Dp()将设备独立像素转换为实际像素

这种方法确保所有按钮具有相同的最小尺寸,同时允许内容较长的按钮自动扩展。

回到顶部