根据语言变化动态更新图片资源方案
- 一、需求描述
- 二、关于 Locale
- 三、实现方案
- 3.1 方案一(不可行)
- 3.2 方案二(不可行)
- 3.3 方案三
一、需求描述
Android 项目中引导页图片包含文字信息,由于应用是适配了三种语言(简体中文、繁体中文和英文),所以希望系统语言变化时,对应的图片也随之变化保持和应用语言一致,因此需要实现根据语言变化动态更新图片资源方案。
二、关于 Locale
Locale
是多语言支持(国际化)和本地化的基础,通过它,Android 系统能够根据用户的语言偏好、国家/地区、地区设置等提供正确的语言、日期、时间格式、货币符号等。
一个 Locale 对象通常由以下几个部分组成:
- 语言 (language): 表示用户所使用的语言。例如,“en” 代表英语,“zh” 代表中文。
- 国家/地区 (country): 用于指定与特定语言相关联的地理区域。例如,“US” 代表美国,“CN” 代表中国。国家/地区通常影响格式和文化习惯,比如日期格式、数字和货币符号等。
- 变体 (variant): 变体通常是地区内的特定差异,比如不同的方言或者区域差异。例如,“en-US” 表示美国英语,而 “en-GB” 表示英国英语。
- 脚本 (script): 脚本表示语言的书写形式,比如“Latn”代表拉丁字母,“Hans”代表简体字。
三、实现方案
3.1 方案一(不可行)
常规思路,我们想通过类似字符号串的形式来适配,创建不同的语言文件夹来自动匹配系统语言实现,如values/strings.xml
、values-zh-rCN/strings.xml
、values-zh-rTW/strings.xml
,实际我们创建了drawable
、drawable-zh-rCN
、drawable-zh-rTW
这种文件夹存放不同语言的图片文件,但是通过测试发现,切换系统语言时图片并没有变化,即使杀掉应用再重新进入图片匹配的也不正确,只有在删除应用数据后才会正确匹配一次。
3.2 方案二(不可行)
随后我们尝试监听系统语言变化的广播,当接受到语言变化广播,再更新图片资源,当时实际测试发现,在onReceive
中获取到的是语言变化前的LOCALE
,而不是更新后的LOCALE
。
此方案的实现步骤:注册和取消注册监听器
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 初始化mImageResIds,根据当前语言设置初始值updateImageResIds(getResources().getConfiguration().locale);
}@Override
public void onResume() {super.onResume();// 注册广播接收器IntentFilter filter = new IntentFilter(Locale.getDefault().toString());mBroadcastReceiver = new MyBroadcastReceiver();requireContext().registerReceiver(mBroadcastReceiver, filter);
}@Override
public void onPause() {super.onPause();// 注销广播接收器if (mBroadcastReceiver != null) {requireContext().unregisterReceiver(mBroadcastReceiver);}
}private void updateImageResIds(Locale locale) {// 根据locale获取新的资源ID// ...mImageResIds.clear();mImageResIds.addAll(Arrays.asList(// 新的资源IDR.drawable.new_tutorial_image1,R.drawable.new_tutorial_image2,R.drawable.new_tutorial_image3));// 刷新UI// ... (例如,通知Adapter刷新数据)
}
创建一个广播接收器,监听系统语言变化的广播,在广播接收器中,根据当前设备语言,获取新的图片资源ID。
private class MyBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent**1**) {if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {updateImageResIds(getResources().getConfiguration().locale);}}
}
3.3 方案三
先要确定 AndroidManifest.xml 中为 Activity 设置 configChanges
属性,不能包含locale
,若设置了locale
,那么监听语言变化时候只会走 onConfigurationChanged
,此时页面语言都不会变化,需要手动设置所有。
<activityandroid:name=".YourActivity"android:configChanges="locale|layoutDirection" />
若没有设置了locale
,那么界面会重新创建,作为 Activity
会走 onCreate
生命周期,所以我们可以在 onCreate
时获取当前语言环境 LOCALE
,这个时候获取到的 LOCALE
就是系统语言变化后的值,通过获取到的 locales
就可以设置对应的图片ID了。
private List<Integer> mImageResIds = Arrays.asList(R.drawable.tutorial_image1,R.drawable.tutorial_image2,R.drawable.tutorial_image3);@Override
public void initView(ViewDataBinding binding) {//设置图片资源setImageBasedOnLanguage();//其他UI
}
根据语言设置图片资源ID,LOCALE
一般是由语言+地区
组成,若包含Hans
则是简体,若包含Hant
则是繁体
简体:zh-Hans-CN
繁体:zh-Hant-CN
英文:en-CN
private void setImageBasedOnLanguage() {String locale = getResources().getConfiguration().getLocales().get(0).toString();LogUtils.i("[TutorialDialogFragment][setImageBasedOnLanguage] locale:" + locale);if (locale.contains("Hant")) {mImageResIds = Arrays.asList(R.drawable.tutorial_image1_zh_tw,R.drawable.tutorial_image2_zh_tw,R.drawable.tutorial_image3_zh_tw);} else if (locale.contains("en")) {mImageResIds = Arrays.asList(R.drawable.tutorial_image1_en,R.drawable.tutorial_image2_en,R.drawable.tutorial_image3_en);}
}