使用go-gio库示例tabs详解
包含的组件和功能
1、标签页的显示和设置
package main
import (
"fmt"
"image"
"image/color"
"log"
"math"
"os"
"gioui.org/app"
"gioui.org/f32"
"gioui.org/io/system"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"gioui.org/font/gofont"
)
var w *app.Window
func main() {
go func() {
defer os.Exit(0)
w = app.NewWindow(app.Title("tabSwitcher"))
if err := loop(w); err != nil {
log.Fatal(err)
}
}()
app.Main()
}
// 事件循环
func loop(w *app.Window) error {
th := material.NewTheme(gofont.Collection())
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)
drawTabs(gtx, th)
e.Frame(gtx.Ops)
}
}
}
var tabs Tabs // 标签
// Tabs 标签组
type Tabs struct {
list layout.List // 列表组件
tabs []Tab // 标签组件
selected int // 记录被选中的值
}
// Tab 子标签
type Tab struct {
btn widget.Clickable // 点击对象
Title string // 标题名称
}
// 初始化10个标签
func init() {
for i := 1; i <= 10; i++ {
tabs.tabs = append(tabs.tabs,
Tab{Title: fmt.Sprintf("Tab %d", i)},
)
}
}
// 设置上下文和组件的别名
type (
C = layout.Context
D = layout.Dimensions
)
// 标签界面
func drawTabs(gtx layout.Context, th *material.Theme) layout.Dimensions {
// 垂直布局
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx C) D {
return tabs.list.Layout(gtx, len(tabs.tabs), func(gtx C, tabIdx int) D {
// 获取当前的子标签组件对象
t := &tabs.tabs[tabIdx]
// 当前组件被点击后
if t.btn.Clicked() {
// 将当前值赋值为被选择的值
tabs.selected = tabIdx
// 刷新ui
w.Invalidate()
}
var tabWidth int // 标签宽度
return layout.Stack{Alignment: layout.S}.Layout(gtx,
layout.Stacked(func(gtx C) D {
// 创建一个可点击的小部件
dims := material.Clickable(gtx, &t.btn, func(gtx C) D {
// 12 宽度的组件
return layout.UniformInset(unit.Sp(12)).Layout(gtx,
// 显示标签的标题信息
material.H6(th, t.Title).Layout,
)
})
// 标签宽度等于当前组件的宽度
tabWidth = dims.Size.X
return dims
}),
// 选中提示条
layout.Stacked(func(gtx C) D {
// 当选中标签id不是当前标签id时隐藏提示条
if tabs.selected != tabIdx {
return layout.Dimensions{}
}
// 当选中标签id和当前标签id相等时,正常显示提示条界面
// 标签高度.将dp转换为int像素值
tabHeight := gtx.Px(unit.Dp(3))
// 矩形填充
tabRect := image.Rect(0, 0, tabWidth, tabHeight)
// 填充颜色
paint.FillShape(gtx.Ops, th.Palette.ContrastBg, clip.Rect(tabRect).Op())
return layout.Dimensions{
Size: image.Point{X: tabWidth, Y: tabHeight},
}
}),
)
})
}),
// 在下面的区域填充颜色
layout.Flexed(1, func(gtx C) D {
// 填充区域-设置颜色
fill(gtx, dynamicColor(tabs.selected), dynamicColor(tabs.selected+1))
// 中间显示信息
return layout.Center.Layout(gtx,
material.H1(th, fmt.Sprintf("Tab content #%d", tabs.selected+1)).Layout,
)
}),
)
}
// 填充区域
func fill(gtx layout.Context, col1, col2 color.NRGBA) {
dr := image.Rectangle{Max: gtx.Constraints.Min}
paint.FillShape(gtx.Ops,
color.NRGBA{R: 0, G: 0, B: 0, A: 0xFF},
clip.Rect(dr).Op(),
)
col2.R = byte(float32(col2.R))
col2.G = byte(float32(col2.G))
col2.B = byte(float32(col2.B))
paint.LinearGradientOp{
Stop1: f32.Pt(float32(dr.Min.X), 0),
Stop2: f32.Pt(float32(dr.Max.X), 0),
Color1: col1,
Color2: col2,
}.Add(gtx.Ops)
defer clip.Rect(dr).Push(gtx.Ops).Pop()
paint.PaintOp{}.Add(gtx.Ops)
}
// 动态的获取颜色
func dynamicColor(i int) color.NRGBA {
sn, cs := math.Sincos(float64(i) * math.Phi)
return color.NRGBA{
R: 0xA0 + byte(0x30*sn),
G: 0xA0 + byte(0x30*cs),
B: 0xD0,
A: 0xFF,
}
}