外观
自定义控件
每个控件都构建在一个基座(base)之上,即同一个控件去掉外观后的样子: 基座处理指针、键盘和焦点,告诉辅助技术它是什么,而把颜色、尺寸和形状 完全交给它返回的元素,你可以像对其他元素一样为它们设置样式。在它们 之上构建你自己的设计,就像 Web 上的无头(headless)组件库那样。
| 基座 | 作用 |
|---|---|
ButtonBase | 一个可获得焦点的行,并在指针、Enter 和 Space 时报告 Clicked |
CheckboxBase、SwitchBase、ToggleBase | 一个切换 *bool 值的行 |
RadioBase | 一个把选中值写入 *T 的行 |
SliderBase | 根据指针在其内容盒(含内边距)上的横向位置设置 *float64,Vertical 时为纵向;并可用方向键、Page Up 和 Page Down、Home 和 End 按其 Step 调整 |
TabsBase | 标签 List,其 Tab 选择一个 *int,方向键移动选择项和焦点 |
SegmentedBase | 由 Segment 组成的 Track,一个选择 *int 的单选组 |
CollapsibleBase | 一个 Trigger 显示和隐藏 Panel 构建的内容,用 Progress 使其增长和收缩,取值从 0(收起)到 1(展开) |
SelectBase | 一个 Trigger 打开由 Item 组成的 Popup,选择 *T;方向键高亮(Highlighted),Enter 选中 |
ComboboxBase | 一个 Input,其文本过滤下方 Popup 的 Item;方向键高亮,Enter 或点击选择(Chosen) |
PopoverBase、DialogBase | 位于锚点旁边的面板,或覆盖整个窗口背景之上的面板,点击外部或按 Escape 关闭 |
TooltipBase | 当指针停留或键盘焦点位于锚点上时,在其旁边显示提示;点击或按 Escape 隐藏(工具提示) |
ToastViewportBase、ToastBase | 在你自己的视口里显示窗口的提示条,每条是一个带有 ActionButton 和 CloseButton 的状态;当指针或焦点位于其上时计时暂停(提示条) |
TextInputBase、TextAreaBase | 没有内边距、背景、边框或圆角的文本输入,可设为 ReadOnly 或不可 |
图表也有自己的基座:包 ui/chart提供没有外观的标尺、 坐标轴、标记和选择。
基座构造函数返回值形式的部件,其构建周期与其他元素相同。对有状态的 基座,在构造前用 Context.Key 给它一个键。
基于 SegmentedBase 的分段控件,以及基于 SelectBase 的选择器:
go
t := c.Theme()
view := ui.SegmentedBase(c.Key("period"), &app.view, 3)
view.Track.Padding(3).Radius(999).Background(t.Surface).Children(func() {
for i, name := range []string{"Day", "Week", "Month"} {
seg := view.Segment(i).Padding(5, 14).Radius(999)
if i == app.view {
seg.Background(t.Background).Shadow(0, 1, 2, 0, ui.RGBA(0, 0, 0, 0.15))
}
seg.Children(func() { ui.Text(c, name) })
}
})
sel := ui.SelectBase(c.Key("size"), &app.size)
sel.Trigger.Gap(6).Padding(6, 10).Radius(8).Border(1, t.Border).Children(func() {
ui.Text(c, app.size)
ui.Icon(c, chevron)
})
sel.Popup(func(panel ui.Element) {
panel.Margin(4, 0, 0, 0).Padding(4).Radius(10).Background(t.Background).Border(1, t.Border)
for _, size := range sizes {
item := sel.Item(size).Padding(6, 10).Radius(6)
if item.Highlighted() {
item.Background(t.Accent).TextColor(t.AccentText)
}
item.Children(func() { ui.Text(c, size) })
}
})基座会环绕获得键盘焦点的元素画出焦点环,与其他可聚焦元素一致;对于 自己绘制焦点环的控件,用 FocusRing(false) 关闭它,并在 FocusVisible 时用 Painter.FocusRing 自行绘制。
你自己的控件
对于带有自己的缓冲区或选区模型的文本控件,使用 HandleTextInput 与保留的文本几何。
从元素构建你自己的控件。元素用 ui.Local 在帧与帧之间保持自己的状态:
go
// Spoiler 隐藏文本,直到被点击。
func Spoiler(c *ui.Context, text string) {
t := c.Theme()
box := ui.Box(c).Padding(2, 6).Radius(4).Focusable()
shown := ui.Local(box, "shown", func() bool { return false })
if box.Clicked() {
*shown = !*shown
}
if *shown {
box.Background(t.Surface)
} else {
box.Background(t.Text) // 用文本的颜色,把它遮住
}
box.Children(func() { ui.Text(c, text) })
}当控件的输入改变了它所编辑的内容时,它在构建过程中通过其元素上的 SetChanged 报告这一点:此后 Changed 对它返回 true,与内置控件一致。 富文本编辑器就是这样做的。
为辅助技术给控件设置角色、名称和 状态;用其元素上的 Shortcut 获取它需要的 按键,或用 HandleInput 接收每一个 按键;元素没有绘制的内容用 Draw 来画。你自己的覆盖层, 如抽屉、悬停卡片和菜单,用 AttachTo 定位,用 PressedOutside 和 OverlayShortcut 关闭;Modal 把焦点保持在其中一个之内: 参见覆盖层。