「Unity/TMPro/Dropdown」の版間の差分

提供: 初心者エンジニアの簡易メモ
ナビゲーションに移動 検索に移動
 
(同じ利用者による、間の4版が非表示)
51行目: 51行目:


==Dropdownを開いたときに選択した項目を表示する方法==
==Dropdownを開いたときに選択した項目を表示する方法==
UIのButtonをDropdownに被せて、ButtonをクリックしたときにDropdownを開く以下処理を走らせる。
UIのButtonをDropdownに被せて(Imageを透明に)、ButtonをクリックしたときにDropdownを開く以下処理を走らせる。


選択Indexが表示領域の中央より上なら、スクロールしないように。
選択Indexが表示領域の中央より上なら、スクロールしないように。
75行目: 75行目:
     {
     {
         dropdown.Show();
         dropdown.Show();
         await ScrollToSelectedAsync();
         await DropdownScrollUtil.AdjustScroll(dropdown.gameObject);
     }
     }
}
</pre>
DropdownScrollUtil.cs
<pre>
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
using TMPro;


     async UniTask ScrollToSelectedAsync()
// Dropdownのスクロール位置調整
// 選択Indexが表示領域の中央より上なら、スクロールしないように
// 使い方:await DropdownScrollUtil.AdjustScroll(dropdown.gameObject);
public static class DropdownScrollUtil
{
     public static async UniTask AdjustScroll(GameObject dropdownObj)
     {
     {
         // UI生成待ち(超重要)
        var dropdown = dropdownObj.GetComponent<TMP_Dropdown>();
        if (dropdown == null) return;
 
         // UI生成待ち(Dropdown開いた直後は要る)
         await UniTask.NextFrame();
         await UniTask.NextFrame();
         await UniTask.NextFrame();
         await UniTask.NextFrame();
91行目: 107行目:
         if (totalCount <= 1) return;
         if (totalCount <= 1) return;


        // ===== 表示行数を計算 =====
         var viewport = scrollRect.viewport.rect.height;
         var viewport = scrollRect.viewport.rect.height;
         var content = scrollRect.content;
         var content = scrollRect.content;
102行目: 117行目:
         int centerIndex = visibleCount / 2;
         int centerIndex = visibleCount / 2;


         // ===== 中央まではスクロールしない =====
         // 中央まではスクロールしない
         if (index <= centerIndex)
         if (index <= centerIndex)
         {
         {
109行目: 124行目:
         }
         }


        // ===== 中央を超えたらスクロール =====
         float scrollIndex = index - centerIndex;
         float scrollIndex = index - centerIndex;
         float maxScrollIndex = totalCount - visibleCount;
         float maxScrollIndex = totalCount - visibleCount;
145行目: 159行目:
     {
     {
         dropdown.Show();
         dropdown.Show();
         StartCoroutine(ScrollToSelected());
         StartCoroutine(DropdownScrollUtil.AdjustScroll(dropdown.gameObject));
     }
     }
}
</pre>
DropdownScrollUtil.cs
<pre>
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;


     IEnumerator ScrollToSelected()
// 使い方:StartCoroutine(DropdownScrollUtil.AdjustScroll(dropdown.gameObject));
public static class DropdownScrollUtil
{
     public static IEnumerator AdjustScroll(GameObject dropdownObj)
     {
     {
         // UI生成待ち(超重要)
        var dropdown = dropdownObj.GetComponent<TMP_Dropdown>();
        if (dropdown == null) yield break;
 
         // UI生成待ち
         yield return null;
         yield return null;
         yield return null;
         yield return null;
156行目: 185行目:
         var scrollRect = dropdown.GetComponentInChildren<ScrollRect>();
         var scrollRect = dropdown.GetComponentInChildren<ScrollRect>();
         if (scrollRect == null) yield break;
         if (scrollRect == null) yield break;
        var content = scrollRect.content;
        if (content.childCount == 0) yield break;


         int index = dropdown.value;
         int index = dropdown.value;
164行目: 190行目:
         if (totalCount <= 1) yield break;
         if (totalCount <= 1) yield break;


         // ===== 表示行数を計算 =====
         var viewport = scrollRect.viewport.rect.height;
        float viewportHeight = scrollRect.viewport.rect.height;
        var content = scrollRect.content;
         float itemHeight =
 
            ((RectTransform)content.GetChild(0)).rect.height;
        if (content.childCount == 0) yield break;
 
         float itemHeight = ((RectTransform)content.GetChild(0)).rect.height;
        int visibleCount = Mathf.FloorToInt(viewport / itemHeight);


        int visibleCount = Mathf.FloorToInt(viewportHeight / itemHeight);
         int centerIndex = visibleCount / 2;
         int centerIndex = visibleCount / 2;


         // ===== 中央まではスクロールしない =====
         // 中央まではスクロールしない
         if (index <= centerIndex)
         if (index <= centerIndex)
         {
         {
179行目: 207行目:
         }
         }


         // ===== 中央を超えたらスクロール =====
         float scrollIndex = index - centerIndex;
         float maxScrollIndex = totalCount - visibleCount;
         float maxScrollIndex = totalCount - visibleCount;
         if (maxScrollIndex <= 0)
         if (maxScrollIndex <= 0)
         {
         {
187行目: 216行目:
         }
         }


        float scrollIndex = index - centerIndex;
         float normalizedPos = 1f - (scrollIndex / maxScrollIndex);
         float normalizedPos = 1f - (scrollIndex / maxScrollIndex);
         scrollRect.verticalNormalizedPosition = Mathf.Clamp01(normalizedPos);
         scrollRect.verticalNormalizedPosition = Mathf.Clamp01(normalizedPos);
     }
     }
}
}
</pre>
</pre>

2026年3月22日 (日) 16:54時点における最新版

TMP_Dropdownのスクリプトで制御

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class SettingScene : MonoBehaviour
{
    TMP_Dropdown areaDropdown;
    List<string> areas;
    string area;
    void Start()
    {
        AreaDropdownInit();
        areaDropdown = this.transform.Find("AreaDropdown").GetComponent<TMP_Dropdown>();
        areaDropdown.onValueChanged.AddListener(delegate {
            AreaDropdownValueChanged(areaDropdown);
        });
    }
    void AreaDropdownInit()
    {
        areas = new List<string>();
        areas.Add("simple");
        areas.Add("sabaku");
        areas.Add("sushi");
        List<TMP_Dropdown.OptionData> optionMessages = new List<TMP_Dropdown.OptionData>();
        TMP_Dropdown areaDropdown = this.transform.Find("AreaDropdown").GetComponent<TMP_Dropdown>();
        areaDropdown.ClearOptions();
        foreach (string area in areas)
        {
            TMP_Dropdown.OptionData optionData;
            optionData = new TMP_Dropdown.OptionData();
            optionData.text = area;
            optionMessages.Add(optionData);
        }
        foreach (TMP_Dropdown.OptionData message in optionMessages)
        {
            areaDropdown.options.Add(message);
        }
        areaDropdown.value = areas.IndexOf(area);
        this.transform.Find("AreaDropdown/Label").GetComponent<TextMeshProUGUI>().text = areas[areaDropdown.value].ToString();
    }
    void AreaDropdownValueChanged(TMP_Dropdown change)
    {
        area = areas[change.value];
        this.transform.Find("AreaDropdown/Label").GetComponent<TextMeshProUGUI>().text = areas[areaDropdown.value].ToString();
    }
}

UIのButtonをDropdownに被せて(Imageを透明に)、ButtonをクリックしたときにDropdownを開く以下処理を走らせる。

選択Indexが表示領域の中央より上なら、スクロールしないように。

UniTaskバージョン

using Cysharp.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class TMPDropdownScrollFix : MonoBehaviour
{
    [SerializeField]
    public TMP_Dropdown dropdown;
    [SerializeField]
    private Button button;
    void Start()
    {
        button.onClick.AddListener(() => OpenDropdownAsync().Forget());
    }
    public async UniTaskVoid OpenDropdownAsync()
    {
        dropdown.Show();
        await DropdownScrollUtil.AdjustScroll(dropdown.gameObject);
    }
}

DropdownScrollUtil.cs

using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
using TMPro;

// Dropdownのスクロール位置調整
// 選択Indexが表示領域の中央より上なら、スクロールしないように
// 使い方:await DropdownScrollUtil.AdjustScroll(dropdown.gameObject);
public static class DropdownScrollUtil
{
    public static async UniTask AdjustScroll(GameObject dropdownObj)
    {
        var dropdown = dropdownObj.GetComponent<TMP_Dropdown>();
        if (dropdown == null) return;

        // UI生成待ち(Dropdown開いた直後は要る)
        await UniTask.NextFrame();
        await UniTask.NextFrame();

        var scrollRect = dropdown.GetComponentInChildren<ScrollRect>();
        if (scrollRect == null) return;

        int index = dropdown.value;
        int totalCount = dropdown.options.Count;
        if (totalCount <= 1) return;

        var viewport = scrollRect.viewport.rect.height;
        var content = scrollRect.content;

        if (content.childCount == 0) return;

        float itemHeight = ((RectTransform)content.GetChild(0)).rect.height;
        int visibleCount = Mathf.FloorToInt(viewport / itemHeight);

        int centerIndex = visibleCount / 2;

        // 中央まではスクロールしない
        if (index <= centerIndex)
        {
            scrollRect.verticalNormalizedPosition = 1f;
            return;
        }

        float scrollIndex = index - centerIndex;
        float maxScrollIndex = totalCount - visibleCount;

        if (maxScrollIndex <= 0)
        {
            scrollRect.verticalNormalizedPosition = 1f;
            return;
        }

        float normalizedPos = 1f - (scrollIndex / maxScrollIndex);
        scrollRect.verticalNormalizedPosition = Mathf.Clamp01(normalizedPos);
    }
}

コルーチンパターン

using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class TMPDropdownScrollFix : MonoBehaviour
{
    [SerializeField]
    public TMP_Dropdown dropdown;
    [SerializeField]
    private Button button;
    void Start()
    {
        button.onClick.AddListener(() => OpenDropdown());
    }
    void OpenDropdown()
    {
        dropdown.Show();
        StartCoroutine(DropdownScrollUtil.AdjustScroll(dropdown.gameObject));
    }
}

DropdownScrollUtil.cs

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

// 使い方:StartCoroutine(DropdownScrollUtil.AdjustScroll(dropdown.gameObject));
public static class DropdownScrollUtil
{
    public static IEnumerator AdjustScroll(GameObject dropdownObj)
    {
        var dropdown = dropdownObj.GetComponent<TMP_Dropdown>();
        if (dropdown == null) yield break;

        // UI生成待ち
        yield return null;
        yield return null;

        var scrollRect = dropdown.GetComponentInChildren<ScrollRect>();
        if (scrollRect == null) yield break;

        int index = dropdown.value;
        int totalCount = dropdown.options.Count;
        if (totalCount <= 1) yield break;

        var viewport = scrollRect.viewport.rect.height;
        var content = scrollRect.content;

        if (content.childCount == 0) yield break;

        float itemHeight = ((RectTransform)content.GetChild(0)).rect.height;
        int visibleCount = Mathf.FloorToInt(viewport / itemHeight);

        int centerIndex = visibleCount / 2;

        // 中央まではスクロールしない
        if (index <= centerIndex)
        {
            scrollRect.verticalNormalizedPosition = 1f;
            yield break;
        }

        float scrollIndex = index - centerIndex;
        float maxScrollIndex = totalCount - visibleCount;

        if (maxScrollIndex <= 0)
        {
            scrollRect.verticalNormalizedPosition = 1f;
            yield break;
        }

        float normalizedPos = 1f - (scrollIndex / maxScrollIndex);
        scrollRect.verticalNormalizedPosition = Mathf.Clamp01(normalizedPos);
    }
}