NSGo

编写组件

部件与状态

不持有应用拥有的状态,开放每个部件的样式,并告诉辅助技术组件是什么。

无样式组件决定控件的行为,把外观留给使用者。本页按 base 构建控件的方式写一个 Toggle:一个可开可关的胶囊。

受控值

控件不持有应用拥有的值:应用以函数传入,并在回调中设置它。组件在显示它的地方读取,所以值变化时只有那一部分更新。

// Toggle is a pill that is on or off. Its parts are the pill and a dot
// inside it, then its children, the label.
type Toggle struct {
	On       func() bool
	Disabled func() bool
	// OnChange receives the value a press asks for, the opposite of On's.
	OnChange func(on bool)

	Class        string
	Style        core.Style
	StyleFunc    func() core.Style
	DotClass     string
	DotStyle     core.Style
	DotStyleFunc func() core.Style
	Children     []core.Node
	Label        string
}

应用把值放在 signal 里:chips.Toggle{On: bold.Get, OnChange: bold.Set, Label: "Bold"}。

部件

组件绘制的每个部件都有以部件命名的 Class、Style 和 StyleFunc(DotClass、DotStyle、DotStyleFunc)。Style 是固定的,StyleFunc 跟随它读取的 signal,class 位于两者之下,应用用哪种写法都可以。

部件通过 PartStates 取得控件的状态,而不是自己上报,这样 checked: class 和 Checked 样式会作用于它,而辅助技术看到的仍是一个控件:

func (t Toggle) Render(*core.Scope) core.Node {
	on := func() bool { return t.On != nil && t.On() }
	off := func() bool { return t.Disabled != nil && t.Disabled() }
	shows := func() core.PartStates { return core.PartStates{Checked: on(), Disabled: off()} }
	dot := core.View{Class: t.DotClass, Style: t.DotStyle, StyleFunc: t.DotStyleFunc, PartStates: shows}
	return core.View{
		Class: t.Class, Style: t.Style, StyleFunc: t.StyleFunc,
		Role: core.RoleSwitch, Label: t.Label, Checked: on, Disabled: t.Disabled,
		OnPress: func(core.PressEvent) {
			if t.OnChange != nil {
				t.OnChange(!on())
			}
		},
		Children: append([]core.Node{dot}, t.Children...),
	}
}

应用只用 class 就能给它样式:

chips.Toggle{
	On: bold.Get, OnChange: bold.Set, Label: "Bold",
	Class:    "flex-row items-center gap-2 rounded-full border border-zinc-300 px-3 py-1 checked:bg-blue-50",
	DotClass: "size-2 rounded-full bg-zinc-300 checked:bg-blue-500",
	Children: []core.Node{core.Text{Content: "Bold"}},
}

无障碍

控件的根视图说明它是什么:Role;文字没有说清时给出 Label;激活后会发生什么写在 Hint;适用时再加上 Checked、Selected、Disabled 或 Expanded。部件本身不发声。用方向键在条目间移动的控件只占一个 Tab 停靠点,像标签列表那样。角色和操作的列表见无障碍。

要透传的字段

根视图是自己的视图的组件,要接收并传下该视图的 OnLayout、Tooltip 和 TestID,让应用能像对待任何视图一样测量、提示和测试它。回调是可选的:OnChange 为 nil 时,控件只显示值而不改变它。

在 GitHub 上编辑此页