C#
Unity
2D
uGUI

Unity標準UIのInputFieldはScroll出来ないので対処法

More than 1 year has passed since last update.

InputFieldの罠

Unity標準UIのInputFieldには微妙なバグ(仕様?)があります。
たとえば、こんな感じで
Unity (64bit) - Untitled - stv_sample01 - Android_ _DX11 on DX9 GPU_ 2016-07-15 16.05.49.png

全画面InputFieldしか無い画面をScrollViewのContentに配置すると
スクロールさせようとタップした途端にInputFieldにフォーカスがあたってしまい、スクロールがキャンセルされてしまうのです。
なのでこの画像の例だと、InputField(16)を選択するのがすごく大変になります(ScrollBarでスクロールさせるか、Editor/PCならマウスホイールでできなくもないですが・・・いけてない)

なお、同じく標準UIのButtonなんかはスクロールも出来るし、タップも出来るんですよ。おかしくないですか。

あーあ。次のバージョンで修正されるといいなー。

と。そうも言ってられないので今できる事をしましょう。

前述の通りInputFieldはスクロール対応じゃないですが、Buttonはスクロール対応なので、InputFieldの上に同じサイズの透明なButtonをかぶせてしまう荒業を試してみます。
Unity (64bit) - Untitled - stv_sample01 - Android_ _DX11 on DX9 GPU_ 2016-07-15 16.14.50.png

上記のように一つ親(ScrollableInputField)を作って、その中にInputFieldとButtonを。

なおButtonはボタン判定はあるけど、見えない(InputFieldを隠さない)ようにしなくてはなので

Unity (64bit) - Untitled - stv_sample01 - Android_ _DX11 on DX9 GPU_ 2016-07-15 16.16.02.png

α値を0にしたり、TransitionをNoneにしたりしておきます。
(※このScrollableInputFieldをPrefab化して使う。)

わーい、これでスクロール出来るぞ!!
Unity (64bit) - Untitled - stv_sample01 - Android_ _DX11 on DX9 GPU_ 2016-07-15 16.35.31.png

スクロールは出来るようになった。 がしかし・・・。

しかしこれだとInputFieldに入力できないんですよね。
まぁ、そりゃそうです。上にかぶさっているボタンがタップイベントを奪うので、InputFieldにフォーカスが行かなくなってしまっています。

なので一工夫。この透明ボタンのonClickにInputFieldのactivate処理を入れてあげれば上手く行きそうです。

以下ソース

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

public class ScrollableInputField : MonoBehaviour
{
    [SerializeField]
    private InputField _targetInputField;

    [SerializeField]
    private Button _guardButton;

    public UnityEvent OnFocus = new UnityEvent();

    void Start ()
    {
        _guardButton.onClick.AddListener(() =>
        {
            _targetInputField.ActivateInputField();
            OnFocus.Invoke();
        });
    }
}

めちゃめちゃ短いですね。
そして忘れずにInspectorでInputFieldとButtonをセットしておきます。

Unity (64bit) - Untitled - stv_sample01 - Android_ _DX11 on DX9 GPU_ 2016-07-15 16.43.11.png

これで、ドラッグでスクロールできるし、タップすれば入力が出来るInputFieldの完成です!

良いScrollライフを。

おまけ

ところで謎のUnityEvent OnFocusがあります。
これは折角ボタンのOnClickでフォーカスを発生させているので、副次的な効果としてフォーカスの取得もUnityEvent化してしましまいました。
(余計なお世話な人は消しちゃってください。)

まぁ、見ての通り非常にシンプルで、ボタンクリックイベントでフォーカスするついでに
OnFocused.Invoke(this);
とするだけで外部から擬似的にフォーカスイベントが取れる形になるのでお得感あります。1

例えばフォーカスが当たると同時にそのInputFieldを画面の真ん中に持ってくる(ScrollRectのvertical(holizontal)NormalizedPositionを良い感じに変更する)みたいなことがやりたい場合に便利です。

お試しあれ~


  1. InputFieldにはOnFocus的なイベントが存在せず毎フレームisFocusedを見る。 みたいな処理が必要だった(はず)