什么是RTL布局
RTL布局是针对中东地区的书写习惯适配的一套从右向左的布局方式,字面意思就是Right-to-Left
.
针对iOS9之后的RTL适配,苹果有一个官方文档教我们怎么做适配。
举个例子对比:

在Xcode的项目图标点击Edit Scheme
->Run
->Options
,找到Application Language
,可以指定app运行时的语言环境, 就不需要手动进入设置修改系统语言了.
如下图:

开始适配
切换RTL布局
一般我们做了阿拉伯语言的适配之后, 用户只要系统语言是阿拉伯语言环境, 系统就会自动帮我们的app设置为RTL布局. 但是有一种情况是比如产品需要我们添加一个app内切换语言的功能, 其中就包括阿拉伯语言. 这时App语言不一定跟系统语言保持一致, 也许系统是英文,App内部设置成了阿拉伯语. 我们依然需要变成RTL布局,系统是不会帮我们完成这项任务的,我们只有自己来设置RTL.
由于目前我们的项目iOS支持版本是从iOS9开始, 正好iOS9之后系统提供了相应的API, 可以来强行将视图的布局切换为RTL布局.
1 | typedef NS_ENUM(NSInteger, UISemanticContentAttribute) { |
UView
有一个semanticContentAttribute
的属性,当我们将其设置成UISemanticContentAttributeForceRightToLeft
之后,UIView
将强制变为RTL布局。当然在非RTL语言下,我们需要设置它为UISemanticContentAttributeForceLeftToRight
,来适配系统是阿拉伯语,App是其他语言不需要RTL布局的情况。
一般情况下, 我们设置[UIView appearance]
的semanticContentAttribute
属性就能达到绝大部分视图的RTL布局效果, 因为基本所有视图都继承于UIView
.
1 | [UIView appearance].semanticContentAttribute = UISemanticContentAttributeForceRightToLeft; |
使用[UIView appearance]
设置后,大部分的View
看上去正常了。除了搜索栏。使用[UIView appearance]
设置后,搜索栏是不生效的。不过不用担心,我们只需要设置一下[UISearchBar appearance]
即可.
1 | [UISearchBar appearance].semanticContentAttribute = UISemanticContentAttributeForceRightToLeft; |
布局适配
Autolayout 约束布局
设置完view
的semanticContentAttribute
后,如果使用的是Autolayout
布局,并且Autolayout
下,使用的是leading
和trailing
,系统会自动帮助我们调整布局,将其适配RTL。但是如果使用的是left
和right
,系统是不会这么做的。
所以为了适配布局,我们需要将所有的left
,right
替换成leading
和trailing
。
如果使用了可视化编程, xib
或者storyboard
上面添加的约束本身就是使用的leading
和trailing
, 所以项目中如果使用了可视化的视图, 是会自动适配RTL布局的.
注意:同一个view不要同时使用left
, right
和leading
, trailing
属性, 会crash
崩溃.
Frame布局
目前我们项目中主要是Masonry和Frame两种布局混用的方式. Masonry就是上面约束的修改方式就可以完成适配.
对于Frame布局, 其实就是重新计算frame.origin.x
, 因为RTL模式下, 改变只是x
轴的起点, y
和视图的size
是不变的. 而且对于一个view
, 如果知道它的父视图的width
, 就可以计算出view
在RTL模式下的frame
, 所以我们可以给UIView
封装一个分类category
:
1 |
|
这样我们只需要在使用了Frame布局的地方, 添加一句类似如下的代码:
1 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 300)]; |
就可以完成Frame布局的适配.
从适配的工作量来讲, Frame要比Autolayout繁琐一些, 所以建议以后的新代码, 建议能用Masonry的就用Masonry, 而且要用leading
和trailing
属性.
图片镜像
由于一些图片素材, 在RTL下是需要镜像反转的, 比如个人中心cell
上的箭头, 我们如果没使用系统自带的, 而是用的图片素材, 那么正常模式下, 箭头是向右的, RTL模式下就需要将它镜像朝右.
系统针对这种情况提供了一个镜像的方法:
1 | // Creates a version of this image that, when assigned to a UIImageView’s image property, draws its underlying image contents horizontally mirrored when running under a right-to-left language. Affects the flipsForRightToLeftLayoutDirection property; does not affect the imageOrientation property. |
但是这个方法并不好用。通过切换系统语言,来适配RTL应该是没问题的。但是在App内部切换语言,手动修改RTL布局,系统的这个方法就经常出现错误镜像的情况。
所以我们可以再给UIImage
写一个镜像的分类来达到相同的效果:
1 | - (UIImage *)rtl_orientationUpMirrored { |
Label的textAlignment
在iOS9之后UILabel
的textAlignment
是NSTextAlignmentNatural
, 这个属性在正常语言环境下是居左的, 在RTL下则是居右的, 会自动适配RTL.
1 | Use the default alignment associated with the current localization of the app. The default alignment for left-to-right scripts is NSTextAlignmentLeft, and the default alignment for right-to-left scripts is NSTextAlignmentRight. |
但是有时当我们在系统内切换语言的时候,系统经常会错误的设置textAlignment
。所以我们需要自己去适配textAlignment
.
以UILabel
为例,我们hook
它的初始化方法,根据当前是否是RTL,给它一个正确的默认值:
1 |
|
总结
其实根据下面的参考文章, 还有一些点需要适配, 但是根据目前项目中遇到的情况, 以上过程, 基本项目中大部分的页面都可以完成RTL的适配.
参考文章:
RTL适配历程
阿拉伯语言的自动适配