GeorgeYang'Blog

my technology blog

android程序内多语言切换不需要重新启动的方法

阅读:568 创建时间:16-04-27 01:30:17 tags:android,textview

关于android程序内的的多语言切换,一般能搜索到这段代码:

     public void switchLanguage(Locale locale) {
                  Configuration config = getResources().getConfiguration();// 获得设置对象
                  Resources resources = getResources();// 获得res资源对象
                  DisplayMetrics dm = resources.getDisplayMetrics();// 获得屏幕参数:主要是分辨率,像素等。
                  config.locale = locale; //语言
                  resources.updateConfiguration(config, dm);
          }

多数给出的方案是重新启动activity或者重新setContentView,但是微信却能办到不重启又能修改语言,怎么办到的呢?就让鄙人吹吹实现思路吧:首先定义一个多语言切换支持的自定义控件,整个app涉及到多语言的布局的地方都要使用它,控件初始化的时候获取string资源id,保存string资源id,settext的时候要更新string资源id,切换语言的时候用上文所提供的代码,设置完语言后(假设设置成中文),如果重新通过string资源id设置text,那么就会显示中文文字,如果我们不主动去更新,他们就不自觉了,就像泡妹子一样,主动才能到手,所以我们需要对所有的多语言支持的自定义控件进行更新,方法就是通过发送 消息给每一个activity,activity收到后,拿出自己的view,把全部子view列举一次,如果是多语言支持的自定义控件,就更新它,详细步骤看下文:

步骤1:

建立多语言文件夹,并写好多语言所需的文字

values-zh

values-en

.....

不细讲了

步骤2:

定义多语言切换接口,需要自定义view实现它

在控件包(widget包)下建立AppTextView和AppButton

建立接口:LanguageView,包含以下方法:

     //由于setText无法被重写,需要添加以下三个必要的方法,如果你的app不需要对多语言的textview修改值(只是xml写死就够了),那就不需要实现他们
     void setTextById (@StringRes int id);//手动设置textId
     void setTextWithString (String text);//手动去掉textId,不然重新加载语言的时候会被重置掉
     void setTextByArrayAndIndex (@ArrayRes int arrId, @StringRes int arrIndex);//手动通过TextArray设置语言

     void reLoadLanguage();//修改语言时主要调用的方法

步骤3:

自定义多语言切换view:

 public class AppTextView extends TextView implements LanguageView {
     private int textId ;//文字id
     private int hintId ;//hint的id
     private int arrResId,arrResIndex;

     public AppTextView(Context context) {
         super(context);
         init(context, null);
     }

     public AppTextView(Context paramContext, AttributeSet paramAttributeSet) {
         super(paramContext, paramAttributeSet);
         init(paramContext, paramAttributeSet);
     }

     public AppTextView(Context paramContext, AttributeSet paramAttributeSet, int paramInt) {
         super(paramContext, paramAttributeSet, paramInt);
         init(paramContext, paramAttributeSet);
     }

     /**
      * 初始化获取xml的资源id
      * @param context
      * @param attributeSet
      */
     private void init (Context context,AttributeSet attributeSet) {
         if (attributeSet!=null) {
             String textValue = attributeSet.getAttributeValue(ANDROIDXML, "text");
             if (!(textValue==null || textValue.length()<2)) {
                 //如果是 android:text="@string/testText"
                 //textValue会长这样 @0x7f080000,去掉@号就是资源id
                 textId = StringUtil.string2int(textValue.substring(1,textValue.length()));
             }

             String hintValue = attributeSet.getAttributeValue(ANDROIDXML, "hint");
             if (!(hintValue==null || hintValue.length()<2)) {
                 hintId = StringUtil.string2int(hintValue.substring(1,hintValue.length()));
             }
         }
     }

     @Override
     public void setTextById (@StringRes int strId) {
         this.textId = strId;
         setText(strId);
     }

     @Override
     public void setTextWithString(String text) {
         this.textId = 0;
         setText(text);
     }
     @Override
     public void setTextByArrayAndIndex (@ArrayRes int arrId, @StringRes int arrIndex) {
         arrResId = arrId;
         arrResIndex = arrIndex;
         String[] strs = getContext().getResources().getStringArray(arrId);
         setText(strs[arrIndex]);
     }

     @Override
     public void reLoadLanguage () {
         try {
             if (textId>0) {
                 setText(textId);
             } else if (arrResId>0) {
                 String[] strs = getContext().getResources().getStringArray(arrResId);
                 setText(strs[arrResIndex]);
             }

             if (hintId>0) {
                 setHint(hintId);
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 }

步骤4:

博客出处 编写xml:

 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical" android:layout_width="match_parent"

     android:layout_height="match_parent">

     <cn.georgeyang.languageupdate.widget.AppTextView
         android:text="@string/testText"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />

     <cn.georgeyang.languageupdate.widget.AppButton
         android:id="@+id/btn"
         android:text="@string/next"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />

 </LinearLayout>

步骤5:

写好activity代码后,添加eventbus,实现activity之间的通信(用其它方式实现通信也行)

 gradle添加    compile 'org.greenrobot:eventbus:3.0.0'


 public class MainActivity extends AppCompatActivity {

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);

         EventBus.getDefault().register(this);


         findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                  switchLanguage(Locale.CHINESE);
                  ClassEvent event = new ClassEvent();
                 event.msg = "do it";
                 EventBus.getDefault().post(event);
             }
         });
     }

  public void switchLanguage(Locale locale) {
         Configuration config = getResources().getConfiguration();// 获得设置对象
         Resources resources = getResources();// 获得res资源对象
         DisplayMetrics dm = resources.getDisplayMetrics();// 获得屏幕参数:主要是分辨率,像素等。
         config.locale = locale; 
         resources.updateConfiguration(config, dm);
     }

     @Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行
     public void onStringEvent(ClassEvent event) {
         Log.d("test","MainActivity got message:" +  event);
         //start update language
     }

     @Override
     protected void onDestroy(){
         super.onDestroy();
         EventBus.getDefault().unregister(this);//反注册EventBus
     }
 }

步骤6

编写修改多语言文字的代码:

    //给给出一个view,把子view全部检查一遍,如果是实现LanguageView接口的view,更新语言
     public static void updateViewLanguage(View view) {
         if (view instanceof ViewGroup) {
             ViewGroup vg = (ViewGroup) view;
             int count = vg.getChildCount();
             for (int i = 0; i < count; i++) {
                 updateViewLanguage(vg.getChildAt(i));
             }
         } else if (view instanceof LanguageView) {
             LanguageView tv = (LanguageView) view;
             tv.reLoadLanguage();
         }
     }

修改多语言文字的代码写好后,开始调用:

     @Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行
     public void onStringEvent(ClassEvent event) {
         Log.d("test","MainActivity got message:" +  event);
         ViewUtil.updateViewLanguage(findViewById(android.R.id.content));
     }

最后点一下按钮就能更新语言了,activity没有重启,而且上一个activity的语言也跟着改变,不需要自己找出textview手动修改,是不是很方便呢?!

最后给出demo代码:

gitDemo