UnityVR--UIManager--UI Management 1

Table of contents

Preface

The structure of UI nodes

Components needed

  1. CanvasGroup

  2. OnClick() monitoring of Button and other controls

  3. Event Trigger

Build UI toolset

  1. Management UI node

  2. UIBase includes the following tools

Establishing a sub-panel management tool—taking the main panel MainUi as an example


Preface

  The importance of UI in the project is self-evident, and there are many types of UI controls (the brief introduction to UGUI only lists common controls and important parameters). It is not only necessary to have a unified tool manager to control the initialization and arrangement of each UI node , components, etc., you also need a UIManager to control them uniformly in the project.

  This article mainly introduces the UI tool set UITools. Due to limited space, UIManager will be placed in the next article.

  UITools provides a series of operating tools for UI nodes, especially for highly interactive UI controls such as Button and Slider. Centralized management of these tools will greatly improve code reusability and reduce system consumption.

  Let’s start with the UI node settings in the scene:

The structure of UI nodes

  The structure of the UI panel is roughly as shown below. Different panels use Canvas as a carrier. In the scene display, the node loaded first (the node above) is displayed first, and the node loaded later is overlaid on top:

  For example, click the Play button in the main interface to display one of the EXTRAS panels. This panel should be placed under the main panel node and covered on the main panel when displayed.

  *Note: In many projects, there are no UI nodes in the scene, and the UI exists in the Resource folder as a prefab, as shown below, the UI prefab is made and placed in the Resource/UI folder ( The example used here is downloaded from AssetStore, only the most basic panels are retained):

  The structure of each prefab is as follows:

   

  

UI components needed

  In the previous brief introduction to UGUI , some UI controls were listed. These controls do not necessarily have the components we need to use by default, such as:

  1. CanvasGroup

  

  This component can be placed on the Canvas to achieve the effect of fading in and out of the panel by controlling the Alpha value. If the DoTween plug-in is installed, a simple display animation effect can be achieved (the easing effect curve can be referred to:https://easings.net/) 

       canvasGroup = gameObject.AddComponent<CanvasGroup>(); 
       canvasGroup.interactable = false;  //还没显示完全时不允许交互
       canvasGroup.DOFade(0f, 1f); //安装DoTween插件,控制Alfa值,1s内透明度变成0

       //1.5s内按照OutExpo动画曲线显现,完成后回调
       canvasGroup.DOFade(1f, 1.5f).SetEase(Ease.OutExpo).OnComplete(()=>
       {//完成显示之后的回调
          action?.Invoke();  //执行回调
          canvasGroup.interactable = true;  // 面板可以交互
       });  

  2. OnClick() monitoring of Button and other controls

  The Button button is the most interactive button. OnClick() on it serves as a monitor for button presses and is used very frequently in scenes. The method of binding the listener can be as follows:

  Method 1: Add a script node directly to the OnClick() panel and specify the callback function

   Method 2: Dynamically set in code:

        button = transform.GetComponent<Button>();
        button.onClick.AddListener(()=>
        {
            Debug.Log("没想好要干嘛");
        });

  3. Event Trigger

  Button provides events when the button is pressed, while EventTrigger provides a richer variety of events.

    public enum EventTriggerType
    {
        PointerEnter, //鼠标进入
        PointerExit,  //鼠标离开
        PointerDown,  //鼠标按下
        PointerUp,    //鼠标抬起
        PointerClick, //鼠标点击(鼠标抬起时已不在原UI上时不会触发,在PointerUp之后调用)
        Drag,         //鼠标拖拽
        Drop,         //拖拽结束时鼠标不在被拖拽UI上并且在另外一个UI上时触发(在PointerUp之后)
        Scroll,       //滑轮滚动时
        UpdateSelected, //被选中后的每一帧
        Select,       //在被选中时
        Deselect,     //结束选中时
        Move,         //按方向键时
        InitializePotentialDrag,  //初始化拖拽(在PointerDown之后,PoinerUp之前调用,点击就会调用)
        BeginDrag,    //拖拽开始(鼠标按下不移动不会触发)
        EndDrag,      //拖拽结束
        Submit,       //默认为Enter键
        Cancel        //默认为Enter键
    }

  The method of adding listeners and callbacks is the same as OnClick(). They can also be added in the panel or dynamically added in the script.

  Method 1: Click "AddNewEventType" -> find the event that needs to be bound, click the "+" button, and add the callback function

 

   Method 2: Add in the code

        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.callback = new EventTrigger.TriggerEvent();
        entry.callback.AddListener(callBack);
        entry.eventID = EventTriggerType.PointerClick; //添加PointerClick类型的事件
        transform.GetComponent<EventTrigger>().triggers.Add(entry);

Build UI toolset

   Create a base class UIBase.cs to manage all UI nodes, and set some tool control panel initialization, display, hiding, adding events, etc., which can be easily called in the scene.

  1. Management UI node

 First, we need to obtain and manage all UI nodes. However, as you can see from the UI structure diagram above, the UI has a lot of hierarchical structures and nodes, and it cannot be traversed every time it is used. Therefore, before managing these data, you must first use Tag tags to classify UI controls. Controls that require frequent interaction use the "UIEvent" tag, those that only need to control the display use the "UIGO" tag, and other UI nodes that do not require manipulation at all. Don't use labels.

  Then, all nodes can be managed using the following two methods:

  Method 1: Create a dictionary

    //存储一下需要用到的UIGO,以防止每次都去所有节点查找一遍
    private Dictionary<string, GameObject> uiItem;

  Then when the panel is initialized, all nodes are added to the dictionary. (See the initialization tool code below for details)

  Method 2: Drag directly into the panel

    If there are not many nodes, you can create a batch of public GameObjects and simply drag the corresponding UI nodes directly into the panel, for example:

        [Header("MENUS")]
        [Tooltip("The Menu for when the MAIN menu buttons")]
        public GameObject mainMenu;
        [Tooltip("THe first list of buttons")]
        public GameObject firstMenu;
        [Tooltip("The Menu for when the PLAY button is clicked")]
        public GameObject playMenu;
        [Tooltip("The Menu for when the EXIT button is clicked")]
        public GameObject exitMenu;
        [Tooltip("Optional 4th Menu")]
        public GameObject extrasMenu;

  Then drag them in one by one.

The following is a detailed introduction to the UIBase.cs implementation process:

  2. UIBase includes the following tools

  (1) Initialization - The tasks that need to be implemented include: traversing the UI nodes and putting them into dictionary management, attaching the EventTrigger component to the node with the "UIGO" label, and attaching the CanvasGroup component to the root node (Canvas).

    private Dictionary<string, GameObject> uiItem;  //字典用于存储UI节点

    public virtual void InitPanel(UnityAction action=null)
    {
        uiItem= new Dictionary<string, GameObject>();//实例化字典对象
        List<Transform> list= new List<Transform>(); //建立一个列表用于存储节点
        FindChild(transform,list);  
        //使用自定义的FindChild方法遍历当前节点以下的所有子节点,并存入list

        foreach (var item in list)
        {
           if(!uiItem.ContainsKey(item.name))
              uiItem.Add(item.name, item.gameObject);//把这个节点放进字典

           //判断如果是按钮组件,就添加EventTrigger
            if(item.CompareTag("UIEvent"))
            {
                var trigger=item.gameObject.AddComponent<EventTrigger>();
                if (trigger.triggers.Count== 0)
                   trigger.triggers=new List<EventTrigger.Entry>(); 
            }               
        }
        canvasGroup = gameObject.GetComponent<CanvasGroup>();
        //获取UI根节点的CanvasGroup,以便于控制实现面板慢慢显现的特效
        action?.Invoke();  //如果有回调的话回调
    }

  Among them, the method of traversing child nodes can be summarized as a small tool:

    //一个查找子物体的工具,从当前节点开始找
    private void FindChild(Transform father,List<Transform> list)
    {
        if(father.childCount> 0)
        {
            for(int i=0;i<father.childCount;i++)
            {
                list.Add(father.GetChild(i));
                FindChild(father.GetChild(i),list);
            }
        }
        return;
    }

  (2) Display panel - if DoTween is not used, but displayed directly

    //显示面板
    public virtual void Show(UnityAction action=null)
    {
        gameObject.SetActive(true);  //节点激活
        action?.Invoke();
    }

    If you use DoTween to make a small fade-out animation, then the Show tool is written as follows:

    //显示面板
    public virtual void Show(UnityAction action=null)
    {
        gameObject.SetActive(true);  //节点激活
        switch(showType) //显示的方式ShowType定义为一个枚举数据
        {
            case ShowType.Normal:   
                action?.Invoke();
                break;
            case ShowType.Fade:
            {
                if (canvasGroup == null)
                    { canvasGroup = gameObject.AddComponent<CanvasGroup>(); }
                canvasGroup.interactable = false;  //还没显示完全时不允许交互
                canvasGroup.DOFade(0f, 0f); //DoTween插件,控制Alfa值,透明度变成0,1s时间
                canvasGroup.DOFade(1f, 1.5f).SetEase(Ease.OutExpo).OnComplete(()=>
                {
                    action?.Invoke();
                    canvasGroup.interactable = true;  // 可以交互
                });  //1.5s内按照OutExpo动画曲线显现,完成后回调
            }
                break;
        }
    }   

 The display method ShowType is summarized into an enumeration:

public enum ShowType
{
    Normal, Fade, Mask      //直接显示,渐显效果,遮罩
}

  (3) Hidden panel - the structure is similar to the display panel. In order to save space, DoTween is not used here. If you need to use DoTween, you can copy and modify the above display panel code.

    //隐藏
    public virtual void Hide(UnityAction action=null)
    {
      action?.Invoke();
      gameObject.SetActive(false);
    }

  (4) Get components - there are many types of UI components, so use generic methods to get components

    protected T GetComponent<T>(string name) where T : MonoBehaviour
    {
        if (!uiItem.ContainsKey(name)) return null;  //如果没有这个组件就返回空
        return uiItem[name].GetComponent<T>();
    }

  (5) Add the EventTrigger component to the control and register the event - the method has been explained above

    public void AddEventTrigger(string controlName,EventTriggerType type,
        UnityAction<BaseEventData> callBack)
    {
        //从字典中获取控件,并添加EventTrigger组件
        if(!uiItem.ContainsKey(controlName)) return;
        if (uiItem[controlName].gameObject.GetComponent<EventTrigger>()==null)
            uiItem[controlName].AddComponent<EventTrigger>();
        //添加Entry、监听、回调
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.callback = new EventTrigger.TriggerEvent();
        entry.callback.AddListener(callBack);  
        entry.eventID = type;
        uiItem[controlName].GetComponent<EventTrigger>().triggers.Add(entry);
    }

  The above is the general UI panel management tool, specific to each UI panel, such as the main panel Canvas_Main, exit panel Canv_EXIT, some game projects also have backpack panels, ranking panels, etc., which need to be rewritten according to different situations. tool. Let's take the main panel as an example and write the script MainUi.cs for main panel management.

Establishing a sub-panel management tool—taking the main panel MainUi as an example

  For a sub-panel, the work that needs to be done includes: rewriting initialization tools, display tools, etc.; adding components, events and callbacks on key nodes; obtaining components of important nodes, such as pictures, text and other components, for subsequent control etc.

public class MainUI : UITools
{//针对MainUI节点的工具,之后会使用UIManager动态挂在主面板上,提前挂好也可以
    
    public override void Init(UnityAction action = null) //重写UITools的Init()
    {
        base.Init(action);   
        //给Button_Play按钮添加一个PointerClick事件和回调
        AddEventTrigger("Button_Play", EventTriggerType.PointerClick, OnEventStart);
        //给Button_Extras按钮添加一个PointerClick事件和回调
        AddEventTrigger("Button_Extras", EventTriggerType.PointerClick, OnEventEnd);
        //给Button_Exit按钮添加一个PointerClick事件和回调
        AddEventTrigger("Button_Exit", EventTriggerType.PointerClick, OnEventExit);
    }

    private void OnEventStart(BaseEventData data)
    {
        UIManager.Instance.ShowPanel<ExtraUi>("ExtraPanel", "EXTRAS", null, UIManager.PanelType.Extra);  //点Button_Play按钮显示EXTRAS面板
    }

    private void OnEventEnd(BaseEventData data)
    {
        UIManager.Instance.HidePanel("ExtraPanel"); //点Button_Extras按钮隐藏EXTRAS面板
    }

    private void OnEventExit(BaseEventData data)
    {
        UIManager.Instance.ShowPanel<ExitUi>("ExitPanel", "EXIT", null, UIManager.PanelType.UP);  //点Button_Exit按钮弹出询问是否退出面板
    }
}

  The above are the tools needed for the main panel MainUi. The tool classes of other panels can also be written with reference to it. Among them, UIManager is used in the two callback methods, which will overall manage the initialization, layout, etc. of the entire UI node. You can refer to the definition of UIManager in the next article.

Guess you like

Origin blog.csdn.net/tangjieitc/article/details/131183707