LoginSignup
1
0

More than 5 years have passed since last update.

Cocos2d-xでテキストボックスのUIテーマをMaterial Designにする方法

Posted at

ターゲット

  • 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バージョンに関わらず古いテーマが使用されている。

s_old_ui_01.png

マテリアルデザインについて

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を適用する方法を試しました。

res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="@android:style/Theme.Holo.Light">
    </style>
</resources>
res/values-v21/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="android:Theme.Material.Light">
    </style>
</resources>

上記適用することで↓が

s_old_ui.png

こうなる予定↓だったが…

s_new_ui.png

…ならなかった。styles.xmlが効いていない模様。

ただ、Android 7でやると古いUIテーマのままなはずなのに新UIテーマで表示される。
7以降はOSがよしなにやってくれているのかもしれない。
とは言えAndroid6では古いままなので何とかする。

原因調査: Cocos2d-xのコードを見てみる

C++

テキストボックス(入力インターフェース)はcocos2d_libsのEditBoxクラスで定義している。
このクラスで定義されたテキストボックスをタップするとAndroidでは
EditBoxImplAndroid::openKeyboard()内のshowEditTextDialogJNIメソッドが呼ばれる。
このメソッドで画面上部のテキストボックスダイアログを表示させているようだ。

CCEditBoxImplAndroid.cpp
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のところは省きます)。

Cocos2dxActivity.java
@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

Cocos2dxHandler.java
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クラスのコンストラクタ。

Cocos2dxEditBoxDialog.java
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が適用されるのではないかと思います。
(手間かかるので試してないです。)

Cocos2dxEditBox.java
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からテーマを変更します。

Cocos2dxHandler.java
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にあったテーマを使うように変更。

Cocos2dxEditBoxDialog.java
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でテキストボックスの背景色を変更します。
これをやらないと背景が透明になって見づらかった。。

Cocos2dxEditBoxDialog.java
@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);

    // ......
}

結果

無事マテリアルデザインになりました。

s_android6.png

まとめ

  • Cocos2d-x v3.7以下のバージョンではstyles.xmlでテキストボックスのUIテーマが変更できなかった
  • Cocos2dxEditBoxDialogクラスで指定していたテーマをAPI Levelによって変更できるようにした
    • style.xmlではなくコードによる変更
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0