【Unity】全てのInputFieldが空でなければボタンを表示する

InputFieldを動的に生成し、全部が入力された状態であればOKボタンが押せるようにする、という処理を実現するのに思いのほか苦戦してしまいました。

実装したコード

まず、InputFieldを生成するときにイベントリスナーを設定。

//文字変更時のイベント設定
inputField.transform.GetChild(1).gameObject.GetComponent<InputField>().onValueChanged.AddListener(InputText);

InputFieldをFor文で指定の回数だけ生成して、それぞれに対してイベントリスナーを設定しています。

InputText関数の中身はこちら。

void InputText(string value)
{
    bool isAllInput = true;

    if (value == "")
    {
        //今入力したテキストボックスが空になったらOKボタンを非表示にする
        isAllInput = false;
    }
    else
    {
        //今入力したテキストボックスが空でなければ、
        //今入力したテキストボックス以外で空のテキストボックスがある場合はOKボタンを非表示にする
        for (int i = 0; i < arrInputField.Count; i++)
        {
            //入力がない場合はOKボタンを押せない
            if (arrInputField[i].transform.GetChild(1).gameObject.GetComponent<InputField>().isFocused==false &&
                arrInputField[i].transform.GetChild(1).transform.GetChild(2).gameObject.GetComponent<Text>().text == "")
            {
                isAllInput = false;
            }
        }
    }

    if (isAllInput == true)
    {
        goButton.gameObject.SetActive(true);
    }
    else
    {
        goButton.gameObject.SetActive(false);
    }

}

解説

何をしているか解説します。

①InputFieldに入力された文字が空になったら問答無用でOKボタンはOFF

InputText関数は現在入力されているInputFieldの文字が変更されるタイミングで呼ばれます。
いずれかのInputFieldが空ならOKボタンはOFFにしたいのですから、現在のInputFieldが空になったら他がどうであってもOFFにします。

②その他のInputFieldで値が空のものがあればOKボタンはOFF

InputText関数(InputFieldのonValueChanged時に呼ばれる関数)には引数としてstring型しか渡せません。
そのため、「今入力されているのがどのInputFieldなのか」を判断するためにisFocusedという変数を使っています。

現在入力中のInputFieldが空でなくても、どこかに空があればOKボタンをOFFにするということをやっています。

なぜこんなまどろっこしいことを?

①onValueChanged時のテキスト取得方法による結果の違い

わざわざ現在入力中のInputFieldを判断せず、onValueChanged時にすべてのInputFieldの値を取得すればいいじゃないか、と思われたかもしれません。
私も初めはその方法でやろうとしましたが、どうにも取得される文字が期待するものではありませんでした。

InputText関数内で、2つの方法で取得したInputFieldの値をそれぞれログに出してみます。

Debug.Log(value);
Debug.Log(arrInputField[0].transform.GetChild(1).transform.GetChild(2).gameObject.GetComponent<Text>().text);

上が、onValueChanged時に引数として渡される値。下が、InputFieldを直接参照して取得される値です。

実行してテキストボックスに「A」と1文字入力してみます。
すると、

引数として渡される値には、入力後の「A」という文字列が入っていますが、InputFieldを直接参照すると入力前の値が取得されてしまいます。

そのため

  • 現在入力中のInputFieldは引数から値を取得する
  • その他のInputFieldは変更していないのでInputFieldの値を直接参照する

という使い分けをする必要がありました。

②onValueChanged時にどのInputFieldが入力中かを特定できない

InputText関数(InputFieldのonValueChanged時に呼ばれる関数)には引数としてstring型しか渡せません。
そのため、「今入力されているのがどのInputFieldなのか」を引数からは判断できません。

そこで、isFocusedという変数を使うことにしました。
この変数はUnityスクリプトリファレンスを見ていてたまたま見つけました。
テキストボックスにフォーカスが当たっていればTrue、そうでなければFalseを返します。

InputFieldをFor文でループして、現在フォーカスが当たっていないものの値をチェックするという処理になっています。

③onEndEditだと期待したタイミングにOKボタンが切り替わらない

onEndEditは入力し終えたときに呼ばれるので、テキストボックスに値を入力して別のところをタップして初めて有効になります。

今回はテキストボックスに入力または削除した瞬間にOKボタンを表示・非表示にしたかったので、こちらのイベントではうまくいきませんでした。

まとめ

onValueChangedイベントに好きな引数を持たせられればいいんですけどね。
そしたらisFocusedを使わなくても「何番目のInputFieldか」を渡せば特定ができます。

onClickなんかは引数を持たせられますよね。

まあでも、Unity側で

このように引数が指定されている以上、できないのでしょう。
いろいろ試してみましたが好きな引数を渡すことはできませんでした。

isFocused関数は、もう本当に困ってリファレンスを見に行って見つけたので、リファレンスで使えそうな変数やメソッドがないか探すのは非常に大切なことだなと思いました。

コメントする

メールアドレスが公開されることはありません。