Android阿拉伯适配rtl

概述

阿拉伯作为一个土豪帝国,android在sdk17(Android4.2)也开始支持RTL(right to left)布局了。镜像view等一些设计原则,都可以从官网找到。给出链接传送门
https://material.io/guidelines/usability/bidirectionality.html#bidirectionality-rtl-mirroring-guidelines

RTL布局

rtl布局的判断来自两个部分,一个是系统语言,还有一个就是AndroidManifest.xml中application结点中的supportRtl属性,只有当为true的时候,app才会支持镜像适配。

<application
     ...
     android:supportsRtl="true"
     />
</application>

布局的判断可以使用LayoutDirection.

总结一个函数就是这样的:

/**
* 判断是否进行阿拉伯镜像,判断取决于两个条件:<br />
* 一丶Androidmanifest.xml中的supportsRtl<br />
* 二、当前系统为阿拉伯语
*
* @return 是否为rtl
*/
public static boolean isRTL() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
  return false;
}

ApplicationInfo applicationInfo = BaseApplication.getInstance().getApplicationInfo();
boolean hasRtlSupport = (applicationInfo.flags & FLAG_SUPPORTS_RTL) == FLAG_SUPPORTS_RTL;
boolean isRtl = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
return hasRtlSupport && isRtl;
}

如何适配

在如何适配上,可以分几个方面:图标、xml属性、代码set方法、部分控件、自定义控件。

图标

图标大概是最直白的一个。back按钮,喇叭、进度条等等,都得反一下。新建一个drawable-ldrtl-xxhdpi目录统统扔进去。

image

image

ps:具体的可以参考之前的官网链接,里面讲的很清楚,只提一个重点,那么就是进度条,并不是所有的进度条都需要镜像,如果是多媒体播放的进度条,那么还是遵循从左往右的,例如视频等等,也可以参考youtube、facebook这样的app来看看。

xml属性

对于UI上的适配,大部分处理都是由布局xml来决定的,这里推荐使用Android Studio自带的“RTL Support”来优化。
鼠标右键编辑区域,Refactor->Add RTL Support Where Possible...

image
image

点击run后,会适配所有left和right相关的属性,一律换成start和end,值得注意一点的是,如果你的app要支持到17以下,那么写属性的时候,需要把两个方法都写上,这样才不会报错。

这里涉及到的相关属性包括:

LTR RTL
layout_marginLeft /layout_marginRight layout_marginStart/layout_marginEnd
paddingLeft/paddingRight paddingStart/paddingEnd
layout_alignLeft/layout_alignRight layout_alignStart/layout_alignEnd
layout_alignParentLeft/layout_alignParentRight layout_alignParentStart/layout_alignParentEnd
layout_toLeftOf/layout_toRightOf layout_toStartOf/layout_toEndOf
drawableLeft/drawableRight drawableStart/drawableEnd

ps:可能还有某些比较偏的属性,就不列出来了。这里还有一个比较特殊的gravity和layout_gravity,当app支持17以下的时候,可以直接使用start/end代替left/right,官方解释是start/end的字节码要大于left/right,所以你可以直接写成

android:gravity="start"

而不用写成

android:gravity="left|start"

还有一个就是textview,阿拉伯文字都是从右往左的,所以在阿拉伯语言下,如果出现英文中文或者数字,有时候还是会显示在左边。这里介绍一个属性“textDirection”。可以自由定义文字从哪一边开始显示。一般可以设置android:textDirection="locale"让它跟着系统语言走。控制view也有相同属性,叫作“layoutDirection”,可以控制view是否镜像(比如不想某些view发生镜像,可以通过设置这个属性来控制)。

======2018.01.17补充======

今天发现,<include..>标签里的属性,不会被Refactor->Add RTL Support Where Possible...适配~

代码set方法

这个就很好理解了,xml属性里用到的,代码设置里也需要适配一下。同样,支持17以下的话,需要适配版本,话不多说,直接上代码

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
   params.setMarginEnd(0);
} else {
   params.rightMargin = 0;
}

这里涉及到的相关方法包括:

LTR RTL
.leftMargin /.rightMargin setMarginStart/setMarginEnd
setPadding setPaddingRelative
setCompoundDrawablesWithIntrinsicBounds setCompoundDrawablesRelativeWithIntrinsicBounds
setCompoundDrawables setCompoundDrawablesRelative

ps:可能有些比较偏的函数,这里也不列出来了。还有就是给recyclerview设置ItemDecoration的时候,left/right要区分RTL。

部分控件

虽然Android说是支持了RTL,但是还是有一些常用的控件,没能做到适配,这里列举我遇到的两个。viewpager和tablayout(tablayout继承HorizontalScrollView)。

viewpager主要就是手势和view child的交互问题,很简单,网上已经有大神给出了解决方案,大致就是对数据源进行反转,上github链接
RtlViewPager

HorizontalScrollView的问题主要就是,有时候会发生初始状态不在0位置。这里的解决方案是,计算所有child的宽度总和,然后scroll一下就行了。当然,没那么笨,因为HorizontalScrollView里面只能放一个layout,只要计算这个一个layout的宽度就行了。这个问题的原因暂时还没看源码,但是估计是因为,当HorizontalScrollView add完所有的child的时候,会停留在最后,然后执行一波scrollTo(0),让队列回到最前面,但是对于RTL的布局来讲,0位置恰恰就是最后,因此就会出现初始状态不在0位置的问题。

/**
* @author tong.xu
* fix rtl下,tablayout初始化后,不是停留在初始位置的bug
*/
final int scrollX = mTabLayout.getChildAt(0).getMeasuredWidth();
if (CommonUtil.isRTL() && scrollX != 0) {
  mTabLayout.post(new Runnable() {
      @Override public void run() {
        mTabLayout.scrollTo(scrollX, 0);
    }
  });
}

自定义控件

大概这一部分是最难改的了,为什么这么说呢,因为它大概集成了上述所有的问题,并且还要结合自定义控件的逻辑去修改。如果是当初自己写的还稍微好点儿,要是别人写的,还要去读懂实现的逻辑,那是非常耗时费劲的,还容易出bug,所以建议还是谁挖的坑,谁来补(哈哈_,不厚道地笑了)。

简单说说怎么改的入手点吧。首先弄明白rtl和正常的布局有什么不同,比如getLeft(),getX(),X坐标上的变动基本都是要反的,就像之前的HorizontalScrollView,什么滚动啊之类的,都要注意。我来举个最简单的例子,画一个刻度尺。

6.png

一格的刻度大小为

int cell = (Screen.width - 2*x) / 2;

ltr:1的x坐标是x,2是x + cell,3是x + 2 * cell
rtl:(这个时候就要从最右算过来)1的x坐标是Screen.width - x,2是Screen.width - x - cell,3是Screen.width - x - 2 * cell

各个值 LTR下的x坐标 RTL的x坐标
1 x Screen.width - x
2 x + cell Screen.width - x - cell
3 x + 2 * cell Screen.width - x - 2 * cell

看起来是不是一点儿也不麻烦,当然我这个只是一个最简单的例子,当各种逻辑混起来的时候,肯定还会复杂,我这里只给一个思路,具体的还是要靠自己去适配了。

补充(重点,很容易出现的问题)

如果在wrap_content的布局里,放置一个centerInParent的子view,或者是相对应垂直/水平方向的高宽(例如父布局的宽为warp_content,子view使用了centerInHorizontal),在RTL环境下,会导致子view宽高放大,进而影响相邻的view,可能会挤出去,最后看不到。看了一下源码,warp_content在rtl情况下并没有做适配,查看layout的时候,发现宽高变成了65536。。。具体可以看源码对wrap的计算。

总结

总结一下吧,阿拉伯适配对于一个国际化的公司其实还是很重要的,尤其是阿拉伯石油大亨,用户价值还是很高的。适配的操作步骤,按照上述方法一步步下来,先适配简单的,再适配困难的,个别问题再个别处理,一套下来适配个90%基本都是没有问题的。好了,就讲到这里吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349