语言切换

语言种类

例如:

/*** 英国(英语)*/EN("en"),/*** 西班牙(西班牙语)*/ES("es"),/*** 西班牙(葡萄牙语)*/PT("pt"),/*** 法国(法语)*/FR("fr"),/*** 俄罗斯(俄语)*/RU("ru"),/*** 意大利(意大利语)*/IT("it"),/*** 德国(德语)*/DE("de"),/*** 荷兰(荷兰语)*/NL("nl"),/*** 阿拉伯(阿拉伯语)*/AR("ar"),/*** 韩国、朝鲜(韩语)*/KO("ko"),/*** 日本(日语)*/JA("ja");

代码切换App语言

更改context语言配置

@JvmStaticfun wrap(context: Context, newLocale: Locale): Context {return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {createConfigurationResources(context, newLocale)} else {applyLanguage(context, newLocale)context}}private fun applyLanguage(context: Context, newLocale: Locale) {val resources = context.resourcesval configuration = resources.configurationif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// apply localeconfiguration.setLocale(newLocale)} else {// updateConfigurationconfiguration.locale = newLocaleval dm = resources.displayMetricsresources.updateConfiguration(configuration, dm)}}@TargetApi(Build.VERSION_CODES.N)private fun createConfigurationResources(context: Context, newLocale: Locale): Context {val resources = context.resourcesval configuration = resources.configurationconfiguration.setLocale(newLocale)val localeList = LocaleList(newLocale)LocaleList.setDefault(localeList)configuration.setLocales(localeList)return context.createConfigurationContext(configuration)}

基类activity应用语言配置

open class BaseActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)}override fun attachBaseContext(newBase: Context) {super.attachBaseContext(LanguageUtil.wrap(newBase, Language.getCurrentLanguage()))}
}

LTR和RTL,适配阿语

RTL 语言由来
RTL 是 Right-to-left(从右向左) 的缩写。其意为人们书写阅读习惯是从右向左,朝左继续的,常见的 RTL 语言有阿拉伯语,希伯来语等。

全局API设置

从 Android 4.2 即 SDK 17 开始,提供了全面的本地布局支持,允许镜像布局,可以同时支持 RTL 和 LTR。

  1. Android Studio全局设置RTL

  2. AndroidManifest.xml

<application...android:theme="@style/AppTheme"android:supportsRtl="true">...
</application>
  1. 图片配置
    将RTL切图放在下图对应的文件夹内,可以实现阿语下图片的转换
  2. styles里的AppTheme对于TextView、EditText等控件的文本方向、对齐方式设置
    android:layoutDirection 设置组件的布局排列方向
    android:textDirection 设置组件的文字排列方向
    android:textAlignment 设置文字的对齐方式
 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">...<item name="editTextStyle">@style/AppTheme.EditTextStyle</item><item name="android:textViewStyle">@style/AppTheme.TextViewStyle</item><item name="android:autoCompleteTextViewStyle">@style/AppTheme.AutoCompleteTextView</item><item name="textInputStyle">@style/AppTheme.TextInputLayout</item>...</style><style name="AppTheme.EditTextStyle" parent="Widget.AppCompat.EditText"><item name="android:textAlignment">viewStart</item><item name="android:textDirection">locale</item></style><style name="AppTheme.TextViewStyle" parent="Widget.AppCompat.TextView"><item name="android:textDirection">locale</item></style><style name="AppTheme.AutoCompleteTextView" parent="Widget.AppCompat.AutoCompleteTextView"><item name="android:textAlignment">viewStart</item><item name="android:textDirection">locale</item></style><style name="AppTheme.TextInputLayout" parent="Widget.Design.TextInputLayout"><item name="android:textAlignment">viewStart</item><item name="android:textDirection">locale</item><item name="hintEnabled">false</item></style>

特别注意:在AppTheme中设置控件的文本方向和对齐方式,按道理是全局生效的。但是在实际使用中,并没有全局生效,这个时候需要在具体控件使用时进行单独设置

<TextView...style="@style/AppTheme.TextViewStyle".../><com.google.android.material.textfield.TextInputLayout...style="@style/AppTheme.TextInputLayout"...><MultiAutoCompleteTextView...style="@style/AppTheme.AutoCompleteTextView"... /></com.google.android.material.textfield.TextInputLayout>

关于Padding、Margin、setCompoundDrawables等带有方向属性的设置

通过Android Studio的RTL工具全局替换,XML里面发生的变化有:
paddingLeft -> paddingStart
paddingRight -> paddingEnd
marginLeft -> marginStart
marginRight -> marginEnd
layout_alignParentLeft -> layout_alignParentStart
layout_alignParentRight -> layout_alignParentEnd
drawableLeft -> drawableStart
drawableRight -> drawableEnd
layout_constraintLeft_toLeftOf -> layout_constraintRight_toRightOf
layout_constraintRight_toRightOf -> layout_constraintEnd_toEndOf

所以,在代码和styles中关于上述带有方向的属性需要手动修改
例如:

<resources>...<style name="XXX"><item name="android:layout_width">30dp</item><item name="android:layout_height">20dp</item><item name="android:layout_alignParentRight">true</item><item name="android:layout_alignParentEnd">true</item><item name="android:clickable">false</item><item name="android:layout_marginEnd">15dp</item><item name="android:layout_marginStart">15dp</item><item name="android:focusable">false</item></style>...
</resources>
...
enterBtn.setPaddingRelative(12F.dp2Px, 10F.dp2Px, 8F.dp2Px, 10F.dp2Px)
enterBtn.setCompoundDrawablesRelative(null, null, drawable, null)
...
    /*** 设置相对位置的margin*/fun <T : ViewGroup.MarginLayoutParams> T.setRelativeMargin(margin: MICMargin) {marginStart = margin.lefttopMargin = margin.topmarginEnd = margin.rightbottomMargin = margin.bottom}
(parent.layoutParams as ViewGroup.MarginLayoutParams).setRelativeMargin(24f.dp2Px, 7f.dp2Px, 7f.dp2Px, 7f.dp2Px)

部分重要控件适配

  1. ViewPager2
    相比于ViewPager,ViewPager2基于RecyclerView实现,支持垂直方向滚动,支持RTL。
    使用 ViewPager效果

    ViewPager实现的图片查看

    使用 ViewPager2效果

    ViewPager2实现的图片查看

  2. 流式布局(FlexBoxLayout)
    使用之前的自定义控件FlowLayout

使用谷歌官方的FlexBoxLayout


3. PopWindow

mPopupWin.showAsDropDown(targetView, 0, 0);

targetView应该为显示位置相对应的目标view

  1. Banner
public class BannerLocaleCircleIndicator extends BaseIndicator {private int mNormalRadius;private int mSelectedRadius;private int maxRadius;public BannerLocaleCircleIndicator(Context context) {this(context, null);}public BannerLocaleCircleIndicator(Context context, AttributeSet attrs) {this(context, attrs, 0);}public BannerLocaleCircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mNormalRadius = config.getNormalWidth() / 2;mSelectedRadius = config.getSelectedWidth() / 2;}...@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int count = config.getIndicatorSize();if (count <= 1) {return;}float left = 0;int currentPosition = LanguageUtil.isAR() ? count - config.getCurrentPosition() - 1 : config.getCurrentPosition();for (int i = 0; i < count; i++) {mPaint.setColor(currentPosition == i ? config.getSelectedColor() : config.getNormalColor());int indicatorWidth = currentPosition == i ? config.getSelectedWidth() : config.getNormalWidth();int radius = currentPosition == i ? mSelectedRadius : mNormalRadius;canvas.drawCircle(left + radius, maxRadius, radius, mPaint);left += indicatorWidth + config.getIndicatorSpace();}}
}

banner指示器currentPosition在阿语下需要count - config.getCurrentPosition() - 1,为镜像位置

适配阿语的banner

针对性兼容

  1. ImageView,字体图标TextView镜像
    /*** 将image、字体图标等控件镜像翻转*/fun <T : View> T.imageToRTL() {if (LanguageUtil.isAR()) {scaleX = -1f}}
  1. 和Drawable镜像
     /*** 设置镜像drawable*/fun <T : View?> T.setRtlBackgroundDrawable(drawable: Drawable?) {drawable?.isAutoMirrored = LanguageUtil.isAR()this?.backgroundDrawable = drawable}
  1. 动画方向
    在阿语下,X坐标轴方向会改变
     /*** 购物车动画** @param startView 动画的起点位置* @param endView   动画的终点位置* @param context* @param root      父窗体 用于添加的动画的View* @param time      动画持续时间单位s*/public static void AddToCart(final Context context, final View startView, final View endView, final RelativeLayout root, final Drawable bgDrawable, final float time) {if (context == null || (context instanceof Activity && ((Activity) context).isFinishing()) || startView == null || endView == null || root == null || bgDrawable == null)return;endView.postDelayed(new Runnable() {@Overridepublic void run() {//新建一个ImageView 用于动画显示final ImageView view = new ImageView(context);//确定ImageView大小与传进来的ImageView相同RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);//获取ImageView的图片 并设置在新的ImageView上view.setImageDrawable(bgDrawable);//计算父控件的位置int[] parent = new int[2];root.getLocationInWindow(parent);//计算起点控件位置int[] startLocation = new int[2];startView.getLocationInWindow(startLocation);if (LanguageUtil.isAR()) {startLocation[0] = FMFScreenUtil.getWindowWidth() - startLocation[0];}//计算终点控件位置int[] endLocation = new int[2];endView.getLocationInWindow(endLocation);if (LanguageUtil.isAR()) {endLocation[0] = FMFScreenUtil.getWindowWidth() - endLocation[0];}//确定ImageView的位置与startView相同params.setMarginStart(startLocation[0] - parent[0] - root.getPaddingStart());params.topMargin = startLocation[1] - parent[1] - root.getPaddingTop();root.addView(view, params);//计算两者的横向X轴的距离差int XtoX = endLocation[0] - startLocation[0]/* + endView.getWidth() / 2 - startView.getWidth() / 2*/ + endView.getWidth() / 2;//根据距离 时间 获取到对应的X轴的初速度final float xv = XtoX / time;//计算两者的横向X轴的距离差int YtoY = endLocation[1] - startLocation[1] + endView.getHeight() / 2;//根据距离 时间 初始设置的Y轴初速度与X轴初速度相同 获取到竖直方向上的加速度final float g;if (xv > 0) {g = (YtoY + xv * time) / time / time * 2;} else {g = (YtoY - xv * time) / time / time * 2;}final ValueAnimator va = new ValueAnimator();va.setDuration((long) (time * 1000));va.setObjectValues(new PointF(0, 0));//计算位置va.setEvaluator(new TypeEvaluator<PointF>() {@Overridepublic PointF evaluate(float v, PointF pointF, PointF t1) {PointF point = new PointF();point.x = v * xv * time;if (xv > 0) {point.y = g * (v * time) * (v * time) / 2 - xv * v * time;} else {point.y = g * (v * time) * (v * time) / 2 + xv * v * time;}return point;}});va.start();//设置动画va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {PointF point = (PointF) valueAnimator.getAnimatedValue();view.setTranslationX(point.x);view.setTranslationY(point.y);}});//在动画结束时去掉动画添加的ImageViewva.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animator) {}@Overridepublic void onAnimationEnd(Animator animator) {root.removeView(view);}@Overridepublic void onAnimationCancel(Animator animator) {}@Overridepublic void onAnimationRepeat(Animator animator) {}});}}, 100);}

React-Native RTL适配

  1. 图片RTL适配
import {isSA} from '@utils/common';const imagePath = {XXX: () => {return isSA()? require('@assets/img/XXX@rtl.png'): require('@assets/img/XXX.png');},XXXX: () => {return isSA()? require('@assets/img/XXXX@rtl.png'): require('@assets/img/XXXX.png');},
};export default imagePath;
                <ImageBackground...source={imagePath.member_center_footer_image()}>...</ImageBackground>

Android和iOS适配细节

问题类型 结论
排版总体整齐,个别文案显示错乱或者不规范 个别文案或者控件显示错乱不对齐时,按照整体页面的位置和方向进行对齐,可以考虑单独适配的技术实现方式。
阿语 英文混合出现,按照什么样式展示? 1.整体按照语言环境去显示位置,比如英语环境下,整体居左;在阿语环境下,整体居右。 2.英文单词本身还是按照英文顺序从左往右展示。
纯英文在阿语下按照什么样式展示? 1.整体按照语言环境去显示位置,比如英语环境下,整体居左;在阿语环境下,整体居右。2.按照英文单词顺序显示。
输入框输入光标,英文对齐方式 Android 1.光标英语环境下,居左;阿语环境下,居右。 2.阿语环境下,输入的文案,如果是英文,显示在左边;如果是阿语,显示在右边 。iOS 1.ios15以下,光标和输入内容都是居右显示。 2.ios15以上,光标和输入内容都是根据输入语言,英文居左,阿语居右。

Android国际化,阿语RTL适配总结相关推荐

  1. iOS 阿拉伯语 RTL适配

    阿拉伯语: 背景:阿拉伯语使用者占世界人口的6%,使用阿拉伯字母,为从右至左书写的文字,主要通行于18个阿拉伯国家及4个国际组织的官方语言.以阿拉伯语作为母语的人数超过2.6亿人.阿拉伯语在全球范围使 ...

  2. Android阿拉伯语UI适配问题汇总

    Android阿拉伯语UI适配问题汇总 Sensi Sun RTL和LTR LTR 是 Left-to-right(从左向右) 的缩写.(常用) RTL 是 Right-to-left(从右向左) 的 ...

  3. Android 国际化与本地化探索

    Android 国际化与本地化探索 1.翻译注意事项 1.1.尽量避免使用简写! 1.2.严禁回车.换行等! 1.3.尽量避免使用&.'."等特殊符号! 1.4.注意空格的使用! 2 ...

  4. Android 国际化

    由于公司的项目是投放 google play store , 所以要做国际化.国际化遇到的两个大问题 字符串国际化 布局样式国际化 一:字符串国际化        解决这个问题很简单,在res目录下放 ...

  5. android国际化语言编码对照表

    android国际化语言编码对照表 (查询整理以备不时之需,以下内容均已附原文连接) 中文(中国):values-zh-rCN 中文(台湾):values-zh-rTW 中文(香港):values-z ...

  6. 重拾Android之路(三)手机适配

    随着android智能手机的发展和普及,各种各样的大小和尺寸的android智能机不断的退出,通过各种各样的设备机型,我们能够让自己的APP接触到广大的用户.为了能在各种android平台上使用,我们 ...

  7. Unity阿拉伯语的适配(终极版)

    最近在做阿语的适配,发现网上并没有一套完整的方案,这次给大家带来一套完整的解决方案,并配上一套可扩展的代码,希望我们每个人以后再遇到阿拉伯语的适配的时候,可以使用这套终极解决方案来搞定.同时随着uni ...

  8. android屏幕适配的目的,Android 不同分辨率下屏幕适配的实战方案与经验总结

    Android 开发中,屏幕适配是一大考点,几乎每一场面试,都不会落下这个问题,这个问题说简单也简单,说难也难,当然对于有过真实的适配经验的人来说,这个根本不算什么问题,从坑里爬过的人,自然知道这其中 ...

  9. 技术实践 | Android 设备音视频兼容性适配

    导读:WebRTC 是一个非常优秀的项目, 可以支持 Web.iOS.Android.Mac.Windows.Linux 在内的所有平台的 API,保证了 API 在所有平台的一致性.然而 WebRT ...

最新文章

  1. 关于Bulk加载模式
  2. iOS自动打包并发布脚本
  3. sap.m.library acts as one of the two most core framework library
  4. 《TCP/IP详解》笔记----第四章 ARP协议
  5. 关于SpringBoot中的多数据源集成
  6. python安装beautifulsoup失败_Win10环境下python36安装BeautifulSoup出现错误的解决办法
  7. go 语言链接服务器上的mysql数据库
  8. 计算广告 pdf_他创业20年死磕PDF一项业务,如今上市身家76亿:所有的突然牛逼,背后都是玩命死磕...
  9. 天天打无人车是怎样一种体验?
  10. Focal Loss for Dense Object Detection解读
  11. Qt加载gif动态图
  12. 高校学生社团管理系统
  13. 2020计算机二级c语言答案,2020年全国计算机二级C语言考试试题分析
  14. 互联网快讯:龙佰集团冲刺港交所;极米Z6X Pro、极米H3S持续热销;京东物流调集3246人增援上海
  15. Plsql ORA-00054的解决方法
  16. 白硕:区块链技术与数据隐私(附视频)
  17. 功耗大好还是小好_热设计功耗高好还是低好 - 卡饭网
  18. dcloud 5+ 监听安卓前后台切换状态 并后台运行程序
  19. python matlab 多条曲线 单位_【基础篇】MATLAB科研制图常用代码命令
  20. Unity新手必备5款宝藏插件--价值上千元白嫖最新版

热门文章

  1. 2021编程语言top10,C蝉联第一,Python超越Java成为第二
  2. 含泪整理最优质天空ps后期素材素材,你想要的这里都有
  3. 书呆子rico_Excel书呆子优胜者的夏季赠品
  4. 映客财报:翻身与社交突围
  5. LED屏显示驱动简述与类型
  6. bootstrap和css样式兼容(ie、360、qq)不同浏览器的解决办法
  7. 冬天这么冷,到底要不要坚持送孩子入托?
  8. Android定制Home,以及launcher的自定义
  9. java获取时间下周几的时间
  10. 如何解决hbase中数据热点问题