呜呼,伊朗的项目终于做完了,大部分都是在整理右到左布局的需求。好在android sdk 从API17(Android4.2)开始支持右到左布局的需求,但是会有很多坑需要去填。
  Android中的大部分组件是支持右到左布局的,只需要在Androidmanifest中配置如下:

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

我们先看一个demo,MainActivity对应的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.test.activity.MainActivity"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"android:background="@color/fastlane_background"/><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center_vertical"android:text="hello world "android:background="@color/selected_background"/>
</LinearLayout>

我们可以动态设置系统的语言来模仿用户环境,如下将app的配置设置为波斯语,当然,最简单的是到手机设置中直接设置当前语言为波斯语(设置有风险,语言需谨慎~~):

@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Locale locale = new Locale("fa_IR");//fa_IR是波斯语(伊朗)的代码Locale.setDefault(locale);Configuration config = new Configuration();config.locale = locale;DisplayMetrics dm = getResources().getDisplayMetrics();getResources().updateConfiguration(config, dm);setContentView(R.layout.activity_main);}

以下是没有加android:supportsRtl="true"的布局,很正常不过的布局吧?

那么加了之后呢?

显然toolbar的内容已经反过来了。且慢,textview好像没有任何变化?_?,难道textview不支持右到左布局?

1、textview gravity的右到左布局适配

大家知道textview有一个gravity的属性,其中可以通过以下两种方式指定textview的内容在左边还是在右边
  1) left,right:绝对位置,指定内容显示在textview的左边还是右边,这个比较好理解
  2) start,end:这个大家应该见过,该值作用的结果与系统布局方向有关,如下所示:

  举一反三,drawableStart,drawableEnd和layout_marginStart,layout_marginEnd以及layout_toStartOf,layout_toEndOf等也是同理,都是相对布局方向而言的。
  有同学马上就会想到,直接指定textview的gravity为start不就解决上面的问题了嘛!修改后的textview如下:

    <TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center_vertical|start"android:text="hello world "android:background="@color/selected_background"/>

效果如下:

不对啊,这不按套路出牌呀。内容怎么还是在左边。。。
同学们发现没有,内容是英文的,而伊朗是用波斯语言,会不会与语言有关呢?我们再加一个textView显示波斯语言的:

<TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:background="@color/fti_left_color"android:gravity="center_vertical|start"android:text="فارسی" />

结果如下:

是不是反过来了?由于波斯语言是右到左显示的,所以其内容也是默认居右边的。这说明,textview 的内容布局位置与文字显示的方向相关的。为了与伊朗用户的用户习惯保持一致,就算textview的内容是英文的,也应该居右边显示,那么如何做到呢?
Android提供了Java代码动态获取当前布局方向,如下:

    /*** * @param context* @return 如果是右到左布局,返回true*/public boolean isRtl(Context context) {return context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;}

然后我们可以通过该方法设置textView的gravity

        textView.setGravity(isRtl(this) ? Gravity.RIGHT:Gravity.LEFT);

结果大家显然都知道了,这里就不列出来了。
但是这样还是觉得很麻烦,有没有更便捷的属性?有!

name description 描述
android:layoutDirection attribute for setting the direction of a component’s layout 设置组件的布局排列方向
android:textDirection attribute for setting the direction of a component’s text 设置组件的文字排列方向
android:textAlignment attribute for setting the alignment of a component’s text 设置文字的对齐方式
getLayoutDirectionFromLocale() method for getting the Locale-specified direction 获取指定地区的惯用布局方式

其中,android:layoutDirection和android:textDirection的值有:

value type description
inherit int Horizontal layout direction is inherited
继承水平方向
rtl int Horizontal layout direction is from Right to Left
布局方向是右到左
ltr int Horizontal layout direction is from Left to Right
布局方向是左到右
locale int Horizontal layout direction is deduced from the default language script for the locale
从区域设置的默认语言脚本推导出水平布局方向

android:textAlignment的值有:

Constant value Description
center 4 Center the paragraph, for example: ALIGN_CENTER.
居中
gravity 1 Default for the root view. The gravity determines the alignment, ALIGN_NORMAL, ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction.
由view通过gravity属性定义对齐方式
inherit 0 Default.
默认
textEnd 3 Align to the end of the paragraph, for example: ALIGN_OPPOSITE.
与段落的末尾对齐
textStart 2 Align to the start of the paragraph, for example: ALIGN_NORMAL.
与段落的开头对齐
viewEnd 6 Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved layoutDirection is LTR, and ALIGN_LEFT otherwise.
与view的末尾对齐,
viewStart 5 Align to the start of the view, which is ALIGN_LEFT if the view’s resolved layoutDirection is LTR, and ALIGN_RIGHT otherwise.
与view的开头对齐

还是原来的布局,这里多加一行

  <TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:background="@color/selected_background"android:gravity="center_vertical|start"android:textDirection="locale"android:text="hello world " />

效果如下

要给辣么多个textview添加该属性,多麻烦!没事,有全局的设置~~

<resources><style name="AppTheme" parent="@style/Theme.AppCompat.Light.NoActionBar" ><item name="android:textViewStyle">@style/TextDirection</item></style><style name="TextDirection" parent="android:Widget.TextView"><item name="android:textDirection">locale</item></style>
</resources>

然后在Androidmanifest文件中引用该style

<application......android:supportsRtl="true"android:theme="@style/AppTheme">.......</application>

类似的还有EditText

<style name="AppTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">.....<item name="editTextStyle">@style/EditTextStyle</item></style><style name="EditTextStyle" parent="@android:style/Widget.EditText"><item name="android:textAlignment">viewStart</item><item name="android:gravity">start</item><item name="android:textDirection">locale</item></style>

2、组件之间的相对位置

在处理组件之间的相对位置,一般会用到layout_marginLeft,layout_marginRight或者layout_toLeftOf,layout_toRightOf等。那么如果你的app需要兼顾右到左布局的时候,这些布局约束就不合适了,需要用Start,End来代替Left,Right。天呐,如果有几十上百个布局文件,不是要改死程序员了么?别怕,Android studio已经为我们提供了一键适配右到左布局的需求,如下图所示

然后会弹出一个对话框,直接点击“run”

接着会提示你哪些需要添加适配属性的,直接点击“Do Refactor”

如果有不需要修改的,可以选中不修改的文件,或者某一行代码。选择Remove即可

这样我们的布局文件就自定添加start、end属性。
如果布局中使用了drawableStart或者drawableEnd属性就需要注意了,需要考虑图标是否需要跟随布局方向变化而变化,例如作为方向标示的就不应该变化位置,因此需要依旧使用drawableLeft和drawableRight

3、布局约束的右到左布局适配

在开发中,有时需要动态移动view的位置,一般的做法是修改view的layout,设置x,y轴或者设置marginLayoutParams等,当然还有一般的动画。
还是我们的mainActivity,对应的布局有两个textview1,textview2,点击textview2会修改textview1的位置,对应的代码如下:

    private TextView textview1, textview2;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
//        Locale locale = new Locale("fa_IR");
//        Locale.setDefault(locale);
//        Configuration config = new Configuration();
//        config.locale = locale;
//        DisplayMetrics dm = getResources().getDisplayMetrics();
//        getResources().updateConfiguration(config, dm);setContentView(R.layout.activity_main);textview1 = findViewById(R.id.textview1);textview2 = findViewById(R.id.textview2);}@Overridepublic void onClick(View v) {if (v.getId() == R.id.textview2) {ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) textview1.getLayoutParams();marginLayoutParams.leftMargin += 20 ;marginLayoutParams.topMargin += 10;textview1.setLayoutParams(marginLayoutParams);}}

效果如果,我们成功的移动了textview1

我们再解除被注释掉的代码,再试试看:

怎么没有往右下角移动?_? 不是已经设置了leftMargin了么,怎么只有topMargin有效?
在右到左布局下,Android的会从右到左依次绘制view,虽然我们设置了leftMargin,但是,系统在绘制view的时候会以rightMargin约束条件为准,如下图所示,所以就导致了leftMargin无效的问题。
需要注意的是,在右到左布局下,系统坐标并没有改变,getLeft,getTop,getX,getY等值没有发生变化。

所以,我们需要稍作修改

  @Overridepublic void onClick(View v) {if (v.getId() == R.id.textview2) {ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) textview1.getLayoutParams();marginLayoutParams.rightMargin += 20 ;marginLayoutParams.topMargin += 10;textview1.setLayoutParams(marginLayoutParams);}}

结果如下:

那如果在右到左布局下,textview的移动动画与左到右布局下一致呢?很简单,同时设置leftMargin和rightMargin即可:

    @Overridepublic void onClick(View v) {if (v.getId() == R.id.textview2) {int screenWidth = getWindowManager().getDefaultDisplay().getWidth() ;ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) textview1.getLayoutParams();marginLayoutParams.leftMargin += 20;marginLayoutParams.rightMargin = screenWidth- textview1.getWidth()-marginLayoutParams.leftMargin ;marginLayoutParams.topMargin += 10;textview1.setLayoutParams(marginLayoutParams);}}

效果如下

总结

1、如果使用到drawableLeft、drawableRight属性,请确定图标是否需要跟随系统布局方法改变而改变,如果是,请修改为drawableStart、drawableEnd;反之不用
2、在代码中需要动态修改view的布局约束,例如marginLayoutParams,layoutParams.setMargins()等,需要同时考虑left和right,或者采用修改layout的方式。
3、获取view的位置可以通过以下代码:

     int[] location = new int[2];view.getLocationOnScreen(location);float x = location[0];float y = location[1]

4、在relativelayout中添加layout rule的时候,用START_OF
、END_OF代替LEFT_OF、RIGHT_OF。
5、在右到左布局下,其坐标布局方式不变,getLeft,getRight等不变。变的是布局约束,view的绘制受right(start)约束。
6、一些方向图标,重新做一个相对方向的放到 drawable-ldrtl-xxxhdpi 包下
7、textview,editText需要对内容做RTL处理,设置style,详情见第一节
8、在显示文件路径时候,如果包含波斯语,会导致路径显示错误的情况,需要在string的前后加上\u202D 和\u202C

        String content = "sdcard\\فارسی\\3D\\فارسی.mp3";textview1.setText("\u202D"+content+"\u202C");

或者使用如下代码

public String getLTRString(String content) {return BidiFormatter.getInstance().unicodeWrap(content, TextDirectionHeuristics.LTR);}

实际显示如下:

9、如果需要修改view的位置,请不要使用setX,setY方式。推荐采用ViewGroup.MarginLayoutParams来设置margin,或者采用layout的方式。同时需要注意该约束是相对父view而言的。

android适配右到左布局注意事项相关推荐

  1. android 布局排排,[android]如何使LinearLayout布局从右向左水平排列,而不是从左向右排列...

    方法1:利用android:layout_weight android:layout_width="match_parent" android:layout_height=&quo ...

  2. 如何使LinearLayout布局从右向左水平排列,而不是从左向右排列

    方法1:利用android:layout_weight <LinearLayout xmlns:android="http://schemas.android.com/apk/res/ ...

  3. android 居右属性,使用layoutDirection属性设置布局靠左或靠右

    通过设置layoutDirection属性值为mx.core.LayoutDirection.RTL(右到左)或mx.core.LayoutDirection.LTR(左到右),使布局为靠左或靠右(如 ...

  4. android ui布局适配,Android适配全面总结(一)----屏幕适配

    前言 Android适配是一个老生常谈的问题,很多程序员觉得很恶心,不愿意做适配,但是又不得不做.然后老板说,这位兄弟,做好了,今天晚饭给你加个鸡腿,然后程序员开始找各种资料,忙活起来了,最终在苦逼的 ...

  5. Android直播软件搭建左滑右滑清屏控件

    Android直播软件搭建左滑右滑清屏控件 最近在迭代直播软件搭建功能时,项目中之前的左滑清屏是用ViewPager实现的.这次迭代遇到一个布局层次导致的点击失效问题,继续用ViewPager的话改动 ...

  6. Android反向进度条(ProgressBar)的实现——从右到左的进度条

    Android反向进度条(ProgressBar)--从右到左的进度条 前言: 最近在项目中需要使用到反向进度条,在网上查了些资料,感觉对自己作用不大,于是自定义样式,实现了反向进度条. 1. 第一步 ...

  7. android 波斯文排序,Android 4.2原生支持从右到左的文字排列格式

    Android 4.1(Jelly Bean) 在 TextView 和 EditText 元素里对"双向文字顺序"提供了有限的功能支持,允许应用程序在编辑和显示字符的时候,能够同 ...

  8. Android ProgressBar 反向进度条/进度条从右到左走

    近期的项目,有个需求须要使用条状图显示比例,而且右对齐,见下图: 我想到了使用进度条,这样不就不须要在代码动态绘制条状了,省了非常多活. 那么进度条如何从右向左显示呢? 方案一: 将ProgressB ...

  9. android tablerow 间隔,android-如何使TableRow从右到左

    如何从右到左向TableRow添加视图?默认模式为从左到右.我在TableLayout和TableRow中都尝试了android:gravity =" right"和android ...

最新文章

  1. 作为一名准程序员,谈一下现实和未来
  2. IX1000系统信息收集
  3. 华为USG地址池方式的NAPT和NAT Server配置案例
  4. 知道你用linux可视文件系统为什么搜索不到文件吗?(隐藏文件夹搜不到!!要用find . -name “xxx“命令)
  5. 如何发送html email,如何发送HTML电子邮件?
  6. 吴恩达作业10:用卷积神经网络识别人脸happy(基于Keras)
  7. dbml mysql_MySQL数据库笔记二:数据类型及数据库操作
  8. iPhone XR再降价:64GB到手最低仅需4149元
  9. 【选手分享】你想知道的比赛思路这里都有!速查收!
  10. 23种设计模式(二十二)行为变化之命令模式
  11. java sftp工具类_Java代码--SFTP工具类
  12. 播放html5视频黑屏,播放视频黑屏 · Issue #91 · surmon-china/vue-video-player · GitHub
  13. ERP软件实施要提供那些环境条件
  14. ubuntu安装wine版微信
  15. Linux系统下查看dsdt table
  16. 微信内网页链接被多人投诉导致拦截的解决方案
  17. 修改华为路由器lan端口
  18. Android第三方SDK集成 —— 极光推送
  19. linux解压zip、tar压缩包
  20. STM32三种BOOT模式

热门文章

  1. python入门必备指南-致Python初学者 Anaconda入门使用指南完整版
  2. mysql中创建用户并授权_MySQL中创建用户及授权[转]
  3. python面向对象类属性_python面向对象之类属性和类方法案例分析
  4. 利用CStopWatch计算并显示小车运行速度
  5. ege函数库_EGE图形库|EGE图形库下载v12.11 最新版 附使用教程 - 欧普软件下载
  6. C# .net core 解决ToLower中缺少CultureInfo格式重载
  7. 移动端手势操作--两点同时点击的实现方案
  8. 设置共享,实现Linux和Windows之间的共享
  9. POJ 3982 序列 塔尔苏斯问题解决
  10. JSTL 格式化 BigDecimal对象