ターゲット
- Cocos2d-x v3.8未満のバージョンを使用しているアプリ制作者
- v3.8だとテキストボックス関係のクラスが見直されているので修正されている可能性があります
概要
- Cocos2d-x v3.7以下のバージョンで、Android API Levelに応じてテキストボックスのUIテーマを切り替えられるようにしました
- Cocos2dxEditBoxDialogクラスのコンストラクタでUIテーマをハードコーディングしているのでそこを修正すれば変更可能
- style.xmlでは切り替わらなかったのでコードによる変更
背景
Cocos2d-xのテキストボックスダイアログ
Cocos2d-x v3.7以下のバージョンでのテキストボックスはAndroidバージョンに関わらず古いテーマが使用されている。
マテリアルデザインについて
Googleによると、Android 5.0以降ではアプリのUIテーマにマテリアルデザインを使用することを推奨しています。
参考: Android Developers:デベロッパーのためのマテリアル デザイン
マテリアルテーマを適用する
Android 5.0以降のみに提供するアプリであれば、res/styles.xmlで記述しているMyThemeで
android:Theme.Material
などを継承することでマテリアルテーマが適用されます。
参考: Android Developers:マテリアル テーマの使用
OSの互換性を持たせる
アプリによってはAndroid 4系にも提供していると思います。
その場合、4ではマテリアルテーマが存在しないのでOSバージョンによってテーマを変更する必要があります。
参考: Android Developers:互換性の維持
詳しいやり方はここが参考になります。いくつか方法はあります。
->既存のAndroidアプリにMaterial Themeを適用する方法
実際に適用してみる
Android 6.0端末で行いました。
私はstyles.xmlをAndroid 5用と4以下用の2つ用意し、
それをApplicationのAndroidManifestにstylesで定義したAppThemeを適用する方法を試しました。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@android:style/Theme.Holo.Light">
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="android:Theme.Material.Light">
</style>
</resources>
上記適用することで↓が
こうなる予定↓だったが…
…ならなかった。styles.xmlが効いていない模様。
ただ、Android 7でやると古いUIテーマのままなはずなのに新UIテーマで表示される。
7以降はOSがよしなにやってくれているのかもしれない。
とは言えAndroid6では古いままなので何とかする。
原因調査: Cocos2d-xのコードを見てみる
C++
テキストボックス(入力インターフェース)はcocos2d_libsのEditBox
クラスで定義している。
このクラスで定義されたテキストボックスをタップするとAndroidでは
EditBoxImplAndroid::openKeyboard()
内のshowEditTextDialogJNI
メソッドが呼ばれる。
このメソッドで画面上部のテキストボックスダイアログを表示させているようだ。
void EditBoxImplAndroid::openKeyboard()
{
if (_delegate != NULL)
{
_delegate->editBoxEditingDidBegin(_editBox);
}
// .......
showEditTextDialogJNI(_placeHolder.c_str(),
_text.c_str(),
static_cast<int>(_editBoxInputMode),
static_cast<int>(_editBoxInputFlag),
static_cast<int>(_keyboardReturnType),
_maxLength,
editBoxCallbackFunc,
static_cast<void*>(this));
}
Java
Java側ではActivityにあるshowEditTextDialog
が呼ばれます(JNIのところは省きます)。
@Override
public void showEditTextDialog(final String pTitle, final String pContent, final int pInputMode, final int pInputFlag, final int pReturnType, final int pMaxLength) {
Message msg = new Message();
msg.what = Cocos2dxHandler.HANDLER_SHOW_EDITBOX_DIALOG;
msg.obj = new Cocos2dxHandler.EditBoxMessage(pTitle, pContent, pInputMode, pInputFlag, pReturnType, pMaxLength);
this.mHandler.sendMessage(msg);
}
実際にダイアログを作っているところはCocos2dxHandlerのshowEditBoxDialog
。
private void showEditBoxDialog(Message msg) {
EditBoxMessage editBoxMessage = (EditBoxMessage)msg.obj;
new Cocos2dxEditBoxDialog(this.mActivity.get(),
editBoxMessage.title,
editBoxMessage.content,
editBoxMessage.inputMode,
editBoxMessage.inputFlag,
editBoxMessage.returnType,
editBoxMessage.maxLength).show();
}
そして、最後。cocos2d-xのEditBoxDialogクラスのコンストラクタ。
public Cocos2dxEditBoxDialog(final Context pContext, final String pTitle, final String pMessage, final int pInputMode, final int pInputFlag, final int pReturnType, final int pMaxLength) {
super(pContext, android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
// super(context, R.style.Theme_Translucent);
this.mTitle = pTitle;
this.mMessage = pMessage;
this.mInputMode = pInputMode;
this.mInputFlag = pInputFlag;
this.mReturnType = pReturnType;
this.mMaxLength = pMaxLength;
}
テキストボックスのテーマが変わらない原因
Cocos2dxEditBoxDialog.java
で古いテーマがハードコーディングされています。
super(pContext, android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
参考: Cocos2dxEditBoxDialog.java#L140
styles.xmlをいくらいじってもダメだった理由が分かりました。
ちなみにこのあたりのクラスはCocos2d-x v3.8で見直されています。
https://github.com/cocos2d/cocos2d-x/pull/13273
v3.8ではCocos2dxEditBoxDialogクラスは無くなり、Cocos2dxEditBoxクラスになっています。
テーマ直書きもなくなっています。
この状態であればstyles.xmlで定義したAppThemeが適用されるのではないかと思います。
(手間かかるので試してないです。)
public Cocos2dxEditBox(Context context){
super(context);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.setInputFlag(kEditBoxInputFlagInitialCapsAllCharacters);
this.setInputMode(kEditBoxInputModeSingleLine);
this.setReturnType(kKeyboardReturnTypeDefault);
this.setHintTextColor(Color.GRAY);
this.setVisibility(View.INVISIBLE);
this.setBackgroundColor(Color.TRANSPARENT);
this.setTextColor(Color.WHITE);
this.setSingleLine();
}
解決方法: テキストボックスのUIテーマをMaterial Designにする
本題です。テキストボックスのUIテーマをMaterial Designにしていきます。
まず、showEditBoxDialog内でAPI Levelからテーマを変更します。
private void showEditBoxDialog(Message msg) {
// テーマをAPI Levelで変更する(互換性維持)
int theme = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Android 5以上
theme = android.R.style.Theme_Material_NoActionBar_Fullscreen;
} else {
// Android 4以下
theme = android.R.style.Theme_Translucent_NoTitleBar_Fullscreen;
}
EditBoxMessage editBoxMessage = (EditBoxMessage)msg.obj;
// API Levelにあったthemeを使ってCocos2dxEditBoxDialogを生成
new Cocos2dxEditBoxDialog(this.mActivity.get(),
editBoxMessage.title,
editBoxMessage.content,
editBoxMessage.inputMode,
editBoxMessage.inputFlag,
editBoxMessage.returnType,
editBoxMessage.maxLength,
theme).show();
}
Cocos2dxEditBoxDialogクラスではAPI Levelにあったテーマを使うように変更。
public Cocos2dxEditBoxDialog(final Context pContext, final String pTitle, final String pMessage, final int pInputMode, final int pInputFlag, final int pReturnType, final int pMaxLength, final int theme) {
// API Levelにあったthemeを使う
super(pContext, theme);
// super(pContext, android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
this.mTitle = pTitle;
this.mMessage = pMessage;
this.mInputMode = pInputMode;
this.mInputFlag = pInputFlag;
this.mReturnType = pReturnType;
this.mMaxLength = pMaxLength;
}
同じくCocos2dxEditBoxDialogクラスのonCreateでテキストボックスの背景色を変更します。
これをやらないと背景が透明になって見づらかった。。
@Override
protected void onCreate(final Bundle pSavedInstanceState) {
super.onCreate(pSavedInstanceState);
// ......
this.mInputEditText = new EditText(this.getContext());
final LinearLayout.LayoutParams editTextParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
editTextParams.leftMargin = editTextParams.rightMargin = this.convertDipsToPixels(10);
// 背景色を変更
this.mInputEditText.setBackgroundColor(0xf0ffffff);
layout.addView(this.mInputEditText, editTextParams);
// ......
}
結果
無事マテリアルデザインになりました。
まとめ
- Cocos2d-x v3.7以下のバージョンではstyles.xmlでテキストボックスのUIテーマが変更できなかった
- Cocos2dxEditBoxDialogクラスで指定していたテーマをAPI Levelによって変更できるようにした
- style.xmlではなくコードによる変更