Skip to content

从右到左 ​

阿拉伯语、希伯来语、波斯语和乌尔都语从右向左阅读,这些语言的应用界面也是如此:行从右侧开始,侧边栏在右侧,返回箭头指向右。当应用的语言从右向左阅读时,原生 UI 会据此布局窗口,就像 Flutter 的 Directionality、SwiftUI 的 layoutDirection、CSS 的 direction 和 GTK 的文字方向那样。坐标系不会被镜像(Godot 也是如此):在 Rect 中、在 Draw 绘制的内容中以及指针位置中,X 仍然向右增长。被镜像的只有布局。

方向 ​

ui.LeftToRight 和 ui.RightToLeft 是两种方向(ui.Direction)。窗口采用应用语言的方向,由 mygo 包提供;每个元素采用其所在父元素的方向。Direction 可以让一个元素及其内部构建的内容拥有自己的方向,例如在从右向左的窗口中保持从左向右的电话号码、代码示例或媒体播放器控件:

go
ui.Row(c).Direction(ui.LeftToRight).Gap(8).Children(func() {
	ui.Button(c, "⏮")
	ui.Button(c, "⏯")
	ui.Button(c, "⏭")
})

要在创建元素之后、构建其子元素之前立即设置它,就像 Key 一样:控件在构建时读取方向。附加到元素的弹窗(弹出面板、组合框的选项、工具提示)以及 Overlay 构建的内容,采用其被请求处的方向。

Context.Direction 返回当前构建内容的方向,供你自己的控件在绘制沿线指向的内容时使用:

go
forward := "M5 2 11 8 5 14"
if c.Direction() == ui.RightToLeft {
	forward = "M11 2 5 8 11 14"
}

会被镜像的内容 ​

从右向左时:

  • Row 从右侧开始排列子元素,Column 从右侧开始横向对齐子元素:Justify、AlignItems 和 AlignSelf 的 Start 和 End 随方向而定。Reverse 让行从左侧开始排列。网格从右侧放置列,JustifyItems 和 JustifySelf 从单元格的右侧开始。
  • 无论文本以何种方向阅读,TextAlign 的 Start 都是元素的右侧,正如 CSS、AppKit 和 GTK,End 则是左侧。段落按其第一个强方向字符的方向阅读,即 Unicode 双向算法判定的方向;不含强方向字符的段落(如数字或空行)从右向左。从左向右时一切不变:阿拉伯语段落仍从右侧开始,正如 Apple 的指南按语言对齐段落那样。
  • 逻辑边缘的起始侧在右边:PaddingStart、PaddingEnd、MarginStart、MarginEnd、BorderStartWidth、BorderEndWidth、定位元素的 Start 和 End(以及 StartPercent、EndPercent),以及锚点 AnchorTopStart、AnchorStart、AnchorBottomStart、AnchorTopEnd、AnchorEnd 和 AnchorBottomEnd,就像 CSS 的逻辑属性和 Flutter 的 EdgeInsetsDirectional 与 AlignmentDirectional。没有从任一侧定位的绝对元素会放到右侧;若同时给出 Left 和 Right 且宽度不足以容纳两者,则以 Right 为准。
  • 横向滚动从右侧开始,ScrollState.X 从那里计数(0 显示起始端,MaxX 显示末端),就像 Flutter 的偏移量;滚轮和触控板移动内容的方式与从左向右时相同,Shift+滚轮朝末端移动。垂直滚动条在左侧。
  • 控件会镜像沿线指向的部分:开关向左打开;滑块、范围滑块、进度条和仪表从右侧填充,其箭头按键按所指方向移动滑块;标签页、分段控件、工具栏、评分、网格视图和日历用 Left 键前进到下一项;展开箭头、面包屑的尖角、工具栏的溢出按钮和返回按钮指向左(返回则指向右);树、大纲和可展开项从右侧缩进,用 Left 键展开;分栏的第一个面板在右侧;表格的列从右侧开始,并从其左边缘调整列宽;路由器推入的页面从左侧滑入,Alt+Right 表示返回。
  • 弹出面板、选择框和组合框的选项、菜单按钮的菜单,都在唤起它们的元素的起始端打开;右键菜单按从右向左布局,并在指针左侧打开。
  • 在单行文本输入框中,文本从右侧开始,占位符也是如此,空输入框的光标也在那里。方向键按其指向的方向移动光标,无论文本是什么方向;Option(其他平台为 Control)和 Command 配合方向键,在从右向左的段落中按其所指的方向按单词移动和跳到行首行尾,正如 AppKit 和 GTK 的做法。

不会被镜像的内容 ​

  • 物理属性保持物理,正如 CSS:Left、Right、Padding(top, right, bottom, left)、BorderWidth、AnchorTopLeft、Radius 的各角、渐变的角度、变换。
  • 文本、图片、图标以及 Draw 绘制的内容不会被镜像:对勾、放大镜、加载指示器和图表与从左向右时一样。必须指向另一侧的内容,请在读取 Context.Direction 后自行绘制。
  • 代码始终从左向右阅读:代码编辑器和差异查看器(ui/editor)、Markdown 代码块和终端保持自己的方向,时间输入框也是如此,因为时间就是这么书写的。
  • 富文本编辑器(ui/richtext)按其文本的阅读方向对齐段落,正如文档的做法。
  • 检查器从左向右阅读。

试用 ​

MYGO_DIRECTION=rtl 让原生 UI 的每个窗口都按从右向左布局(ltr 则从左向右),无论应用使用什么语言,可在界面翻译完成之前先试用,正如 GTK 的 GTK_DEBUG=invert-text-dir 和 Qt 的 -reverse:

sh
MYGO_DIRECTION=rtl mygo dev

检查器的 RTL 开关可在运行时对其窗口做同样的事;Tester 在调用 SetDirection(ui.RightToLeft) 后会把窗口按从右向左布局,正如布局测试会做的那样:

go
tt := ui.NewTester(app.view, 400, 300)
tt.SetDirection(ui.RightToLeft)
back, _ := tt.Find("Back")
if back.X < 200 {
	t.Error("the back button is not at the right")
}

通过工具栏中的开关,示例画廊会以从右向左显示每个控件。