During screen transitions I disable user input, as the screen we are leaving does not want any more input and the screen we are going to may not quite be ready. So I was hoping that the 4.6 beta 20 release notes of:
UI: Allow users to enable / disable navigation on a global level (including submit / cancel keys). See: EventSystem.current.sendNavigationEvents
meant that it would also disable touch and mouse navigation events but it appears that these still go through.
So I’ve done some research and identified a few methods that could be used:
- CanvasGroup.Interactable
I’m not sure if this would change the visual state of child objects, for example buttons that disabled state. Plus I’m writing a bit of generic script that wants to disable input during a transition. It does not know what canvas(es) are active or may become active during the transition and I do not wish to search each frame. - Separate catch all canvas
This seems like a reasonably clean method, but not quite as clean as the solution I came up with. Under this idea you would have a separate Canvas which can be enabled when you want it to catch mouse clicks. It would contain a full screen transparent image component to catch the click. To ensure it gets clicks over any other canvases set it’s GraphicRaycaster.Priority to a lower value than any others. You could also experiment with using the Blocking objects / Blocking Mask of GraphicRaycaster
However I would prefer to disable the clicks at the source in the EventSystem so came up with the following solution which does not require any extra canvas or knowledge of which canvas(es) or cameras are currently in use. If you come across a better solution please let me know in the comments below or on twitter @hersee.
using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.EventSystems; public class UIDisableInput { // Keep a list of pointer input modules that we have disabled so that we can re-enable them static List<PointerInputModule> disabled = new List<PointerInputModule>(); static int disableCount = 0; // How many times has disable been called? public static void Disable() { if(disableCount++ == 0) { UpdateState(false); } } public static void Enable(bool enable) { if(!enable) { Disable(); return; } if (--disableCount == 0) { UpdateState(true); if (disableCount > 0) { Debug.LogWarning("Warning UIDisableInput.Enable called more than Disable"); } } } static void UpdateState(bool enabled) { // First re-enable all systems for (int i = 0; i < disabled.Count; i++) { if (disabled[i]) { disabled[i].enabled = true; } } disabled.Clear(); EventSystem es = EventSystem.current; if (es == null) return; es.sendNavigationEvents = enabled; if (!enabled) { // Find all PointerInputModules and disable them PointerInputModule[] pointerInput = es.GetComponents<PointerInputModule>(); if (pointerInput != null) { for (int i = 0; i < pointerInput.Length; i++) { PointerInputModule pim = pointerInput[i]; if (pim.enabled) { pim.enabled = false; // Keep a list of disabled ones disabled.Add(pim); } } } // Cause EventSystem to update it's list of modules es.enabled = false; es.enabled = true; } } }