車載定製化系統設定中實現平滑的語言切換
阿新 • • 發佈:2018-11-24
在每個車載系統中,都會有自己獨特的UI風格。比如系統設定這個功能,為了統一風格,我們不能直接去呼叫Android原生的設定應用,而是應該重新做一個風格統一的符合需求的系統設定應用。我們要說的語言切換這個功能,就是其中一個設定項。
如果簡單地實現語言切換,應該是比較簡單的,就是利用反射重新設定一下Locale就好了,這個時候Activity會異常銷燬,並會重新載入重新整理當前語言資源。如下:
public static void setLanguage(Locale locale){ try { Class c = Class.forName("com.android.internal.app.LocalePicker"); Object obj = c.newInstance(); Method method = c.getMethod("updateLocale", new Class[] {Locale.class}); method.invoke(obj, locale); } catch (ClassNotFoundException e) { e.printStackTrace(); }catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); }catch (NoSuchMethodException e) { e.printStackTrace(); }catch (IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } }
但是客戶的需求可沒這麼簡單,首先他不會允許你有一個銷燬再新建立的閃一下的動作,其次會要求增加一個帶loading動畫的彈窗效果。
第一個需求的解決,是在Manifest檔案中對應的設定語言的那個Activity增加屬性: android:configChanges=“locale|layoutDirection”。這樣Activity就不會自動銷燬了。但同時,我們需要註冊一個廣播接收器,監聽語言改變的廣播,在這裡需要把Activity裡面的相關字串重新載入一遍,實現手動的重新整理。如下:
/** 註冊語言改變廣播 */ private void registerLocalReceiver() { IntentFilter mFilter = new IntentFilter(); mFilter.addAction(Intent.ACTION_LOCALE_CHANGED); this.registerReceiver(localReceiver, mFilter); } private BroadcastReceiver localReceiver = new BroadcastReceiver() { @Override public void onReceive(Context arg0, Intent arg1) { Log.i(TAG, "receive the language changed broadcast!"); initData(); } }; @Override public void initData() { mTvTitle.setText(getStr(R.string.set_usually)); mIvTitle.setImageResource(R.drawable.set_usually_n); ....... }
第二個需求,需要在切換語言的同時,還要有一個loading動畫的彈窗效果。如果只是單純地在應用中使用windowManager新增一個view,並利用動畫去轉動,很大概率會出現動畫卡頓的效果,主要是動畫的操作,只能放在主執行緒去做。於是可以把語言切換和動畫的效果,放在另外的程序去處理,這樣就可以實現平滑的語言切換了。彈窗的實現效果如下:
private void showUpdateLanguageDialog(View view){ try{ WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams mWindowParams = new WindowManager.LayoutParams(); mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; mWindowParams.format = PixelFormat.TRANSLUCENT; mWindowParams.gravity = Gravity.LEFT | Gravity.TOP; mWindowParams.x = 0; mWindowParams.y = 0; mWindowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; mWindowParams.width = WindowManager.LayoutParams.MATCH_PARENT; mWindowParams.height = WindowManager.LayoutParams.MATCH_PARENT; mWindowManager.addView(view, mWindowParams); }catch(Exception ex){ } }
由於Locale是不能通過Parcelable傳遞的,所以使用Configuration來傳遞,切換語言也可以用下面的方式:
IActivityManager iActMag = ActivityManagerNative.getDefault();
try {
Configuration config = iActMag.getConfiguration();
config.locale = locale;
// 此處需要宣告許可權:android.permission.CHANGE_CONFIGURATION
// 會重新呼叫 onCreate();
iActMag.updateConfiguration(config);
} catch (RemoteException e) {
e.printStackTrace();
}