一、簡介
二辛燥、效果預(yù)覽
三筛武、實(shí)現(xiàn)步驟
1、功能實(shí)現(xiàn)
2挎塌、配置多語言文件
四徘六、MultiLanguageUtils分析
五、Demo地址
六榴都、內(nèi)容推薦
一待锈、簡介
我想搜到這篇文章的朋友應(yīng)該不需要我多介紹,也明白多語言是用來干嘛嘴高。竿音。。
當(dāng)一個(gè)應(yīng)用越做越大之后拴驮,用的人越來越多春瞬,要滿足不同的群體所以都會(huì)有這一功能。
不過你會(huì)發(fā)現(xiàn)越到后面添加這功能會(huì)比較麻煩套啤。所以前期做好準(zhǔn)備為佳宽气。
不扯這亂七八糟的東西了。。抹竹。线罕。亮劍吧!G耘小钞楼!
二、效果預(yù)覽
是不是要先看看大招是咋樣的袄琳,萬一是花拳繡腿询件。不滿意,就浪費(fèi)大家時(shí)間了唆樊。
大家可可能會(huì)奇怪宛琅,不是切換成英文了嗎? 怎么還有中文字體逗旁。
其實(shí)我只是對(duì)首頁的 標(biāo)題 與 底部導(dǎo)航欄 做了處理 其他的沒有變
所以大家看效果的話 只需觀察 那兩處地方即可嘿辟。
如果對(duì)這個(gè)功能有興趣可以繼續(xù)往下觀察。片效。沒興趣的也請(qǐng)往下看 红伦,看完可能會(huì)更沒興趣。哈哈 開個(gè)玩笑
三淀衣、實(shí)現(xiàn)步驟
1昙读、功能實(shí)現(xiàn)
布局我就不解釋了,就隨便搭搭膨桥。源碼地址就貼在最下面蛮浑,想copy的同學(xué)自己去下載哈。對(duì)了只嚣,如果不錯(cuò)沮稚。別忘了 Star
主要的功能就在于當(dāng)我選中某個(gè)語言時(shí),點(diǎn)擊保存(上圖是“打鉤”的圖片)的時(shí)候去實(shí)現(xiàn)語言的切換册舞。 那么壮虫,是怎么實(shí)現(xiàn)的呢?預(yù)知后事如何且看下文分解;反 囚似!
上菜:點(diǎn)擊保存執(zhí)行事假
//區(qū)分是選中哪種語言
switch (datas.get(checkPos)) {
case "跟隨系統(tǒng)"://切換到 跟隨系統(tǒng)
//獲取手機(jī)系統(tǒng)語言
Locale locale = MultiLanguageUtils.getSystemLanguage().get(0);
String language = locale.getLanguage();
String country = locale.getCountry();
//切換成手機(jī)系統(tǒng)語言 例:手機(jī)系統(tǒng)是中文則換成中文
MultiLanguageUtils.changeLanguage(activity,language, country);
//清空SP數(shù)據(jù) ,用于當(dāng)系統(tǒng)切換語言時(shí) 應(yīng)用可以同步保持切換 例:系統(tǒng)轉(zhuǎn)換成英文 則應(yīng)用語言也會(huì)變成英文
MultiLanguageUtils.changeLanguage(activity,null,null);
break;
case "簡體中文":// 切換到 中文
MultiLanguageUtils.changeLanguage(activity, "zh", "ZH");
break;
case "English"://切換到 英文
MultiLanguageUtils.changeLanguage(activity, "en", "US");
break;
default://默認(rèn)切換成中文
MultiLanguageUtils.changeLanguage(activity, "zh", "ZH");
break;
}
//關(guān)閉應(yīng)用所有Activity
//AppManager.getAppManager().finishAllActivity();
//啟動(dòng) MainActivity
//IntentUtils.toActivity(activity, MainActivity.class,true);
上面的切換語言功能都已經(jīng)封裝成一個(gè)工具類线得,當(dāng)需要執(zhí)行切換語言的時(shí)候 只需調(diào)用一行代碼即可饶唤。是不是很興奮 ,其實(shí)更麻煩的在后面贯钩,先安慰一下大家募狂。
要讓切換語言起效果办素,還需要重啟APP。
例:上面代碼是先調(diào)用了個(gè)人封裝的一個(gè)Activity管理類來關(guān)閉所有的頁面祸穷,然后再重啟MainActivity性穿。大家可以根據(jù)情況自己寫,也可以到源碼地址找到相關(guān)工具類拿去用雷滚。
大餐來了 MultiLanguageUtils.class 先感謝下大神提供的這個(gè)類:https://blog.csdn.net/m0_38074457/article/details/84993366
個(gè)人做了調(diào)整需曾,改的有點(diǎn)面目全非,現(xiàn)在分享給大家祈远。如果還行呆万。。车份。你們懂得 點(diǎn)個(gè)贊意思一下就行 谋减,,關(guān)注扫沼,分享出爹,打賞 我是不敢想的。
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.LocaleList;
import android.support.v4.os.ConfigurationCompat;
import android.support.v4.os.LocaleListCompat;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import java.util.Locale;
import blcs.lwb.lwbtool.Constants;
/**
* Todo 多語言設(shè)置
* 來自:https://blog.csdn.net/m0_38074457/article/details/84993366
* 使用步驟:
* 1缎除、Application中onCreate添加registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
@Override
protected void attachBaseContext(Context base) {
//系統(tǒng)語言等設(shè)置發(fā)生改變時(shí)會(huì)調(diào)用此方法严就,需要要重置app語言
super.attachBaseContext(MultiLanguageUtils.attachBaseContext(base));
}
* 2、改變應(yīng)用語言調(diào)用MultiLanguageUtils.changeLanguage(activity,type,type);
*/
//public final static String SP_LANGUAGE="SP_LANGUAGE";
//public final static String SP_COUNTRY="SP_COUNTRY";
public class MultiLanguageUtils {
/**
* TODO 1伴找、 修改應(yīng)用內(nèi)語言設(shè)置
* @param language 語言 zh/en
* @param area 地區(qū)
*/
public static void changeLanguage(Context context,String language, String area) {
if (TextUtils.isEmpty(language) && TextUtils.isEmpty(area)) {
//如果語言和地區(qū)都是空盈蛮,那么跟隨系統(tǒng)s
SPUtils.put(context, Constants.SP_LANGUAGE,"");
SPUtils.put(context, Constants.SP_COUNTRY,"");
} else {
//不為空废菱,那么修改app語言技矮,并true是把語言信息保存到sp中,false是不保存到sp中
Locale newLocale = new Locale(language, area);
setAppLanguage(context,newLocale);
saveLanguageSetting(context, newLocale);
}
}
/**
* Todo 更新應(yīng)用語言
* @param context
* @param locale
*/
private static void setAppLanguage(Context context, Locale locale) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
Configuration configuration = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(locale);
configuration.setLocales(new LocaleList(locale));
context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(locale);
resources.updateConfiguration(configuration,metrics);
} else {
configuration.locale = locale;
resources.updateConfiguration(configuration,metrics);
}
}
/**
* TODO 3殊轴、 跟隨系統(tǒng)語言
*/
public static Context attachBaseContext(Context context) {
String spLanguage = (String) SPUtils.get(context, Constants.SP_LANGUAGE,"");
String spCountry = (String) SPUtils.get(context, Constants.SP_COUNTRY,"");
if(!TextUtils.isEmpty(spLanguage)&&!TextUtils.isEmpty(spCountry)){
Locale locale = new Locale(spLanguage, spCountry);
setAppLanguage(context, locale);
}
return context;
}
/**
* 判斷sp中和app中的多語言信息是否相同
*/
public static boolean isSameWithSetting(Context context) {
Locale locale = getAppLocale(context);
String language = locale.getLanguage();
String country = locale.getCountry();
String sp_language = (String) SPUtils.get(context, Constants.SP_LANGUAGE,"");
String sp_country = (String) SPUtils.get(context, Constants.SP_COUNTRY,"");
if (language.equals(sp_language) && country.equals(sp_country)) {
return true;
} else {
return false;
}
}
/**
* 保存多語言信息到sp中
*/
public static void saveLanguageSetting(Context context, Locale locale) {
SPUtils.put(context, Constants.SP_LANGUAGE,locale.getLanguage());
SPUtils.put(context, Constants.SP_COUNTRY,locale.getCountry());
}
/**
* 獲取應(yīng)用語言
*/
public static Locale getAppLocale(Context context){
Locale local;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
local =context.getResources().getConfiguration().getLocales().get(0);
} else {
local =context.getResources().getConfiguration().locale;
}
return local;
}
/**
* 獲取系統(tǒng)語言
*/
public static LocaleListCompat getSystemLanguage(){
Configuration configuration = Resources.getSystem().getConfiguration();
LocaleListCompat locales = ConfigurationCompat.getLocales(configuration);
return locales;
}
//注冊(cè)Activity生命周期監(jiān)聽回調(diào)衰倦,此部分一定加上,因?yàn)橛行┌姹静患拥脑挾嗾Z言切換不回來
//registerActivityLifecycleCallbacks(callbacks);
public static Application.ActivityLifecycleCallbacks callbacks = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
String language = (String) SPUtils.get(activity, Constants.SP_LANGUAGE,"");
String country = (String) SPUtils.get(activity, Constants.SP_COUNTRY,"");
LogUtils.e(language);
if (!TextUtils.isEmpty(language) && !TextUtils.isEmpty(country)) {
//強(qiáng)制修改應(yīng)用語言
if (!isSameWithSetting(activity)) {
Locale locale = new Locale(language, country);
setAppLanguage(activity,locale);
}
}
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
};
}
這里可以能還需要一個(gè)封裝的SP工具
import android.content.Context;
import android.content.SharedPreferences;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* SharedPreferences的封裝
*/
public class SPUtils
{
public SPUtils()
{
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 保存在手機(jī)里面的文件名
*/
public static final String FILE_NAME = "share_data";
/**
* 保存數(shù)據(jù)的方法旁理,我們需要拿到保存數(shù)據(jù)的具體類型樊零,然后根據(jù)類型調(diào)用不同的保存方法
*
* @param context
* @param key
* @param object
*/
public static void put(Context context, String key, Object object)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (object instanceof String)
{
editor.putString(key, (String) object);
}
else if (object instanceof Integer)
{
editor.putInt(key, (Integer) object);
}
else if (object instanceof Boolean)
{
editor.putBoolean(key, (Boolean) object);
}
else if (object instanceof Float)
{
editor.putFloat(key, (Float) object);
}
else if (object instanceof Long)
{
editor.putLong(key, (Long) object);
}
else
{
editor.putString(key, object.toString());
}
SharedPreferencesCompat.apply(editor);
}
/**
* 得到保存數(shù)據(jù)的方法,我們根據(jù)默認(rèn)值得到保存的數(shù)據(jù)的具體類型孽文,然后調(diào)用相對(duì)于的方法獲取值
*
* @param context
* @param key
* @param defaultObject
* @return
*/
public static Object get(Context context, String key, Object defaultObject)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
if (defaultObject instanceof String)
{
return sp.getString(key, (String) defaultObject);
}
else if (defaultObject instanceof Integer)
{
return sp.getInt(key, (Integer) defaultObject);
}
else if (defaultObject instanceof Boolean)
{
return sp.getBoolean(key, (Boolean) defaultObject);
}
else if (defaultObject instanceof Float)
{
return sp.getFloat(key, (Float) defaultObject);
}
else if (defaultObject instanceof Long)
{
return sp.getLong(key, (Long) defaultObject);
}
return null;
}
/**
* 移除某個(gè)key值已經(jīng)對(duì)應(yīng)的值
*
* @param context
* @param key
*/
public static void remove(Context context, String key)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
* 清除所有數(shù)據(jù)
*
* @param context
*/
public static void clear(Context context)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
* 查詢某個(gè)key是否已經(jīng)存在
*
* @param context
* @param key
* @return
*/
public static boolean contains(Context context, String key)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
* 返回所有的鍵值對(duì)
*
* @param context
* @return
*/
public static Map<String, ?> getAll(Context context)
{
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.getAll();
}
/**
* 創(chuàng)建一個(gè)解決SharedPreferencesCompat.apply方法的一個(gè)兼容類
* @author zhy
*
*/
private static class SharedPreferencesCompat
{
private static final Method sApplyMethod = findApplyMethod();
/**
* 反射查找apply的方法
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Method findApplyMethod()
{
try
{
Class clz = SharedPreferences.Editor.class;
return clz.getMethod("apply");
} catch (NoSuchMethodException e)
{
}
return null;
}
/**
* 如果找到則使用apply執(zhí)行驻襟,否則使用commit
*
* @param editor
*/
public static void apply(SharedPreferences.Editor editor)
{
try
{
if (sApplyMethod != null)
{
sApplyMethod.invoke(editor);
return;
}
} catch (IllegalArgumentException e)
{
} catch (IllegalAccessException e)
{
} catch (InvocationTargetException e)
{
}
editor.commit();
}
}
}
如果你們以為有了這幾個(gè)工具就可以出去吹牛逼,那么是你們天真了芋哭,而不是我想的太多沉衣。還有更麻煩的事情還沒開始呢
在繼承Application的類中onCreate方法內(nèi)添加監(jiān)聽回調(diào)
@Override
public void onCreate() {
super.onCreate();
//多語言設(shè)置
registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
}
跟隨系統(tǒng)語言也要在Application中的attachBaseContext配置(感覺可以去掉,本人親測根本沒有調(diào)用到减牺。不知道是不是不同機(jī)型的原因豌习。先保留著 存谎,后續(xù)若發(fā)現(xiàn)無用,可刪掉肥隆。寫出來主要是錢作者有寫但描述不夠詳細(xì))
@Override
protected void attachBaseContext(Context base) {
//系統(tǒng)語言等設(shè)置發(fā)生改變時(shí)會(huì)調(diào)用此方法既荚,需要要重置app語言
super.attachBaseContext(MultiLanguageUtils.attachBaseContext(base));
}
2、配置多語言文件
最麻煩的工作來了栋艳,若前期沒做好相關(guān)工作恰聘。那么你可以開始跟我一步步來實(shí)現(xiàn)了
1、新增多語言文件
可以手動(dòng)創(chuàng)建嘱巾,但要符合命名規(guī)范憨琳。(不推薦)
這里介紹androidStudio 新建多語言文本方法
右擊res——New——Android resource file
創(chuàng)建完文件后。旬昭。篙螟。剩下就是抽出文本進(jìn)行翻譯了。问拘。
2遍略、把項(xiàng)目中的文本都寫到strings.xml文件中
像我這樣:
如何使用這些文本?
UI中: android:text="@string/Title"
代碼中:context.getString(R.string.Title)
快捷鍵使用:選中文本使用 Alt + Enter 打開Extract string resource
給文本命名 ——> 打鉤所有的values——>點(diǎn)擊OK 就可以自動(dòng)生成到strings文件里面
接著翻譯 values-en 文件中的文本骤坐。
到這里差不多都介紹完了 绪杏,若有代碼遺落可查看源碼 。畢竟已經(jīng)實(shí)現(xiàn)過了 纽绍,拿出來分析給大家蕾久,可能會(huì)有疏忽。
MultiLanguageUtils只加了簡單注釋拌夏,若對(duì)MultiLanguageUtils有什么不理解的地方 請(qǐng)繼續(xù)往下看僧著。
四、MultiLanguageUtils分析
我們切換語言只需調(diào)用:MultiLanguageUtils.changeLanguage(activity, "zh", "ZH");
1障簿、changeLanguage(Context context,String language, String area):
public static void changeLanguage(Context context,String language, String area) {
if (TextUtils.isEmpty(language) && TextUtils.isEmpty(area)) {
//如果語言和地區(qū)都是空盹愚,那么跟隨系統(tǒng)s
SPUtils.put(context, Constants.SP_LANGUAGE,"");
SPUtils.put(context, Constants.SP_COUNTRY,"");
} else {
//不為空,那么修改app語言站故,并true是把語言信息保存到sp中皆怕,false是不保存到sp中
Locale newLocale = new Locale(language, area);
setAppLanguage(context,newLocale);
saveLanguageSetting(context, newLocale);
}
}
首先判斷language,area 是否為空
空:清空app本地存儲(chǔ)多語言的sp西篓,為什么要清空呢愈腾?
當(dāng)啟動(dòng)APP時(shí)會(huì)回調(diào) registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
該方法內(nèi)部會(huì)綁定生命周期調(diào)用如下方法
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
String language = (String) SPUtils.get(activity, Constants.SP_LANGUAGE,"");
String country = (String) SPUtils.get(activity, Constants.SP_COUNTRY,"");
LogUtils.e(language);
if (!TextUtils.isEmpty(language) && !TextUtils.isEmpty(country)) {
//強(qiáng)制修改應(yīng)用語言
if (!isSameWithSetting(activity)) {
Locale locale = new Locale(language, country);
setAppLanguage(activity,locale);
}
}
}
若sp有值則根據(jù)對(duì)應(yīng)的值設(shè)置APP語言 ,若為空 岂津,則會(huì)默認(rèn)取系統(tǒng)語言虱黄。
注:當(dāng)選中“跟隨系統(tǒng)語言”時(shí),若不清空SP寸爆。則會(huì)造成當(dāng)系統(tǒng)語言改變礁鲁,App還是會(huì)根據(jù)SP的值來設(shè)置語言盐欺。
有值:根據(jù)傳入的language,area 值切換成相對(duì)應(yīng)的語言
2仅醇、setAppLanguage(Context context, Locale locale)
/**
* Todo 更新應(yīng)用語言
* @param context
* @param locale
*/
private static void setAppLanguage(Context context, Locale locale) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
Configuration configuration = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(locale);
configuration.setLocales(new LocaleList(locale));
context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(locale);
resources.updateConfiguration(configuration,metrics);
} else {
configuration.locale = locale;
resources.updateConfiguration(configuration,metrics);
}
}
更改應(yīng)用的語言主要還是通過更改App配置來實(shí)現(xiàn)冗美,主要實(shí)現(xiàn)步驟如下:
1、先獲取資源配置對(duì)象 2析二、更改資源對(duì)象屬性 3粉洼、更新配置信息
多語言語言適配了Android N (7.0)
7.0以前更新配置信息使用
resources.updateConfiguration(configuration, metrics);
7.0以后更新配置信息使用
context.createConfigurationContext(configuration);
3、跟隨系統(tǒng)語言實(shí)現(xiàn)思路分析
1叶摄、當(dāng)保存跟隨系統(tǒng)語言時(shí)属韧,獲取系統(tǒng)語言 ,并更新App語言蛤吓。
2宵喂、當(dāng)更改手機(jī)設(shè)置語言后,啟動(dòng)App的時(shí)候重新更改App語言(保存其它語言信息的時(shí)候会傲,啟動(dòng)App是時(shí)候也需要根據(jù)保存信息重新設(shè)置)
這里主要分析第二點(diǎn)锅棕。第一點(diǎn)只要調(diào)用changeAppLanguage 就行了
當(dāng)App啟動(dòng)的時(shí)候會(huì)回調(diào)registerActivityLifecycleCallbacks(MultiLanguageUtils.callbacks);
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
String language = (String) SPUtils.get(activity, Constants.SP_LANGUAGE,"");
String country = (String) SPUtils.get(activity, Constants.SP_COUNTRY,"");
LogUtils.e(language);
if (!TextUtils.isEmpty(language) && !TextUtils.isEmpty(country)) {
//強(qiáng)制修改應(yīng)用語言
if (!isSameWithSetting(activity)) {
Locale locale = new Locale(language, country);
setLanguage(activity,locale);
}
}
}
也是通過Sp是否有保存信息來設(shè)置系統(tǒng)語言。
終于寫完了淌山,看了一下篇幅還是挺長裸燎,容我感慨一下。又熬夜了 泼疑,大家要手下留
好吧5侣獭!退渗! 再見
五移稳、Demo地址
六、內(nèi)容推薦
《Android Rxjava+Retrofit網(wǎng)絡(luò)請(qǐng)求框架封裝(一)》
如果你覺得我寫的不錯(cuò)或者對(duì)您有所幫助的話
不妨頂一個(gè)【微笑】氓辣,別忘了點(diǎn)贊秒裕、收藏袱蚓、加關(guān)注哈
看在我花了這么多時(shí)間整理寫成文章分享給大家的份上钞啸,記得手下留情哈
您的每個(gè)舉動(dòng)都是對(duì)我莫大的支持