1.按如下结构建立一个Tabs

2.Tabs上添加Toggle Group组件

3.Tab上添加Toggle、ToggleHighlightStaysActiveAfterLosingFocus

4.Page上添加Canvas Group

5.在Menu上添加TabMenu,系统会自动识别,无需手动赋值(识别错误的话见下文)。这样就完成了Tab控件的制作

6.如果Page下有Toggle,TabMenu会识别错误,需要手动赋值。
解决方法:注释TabMenu.cs以下代码,再手动赋值

7.设定初始选中项,将对应的Tab下的Toggle的isOn勾上,其余Tab的取消勾选就可以了。
附:
TabMenu.cs代码
cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace ChristinaCreatesGames.UI
{
public class TabMenu : MonoBehaviour
{
[Header("Current Index")]
[SerializeField] private int pageIndex = 0;
[Header("Components")]
[SerializeField] private ToggleGroup toggleGroup;
[SerializeField] private List<Toggle> tabs = new List<Toggle>();
[SerializeField] private List<CanvasGroup> pages = new List<CanvasGroup>();
[Header("Event to call")]
public UnityEvent<int> OnPageIndexChanged;
private void Initialize()
{
toggleGroup = GetComponentInChildren<ToggleGroup>();
tabs.Clear();
pages.Clear();
tabs.AddRange(GetComponentsInChildren<Toggle>());
pages.AddRange(GetComponentsInChildren<CanvasGroup>());
}
private void Reset()
{
Initialize();
}
private void OnValidate()
{
Initialize();
OpenPage(pageIndex);
tabs[pageIndex].SetIsOnWithoutNotify(true);
}
private void Awake()
{
foreach (var toggle in tabs)
{
toggle.onValueChanged.AddListener(CheckForTab);
toggle.group = toggleGroup;
}
}
private void OnDestroy()
{
foreach (var toggle in tabs)
{
toggle.onValueChanged.RemoveListener(CheckForTab);
}
}
private void CheckForTab(bool value)
{
for (int i = 0; i < tabs.Count; i++)
{
if (!tabs[i].isOn) continue;
pageIndex = i;
}
OpenPage(pageIndex);
}
private void OpenPage(int index)
{
EnsureIndexIsInRange(index);
for (int i = 0; i < pages.Count; i++)
{
bool isActivePage = (i == pageIndex);
pages[i].alpha = isActivePage ? 1.0f : 0.0f;
pages[i].interactable = isActivePage;
pages[i].blocksRaycasts = isActivePage;
}
if (Application.isPlaying)
OnPageIndexChanged?.Invoke(pageIndex);
}
private void EnsureIndexIsInRange(int index)
{
if (tabs.Count == 0 || pages.Count == 0)
{
Debug.Log("Forgot to setup Tabs or Pages");
return;
}
pageIndex = Mathf.Clamp(index, 0, pages.Count - 1);
}
public void JumpToPage(int page)
{
EnsureIndexIsInRange(page);
tabs[pageIndex].isOn = true;
}
}
}
ToggleHighlightStaysActiveAfterLosingFocus.cs代码
cs
using UnityEngine;
using UnityEngine.UI;
namespace ChristinaCreatesGames.UI
{
public class ToggleHighlightStaysActiveAfterLosingFocus : MonoBehaviour
{
[SerializeField] private Toggle toggle;
[SerializeField] private Image imageToKeepFocusActive;
private void Reset()
{
toggle = GetComponent<Toggle>();
}
private void Awake()
{
toggle.onValueChanged.AddListener(OnToggleValueChanged);
OnToggleValueChanged(toggle.isOn);
}
private void OnDestroy()
{
toggle.onValueChanged.RemoveListener(OnToggleValueChanged);
}
private void OnToggleValueChanged(bool isOn)
{
if (imageToKeepFocusActive == null) return;
imageToKeepFocusActive.color = toggle.isOn ? toggle.colors.highlightedColor : Color.clear;
}
}
}