Ec73be280c1a556f2553918d7d9552e7
WWDC20 10219 - 使用Xcode构建有助于本地化的布局

如果想让自己的应用服务国际市场,本地化就是一个需要认真对待的问题。本地化不仅仅是将UI文案翻译成多国语言,还需要在布局上针对不同的语言进行适配。这个 session 介绍了一些布局的准则和利用 Xcode 帮助布局适配的技巧。

几个布局准则

不管是使用手动计算布局、Auto Layout 还是 Swift UI,一些布局准则是通用的。

1 包含文本的控件,不要使用固定尺寸

按钮上一句很短的英文,翻译成另一种语言可能会很长,需要更多的宽度。另外,有些语言字符的上下会有一些修饰符号,让整个字符比英语字符更“高”,比如缅甸语。因此控件高度最好也不要固定。

下面是一段缅甸语文本和相同字号的英语:
ဤလင့်ခ်ကို ပံ့ပိုးမပေးပါ This link isn't supported

使用 Auto Layout 来计算文本控件的尺寸,不要设置固定长度约束。如果使用Swift UI,避免显式设置 frame 为绝对值。

2 包含文本的控件之间,不要设置固定的间距

既然包含文本的控件尺寸是可变的,如果控件尺寸更大,间距就应该相应地更小,保证整个布局合适。

对于横向空间放置多个文本控件的场景,常见的布局方式是两边的控件到屏幕边缘设置固定的间距,中间的控件确定要“跟随”哪边来布局,最后留出一个可变间距,使用 greaterOrEqualTo 设置一个间距最小值。如图:

3 尽量允许文本多行显示

手机屏幕的横向空间本身很有限,如果文本本身较长,就需要允许文本折行布局。

众所周知,UILabel 默认是单行文本布局,设置 numberOfLines = 0 即可支持多行布局。

4 在有限的空间内不要放置太多的文本控件

例如在横向空间内放置多个文字按钮,文字稍长就容易因为空间不足而被截断。

Xcode 布局调试工具

Xcode 为开发者提供了一组调试工具,可以让开发者方便地调试布局在多种语言下的表现。

Document Preview

Document Preview 可以在多种屏幕尺寸、屏幕方向和语言条件下预览 Storyboard 布局的效果。

我们随便用 Storyboard 搭个界面:

在菜单中依次点击 Editor -> Preview ,即可打开 Document Preview。

点击右下角按钮可以切换预览语言:

分割线上方是项目支持的所有语言,不用多说。下面的几个 Pseudolanguage 是用来方便调试布局效果的“伪语言”。

第一个 Double-length Pseudolanguage 会让文本重复两次,方便预览在长文本下的布局适配效果。

我们尝试切一下,所有文本都买一送一了。

可以看到大标题被截断了,我们把这个 UILabelnumberOfLines 属性设置为0,让它自动折行。

其他的几种 Pseudolanguage 也很有趣,Emotional Pseudolanguage 会把所有的文本变成 Emoji:

Accented Pseudolanguage 会在字符上下加一些符号,这个在 Unicode 中叫做 Combining Diacritical Marks(组合附加符号)。有些语言(比如上面提到的缅甸语)会有这种符号,如上文所说,文本控件的高度也需要针对不同语言动态适配。

Scheme Options

对于使用代码自定义的布局效果,Document Preview 就有些力不从心了,我们需要把 App 实际跑起来验证。

我们看一下官方视频中提供的一个例子:

界面上四个按钮横向排开,用一个 UIStackView 包裹。横向空间很紧张,如果按钮文字再长一些势必被截断。用 Double-length Pseudolanguage 预览一下看:

这里苹果的工程师创建了一个 UIStackView 子类,当判断出横向空间不足以容纳所有子视图时,自动调整为纵向布局。

class ReadjustingStackView: UIStackView {

    ...

    override func layoutSubviews() {
        adjustOrientation()
    }

    @objc
    func adjustOrientation() {
        // Always attempt to fit everything horizontally first
        axis = .horizontal
        alignment = .firstBaseline

        let desiredStackViewWidth = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
        if let parent = superview {
            let availableWidth = parent.bounds.inset(by: parent.safeAreaInsets).width - (leadingConstraint.constant * 2.0)
            if desiredStackViewWidth > availableWidth {
                axis = .vertical
                alignment = .fill
            }
        }
    }
}

将 Storyboard 上的 UIStackView 改成这个 ReadjustingStackView,然后打开Edit Scheme -> Options,将 App Language 设置为 Double-length Pseudolanguage,再启动调试:

和预期中一样,按钮变成了纵向布局。

这里也体现了上文提到的布局原则4,在有限的空间内不要放置太多控件。如果 UI 需要横向排列多个按钮,可以考虑用图标代替文字,这样就不会有多语言适配问题了。

运行时 App 语言还可以设置为 Right-to-Left Pseudolanguage,可以模拟从右到左书写的语言,比如阿拉伯语、希伯来语。苹果官方的设计规范要求,当界面语言为从右到左语言时,整个界面布局需要左右镜像反转,原先左对齐的文本排版也要改为右对齐。这个伪语言选项在调试从右到左语言适配效果时非常有用。我们用这个选项把第一个 Demo 跑起来试一试:

top Created with Sketch.