根据语言变化动态更新图片资源方案

发布于:2025-02-11 ⋅ 阅读:(65) ⋅ 点赞:(0)

一、需求描述

Android 项目中引导页图片包含文字信息,由于应用是适配了三种语言(简体中文、繁体中文和英文),所以希望系统语言变化时,对应的图片也随之变化保持和应用语言一致,因此需要实现根据语言变化动态更新图片资源方案。

二、关于 Locale

Locale 是多语言支持(国际化)和本地化的基础,通过它,Android 系统能够根据用户的语言偏好、国家/地区、地区设置等提供正确的语言、日期、时间格式、货币符号等。
一个 Locale 对象通常由以下几个部分组成:

  • 语言 (language): 表示用户所使用的语言。例如,“en” 代表英语,“zh” 代表中文。
  • 国家/地区 (country): 用于指定与特定语言相关联的地理区域。例如,“US” 代表美国,“CN” 代表中国。国家/地区通常影响格式和文化习惯,比如日期格式、数字和货币符号等。
  • 变体 (variant): 变体通常是地区内的特定差异,比如不同的方言或者区域差异。例如,“en-US” 表示美国英语,而 “en-GB” 表示英国英语。
  • 脚本 (script): 脚本表示语言的书写形式,比如“Latn”代表拉丁字母,“Hans”代表简体字。

三、实现方案

3.1 方案一(不可行)

常规思路,我们想通过类似字符号串的形式来适配,创建不同的语言文件夹来自动匹配系统语言实现,如values/strings.xmlvalues-zh-rCN/strings.xmlvalues-zh-rTW/strings.xml,实际我们创建了drawabledrawable-zh-rCNdrawable-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(
            // 新的资源ID
            R.drawable.new_tutorial_image1,
            R.drawable.new_tutorial_image2,
            R.drawable.new_tutorial_image3
    ));

    // 刷新UI
    // ... (例如,通知Adapter刷新数据)
}

创建一个广播接收器,监听系统语言变化的广播,在广播接收器中,根据当前设备语言,获取新的图片资源ID。

private class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public 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,此时页面语言都不会变化,需要手动设置所有。

<activity
    android: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
        );
    }
}