UnityのUI Toolkitのフォーカスイベントを使ってTextFieldにPlaceholderを実装する方法です。
Unity2021.3.16f1
フォーカスイベント
UI Toolkitでは、FocusInEvent
やFocusOutEvent
によりそのUI要素がフォーカスされたときとそのUI要素からフォーカスが外れた時の処理をハンドリングできます。
これらのイベントは他のイベントと同じくRegisterCallback
メソッドで登録できます。
textField.RegisterCallback<FocusInEvent>(OnFocusIn); textField.RegisterCallback<FocusOutEvent>(OnFocusOut);
UI Toolkitにおけるイベントの詳細については以下の記事を参照してください。
Placeholderを表示する
さてそれではこのフォーカスイベントを使ってTextField
にPlaceholder
を表示するスクリプトを書いてみます。
using UnityEditor; using UnityEngine.UIElements; public sealed class PlaceholderExample : EditorWindow { private const string PlaceHolderText = "This is placeholder"; private bool _isPlaceholderVisible; public void CreateGUI() { var textField = new TextField(); rootVisualElement.Add(textField); // フォーカスイベントのコールバックを登録 textField.RegisterCallback<FocusInEvent>(OnFocusIn); textField.RegisterCallback<FocusOutEvent>(OnFocusOut); // 最初はTextFieldが空なのでPlaceholderを表示しておく ShowPlaceHolder(textField); } // フォーカスが当たった時の処理 // もしPlaceholderが表示されていたら非表示にする private void OnFocusIn(FocusInEvent evt) { var textField = (TextField)evt.target; if (!_isPlaceholderVisible) return; HidePlaceHolder(textField); } // フォーカスが外れた時の処理 // もしTextFieldが空ならPlaceholderを表示する private void OnFocusOut(FocusOutEvent evt) { var textField = (TextField)evt.target; var shouldShowPlaceholder = string.IsNullOrEmpty(textField.text); if (!shouldShowPlaceholder) return; ShowPlaceHolder(textField); } private void ShowPlaceHolder(TextField textField) { textField.SetValueWithoutNotify(PlaceHolderText); _isPlaceholderVisible = true; } private void HidePlaceHolder(TextField textField) { textField.value = string.Empty; _isPlaceholderVisible = false; } [MenuItem("Window/PlaceholderExample")] public static void ShowWindow() { GetWindow<PlaceholderExample>("PlaceholderExample"); } }
ポイントはコメントに書いた通りです。
難しいことはしておらず、フォーカスが外れたときにTextField
が空だったらPlaceholderを設定しています。
実行結果は以下のとおりです。
Placeholderにスタイルを設定する
次に、Placeholderの色は大体グレーだったりするので、スタイルを設定するための対応を行います。
まずスタイルシートを以下のように作ります。
.unity-text-field__placeholder > .unity-base-text-field__input { color: #888888; }
次に先ほどのコードに、Placeholderが表示されているときだけこれを適用する処理を追加します。
using UnityEditor; using UnityEngine; using UnityEngine.UIElements; public sealed class PlaceholderExample : EditorWindow { private const string PlaceHolderText = "This is placeholder"; private bool _isPlaceholderVisible; private string _placeholderClassName; public void CreateGUI() { _placeholderClassName = TextField.ussClassName + "__placeholder"; rootVisualElement.styleSheets.Add(Resources.Load<StyleSheet>("style")); var textField = new TextField(); rootVisualElement.Add(textField); textField.RegisterCallback<FocusInEvent>(OnFocusIn); textField.RegisterCallback<FocusOutEvent>(OnFocusOut); ShowPlaceHolder(textField); } private void OnFocusIn(FocusInEvent evt) { var textField = (TextField)evt.target; if (!_isPlaceholderVisible) return; HidePlaceHolder(textField); } private void OnFocusOut(FocusOutEvent evt) { var textField = (TextField)evt.target; var shouldShowPlaceholder = string.IsNullOrEmpty(textField.text); if (!shouldShowPlaceholder) return; ShowPlaceHolder(textField); } private void ShowPlaceHolder(TextField textField) { // スタイルを適用 textField.AddToClassList(_placeholderClassName); textField.SetValueWithoutNotify(PlaceHolderText); _isPlaceholderVisible = true; } private void HidePlaceHolder(TextField textField) { // スタイルを解除 textField.RemoveFromClassList(_placeholderClassName); textField.value = string.Empty; _isPlaceholderVisible = false; } [MenuItem("Window/PlaceholderExample")] public static void ShowWindow() { GetWindow<PlaceholderExample>("PlaceholderExample"); } }
これでPlaceholderのスタイルが適用されました。
Unity2023からはPlaceholder実装されてる
ちなみにUnity2023からはPlaceholderが普通に実装されているようです(バックポートの予定はなさそう)。