初めに
ToggleのOn/Offの切り替え時にメソッドを呼び出したいとき、OnValueChangedにメソッドをAddListenerすることが多いと思う。
これと同じように、複数のToggleをToggleGroupで管理してOn/Offの切り替え時にメソッドを呼び出そうとした時、微妙な挙動の違いでメソッドが複数回呼び出されてハマったのでメモしておく。
環境
Unity:2019.1.5f1
起こったこと
設定は以下のスクショの通り。
Toggle3つ(A,B,C)をToggleGroupで管理し、どれか一つのみにチェックが入るようになっている。
ToggleGroupには以下のコードをアタッチ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class ToggleController : MonoBehaviour
{
public void Change()
{
Toggle activeToggle = this.gameObject.GetComponent<ToggleGroup>().ActiveToggles().First();
Debug.Log(activeToggle.name);
}
}
各ToggleのOnValueChangedにChangeメソッドをインスペクタからアタッチする。
すると、次のような挙動をする。
メソッドが2回呼び出されているようだ。
これは、例えばB→AとToggleを切り替える時
BがOffになる時のOnValueChangedとAがOnになる時のOnValueChangedが両方動いてしまうことが原因である。
つまりOnValueChangedはチェックマーク(isOn)がついた時ではなくToggleの状態が変わった時に発火するようだ。
対処法
コードを次のように修正した。
なお、特に大差はないがスクリプトからメソッドをAddListenerした。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class ToggleController : MonoBehaviour
{
public ToggleGroup toggleGroup;
private void Start()
{
var toggles = toggleGroup.gameObject.GetComponentsInChildren<Transform>();
foreach (var toggle in toggles)
{
if (toggle.GetComponent<Toggle>() != null)
{
toggle.GetComponent<Toggle>().onValueChanged.AddListener(Change);
}
}
}
public void Change(bool state)
{
if (state)
{
Toggle activeToggle = this.gameObject.GetComponent<ToggleGroup>().ActiveToggles().First();
Debug.Log(activeToggle.name);
}
}
}
変更点はChangeメソッドに引数を持たせたことである。
実際はこのメソッドは2回呼び出されているのだが、引数のstateでToggleにチェックが入っているかどうかを判断しているため、中の処理が行われるのは1回になる。
まとめ
- ToggleGroupのToggleのOnValueChangedを使うときは、処理が重複しないよう注意が必要
- やりたい処理に応じて2つの挙動を使い分けることが大事
- Toggleにはあまり複雑な処理を持たせない方が良い気もする
- 頑張ればButtonでもできる
最後に
ここまで読んでいただきありがとうございました。
投稿者はまだまだUnity初心者のため、アドバイスやコメント等あればお待ちしております。
この記事が何かのお役に立てれば幸いです。