- Home /
What is the "correct" way to switch UI panels - 4.6?
What is the correct way to switch between UI panels in the new UI system? For example: I have a menu, it has 4 sub-menus--the default one (play, options quit), the play menu (character/save selection), the options menu (graphics, etc.), and confirm quit menu. Now, what is the correct way to switch between these sub-menus? Should I just disable and enable the objects or do something else?
What I've seen is that the animation window is used for these and they fade them in and out. It's pretty cool and works pretty good as a "correct" way.
Answer by junglemason · Mar 17, 2015 at 11:07 PM
My preferred way is to assign a CanvasGroup component to anything I want to show/hide. I leave it in its position, and just set the alpha and can toggle whether it accepts user input. All the properties of a CanvasGroup are automatically applied to all of its children (unless the child is a CanvasGroup that is set to ignore its parent).
I don't have to worry about screen size when moving something off-screen to hide it.
I will always have access to its properties since the GameObject is never deactivated.
I can use the Alpha property of the CanvasGroup to fade the element in and out.
I can easily make that UI element and all of its descendants temporarily not receive input while still being visible.
I don't believe in performance of CanvasGroup. It must have something costly to do. Otherwise it should have been added by default. New UI System is terribly bad in performance. It's good in almost cases for interactive UI whereas we don't need really many panels. But in some cases when the number of panels is fairly large, the performance drops seriously. If you have 1000 of static panels, it's still O$$anonymous$$. But when any UI element (on the same Canvas) changes (position, scale, text, ...) it can drop the framerate from 60 to just about 20-30. Terrible design. Think about showing animated text (damage text) when enemy is hit by many bullets. I'm currently using panels to hold Texts (having an Animator). I spent a few hours finding out how it goes bad that way. I'm still trying to improve it but finally I would not use panels to wrap Texts (and won't be able to use Animator).
Now that everyone is on 5.6. Is CanvasGroup still the way to go? Seems to work well for my puzzle game with simple ScrollList $$anonymous$$enu.
Anorak
Answer by Kiwasi · Aug 27, 2014 at 07:50 PM
Multiple options exist. Each has its own benefits and drawbacks. As far as I can tell there is no definitive 'correct' way to accomplish this. If your menu is performance constrained then bench marking on your current device is required.
Enable and disable (this will cause OnEnable and OnDisable to run)
Instantiate and destroy (not recommended, will kill you on the GC)
Moving in the hierarchy so its rendered behind the current panel (causes an increase in draw calls)
Moving the inactive windows off screen, or disabling or modifying renderers (Good for animated effects)
$$anonymous$$oving inactive windows offscreen lets you see everything in editor, it's nice for designing a complex UI with tabs.
Problem is that unity ui doesnt'cull stuff out of canvas, see here http://forum.unity3d.com/threads/draw-call-not-reduced-when-ui-out-of-canvas.265170/
=> I'll just use a script to disable all the offscreen stuff on start!
I tend to use the disable in start approach too. Sort of.
What I actually do is run a coroutine from Start to disable after one frame. That lets a bunch of scripts run GameObject.Find to grab the menu panels they are interested in before they get disabled.
Answer by Bentoon · Aug 30, 2014 at 04:19 AM
Good Question. I am interested in BoredMormons 1st approach
I am not a C# person but it might look something like:
and then I think it could look like : void onSomeTrigger() { enable(panelOne); )
void onEnable() {
if(panelOne.Renderer.disabled) {
panelOne.Renederer.enable;
}
}
(remember to instantiate the new UI in code)
EDIT: Thanks BoredMormon that would be great
here is another simple way:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
public class mouseUp2 : MonoBehaviour {
public GameObject Panel2Disappear;
public GameObject Panel2Appear;
void OnMouseUp () {
Debug.Log("MouseHit");
Panel2Disappear.SetActive(false);
Panel2Appear.SetActive(true);
}
}
Although I Love sub zeros idea of Animating the change... that would be brilliant!
best
~be
I'll post the actual code later on if you like. Not currently on my Unity computer.
So, I'm trying the same thing but am not getting it to work correctly. $$anonymous$$y UI buttons won't change in the game view, but will change in the scene view after I stop playing the game (or will show up changed when I start the game again).
The problem is on line 19 (the method $$anonymous$$enu$$anonymous$$enu). I have 1 canvas, with empties childed to it (what I'm turning on/off), and buttons childed to those empties.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class UiButtons : $$anonymous$$onoBehaviour {
public GameObject menu$$anonymous$$enu, start$$anonymous$$enu;
public void Restart() {
Application.LoadLevel ("$$anonymous$$all_And_Phone");
}
public void Quit() {
Application.Quit();
}
public void $$anonymous$$enu$$anonymous$$enu(){
print ("one");
start$$anonymous$$enu.SetActive(false);
print ("two");
menu$$anonymous$$enu.SetActive (true);
print ("three");
}
public void BackToStart(){
start$$anonymous$$enu.SetActive(true);
menu$$anonymous$$enu.SetActive (false);
}
}
Answer by GXMark · Mar 28, 2015 at 01:31 PM
Canvas kills your performance if you have alot GUI controls. But ok for smaller GUI's
Answer by darshie1976 · Mar 19, 2016 at 05:02 PM
Keep in mind that hiding the panel changing the alpha of the canvasgroup is not deactivating the controls; you will discover that if you use the mouse while the panel is hidden, if you have controls on it, they will be reacting to mouse clicks for example.
So far the best way that I found to swap panels is to use both the alpha to make them hiddne, and at the same time, set to false the interactable to false, so even if you click on the screen you won't affect the controls.
I did not have luck with setActive(), but using this approach it works just fine
Your answer