package main import ( "fmt" "image/color" "log" "os" "gioui.org/app" "gioui.org/font/gofont" "gioui.org/layout" "gioui.org/op" "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/text" "gioui.org/unit" "gioui.org/widget" "gioui.org/widget/material" ) // 定义侧边栏项目 type SidebarItem struct { Text string Btn widget.Clickable // 处理点击事件 ID int // 用于唯一标识每个项目 } // 应用状态 type AppState struct { SidebarItems []SidebarItem SelectedItemID int // 当前选中的项目ID SelectedItemID2 int } func main() { go func() { window := new(app.Window) window.Option(app.Title("Go Desk"), app.Size(unit.Dp(1200), unit.Dp(800))) err := run(window) if err != nil { log.Fatal(err) } os.Exit(0) }() app.Main() } func run(window *app.Window) error { theme := material.NewTheme() theme.Shaper = text.NewShaper(text.WithCollection(gofont.Collection())) // 初始化应用状态 var state AppState state.SelectedItemID = 1 // 默认选中第一个项目 // 初始化侧边栏项目 state.SidebarItems = []SidebarItem{ {Text: "仪表盘", ID: 1}, {Text: "文件", ID: 2}, {Text: "设置", ID: 3}, {Text: "帮助", ID: 4}, } // 初始化一个按钮组件 var btn widget.Clickable var ops op.Ops for { switch e := window.Event().(type) { case app.DestroyEvent: return e.Err case app.FrameEvent: // This graphics context is used for managing the rendering state. gtx := app.NewContext(&ops, e) // Define an large label with an appropriate text: title := material.H1(theme, "Hello, Gio") // Change the color of the label. maroon := color.NRGBA{R: 127, G: 0, B: 0, A: 255} title.Color = maroon // Change the position of the label. title.Alignment = text.Middle // 处理侧边栏按钮点击 for i := range state.SidebarItems { if state.SidebarItems[i].Btn.Clicked(gtx) { fmt.Printf("Item %d clicked\n", state.SidebarItems[i].ID) state.SelectedItemID = state.SidebarItems[i].ID // 更新选中状态 // 这里可以触发其他操作,如加载新的内容页面 } } // 开始绘制界面 layout.Flex{ Axis: layout.Horizontal, }.Layout(gtx, // 侧边栏 layout.Rigid(func(gtx layout.Context) layout.Dimensions { return drawSidebar(gtx, theme, &state) }), // 主内容区 (此处简化,仅显示文本) layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { return material.Body1(theme, fmt.Sprintf("当前显示的内容: Item %d", state.SelectedItemID)).Layout(gtx) }), ) // Draw the label to the graphics context. title.Layout(gtx) // 监听按钮点击事件 for btn.Clicked(gtx) { fmt.Println("按钮被点击了!") } // 使用布局中心化内容 layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { // 创建按钮并使用Material Design样式 return material.Button(theme, &btn, "点我").Layout(gtx) }) // Pass the drawing operations to the GPU. e.Frame(gtx.Ops) } } } // drawSidebar 绘制侧边栏 func drawSidebar(gtx layout.Context, th *material.Theme, state *AppState) layout.Dimensions { // 侧边栏背景和样式 sidebarBackground := func(gtx layout.Context, w layout.Widget) layout.Dimensions { return material.Background(gtx, "", w) /* 设置背景颜色 */ } return layout.Stack{}.Layout(gtx, layout.Expanded(sidebarBackground), layout.Stacked(func(gtx layout.Context) layout.Dimensions { // 使用列表布局排列侧边栏项目 list := layout.List{ Axis: layout.Vertical, } return list.Layout(gtx, len(state.SidebarItems), func(gtx layout.Context, index int) layout.Dimensions { item := &state.SidebarItems[index] // 根据是否选中决定样式 bgColor := "" /* 默认背景色 */ textColor := "" /* 默认文字颜色 */ if item.ID == state.SelectedItemID { bgColor = "" /* 选中时的背景色,例如 primary color */ textColor = "" /* 选中时的文字颜色,例如 on primary color */ } // 绘制可点击的按钮,应用选中的样式 return material.Clickable(gtx, &item.Btn, func(gtx layout.Context) layout.Dimensions { // 填充背景色 (选中与否颜色不同) return layout.Background{}.Layout(gtx, func(gtx layout.Context) layout.Dimensions { return fill(gtx, bgColor) }, func(gtx layout.Context) layout.Dimensions { // 添加边距和布局 return layout.Inset{Top: unit.Dp(5), Bottom: unit.Dp(5), Left: unit.Dp(10), Right: unit.Dp(10)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions { // 显示文字 label := material.Body1(th, item.Text) label.Color = textColor return label.Layout(gtx) }) }, ) }) }) }), ) } // fill 用指定颜色填充区域 func fill(gtx layout.Context, color color.NRGBA) layout.Dimensions { defer clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops).Pop() paint.ColorOp{Color: color}.Add(gtx.Ops) paint.PaintOp{}.Add(gtx.Ops) return layout.Dimensions{Size: gtx.Constraints.Max} }