Posted at

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

More than 3 years have 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を見る。 みたいな処理が必要だった(はず)