Home > database >  how to change multiple UI elements on runtime
how to change multiple UI elements on runtime

Time:04-26

I have many elements on my UI. I want to change the entire UI color. Basically like a new "Skin" for my HUD/Menu in game. What is the best way to do this? In UIBuilder, I can select a selector class and change the color, and it applies to all elements. How can I do this in runtime? I have looked into USS variables, but it doesn't look like I can edit those using C# on runtime.

CodePudding user response:

The easiest answer I see is creating a UIManager class and placing it in the scene.

Your UI Manager will have an instance, thus making it a Singleton, here is the code that should be inside your UIManager

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

public class UIManager : MonoBehaviour
{
    public static Singleton Instance { get; private set; }
    public Color[] skinColours;
    private void Awake() 
    { 
        // If there is an instance, and it's not me, delete myself.
        
        if (Instance != null && Instance != this) 
        { 
            Destroy(this); 
        } 
        else 
        { 
            Instance = this; 
        } 
    }

    public void ReskinUI(int skinIndex)
    {
        // Repeat this for RawImages, Buttons etc.
        foreach (Image image in GameObject.FindObjectsOfType<Image>())
        {
            image.color = skinColours[skinIndex];
        }
    }
}

After your define your UIManager, you can use it in your code like this.

UIManager.Instance.ReskinUI(1);

The '1' there, corresponds to the skin index.

Let me know if this helps

CodePudding user response:

Not sure what you are placing on your UI but there are only two generally, raw images and images.

Step 1. Create a script to gather the images and/or raw images and store a link to them Step 2. Change the colour on those images. Step 3. Ensure other things can grab your code to change the colour

Step 1:

/// <summary>
/// Gets all the images attached
/// </summary>
private void GetAllImagesInChildren()
{
    allGraphics = new List<Graphic>();
    foreach (Transform child in transform)
    {
        var image = child.gameObject.GetComponent<Image>();
        if (image)
        {
            allGraphics.Add(image);
        }
        else
        {
            var rawImage = child.gameObject.GetComponent<RawImage>();
            if (rawImage)
            {
                allGraphics.Add(rawImage);
            }
        }
    }
}

Image and Raw image are both 'Graphic' types and they have the color attribute. Next just use GetComponent. It's also good practice to use GetComponent as little as needed hence storing the value. If you are only using RawImages feel free to switch the order.

Step 2:

/// <summary>
/// All raw images and images.
/// </summary>
private List<Graphic> allGraphics;

// Start is called before the first frame update
void Awake()
{
    GetAllImagesInChildren();
}

/// <summary>
/// Sets the Color of all the UI elements attached
/// </summary>
/// <param name="newColor">New color</param>
public void SetUIColor(Color newColor)
{
    foreach(Graphic graphic in allGraphics)
    {
        graphic.color = newColor;
    }
}

Let's attach the method from step one into a new script, store graphics privately and call it on awake. Then because graphics is now private create a simple public method which just uses our stored values. You could easily overload this with Color32 just copy and paste the method with that.

All together:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIColourChanger : MonoBehaviour
{
    /// <summary>
    /// All raw images and images.
    /// </summary>
    private List<Graphic> allGraphics;

    // Start is called before the first frame update
    void Awake()
    {
        GetAllImagesInChildren();
    }

    /// <summary>
    /// Sets the Color of all the UI elements attached
    /// </summary>
   /// <param name="newColor">New color</param>
    public void SetUIColor(Color newColor)
    {
        foreach(Graphic graphic in allGraphics)
        {
            graphic.color = newColor;
        }
    }

    /// <summary>
    /// Gets all the images attached
    /// </summary>
    private void GetAllImagesInChildren()
    {
        allGraphics = new List<Graphic>();
        foreach (Transform child in transform)
        {
            var image = child.gameObject.GetComponent<Image>();
            if (image)
            {
                allGraphics.Add(image);
            }
            else
            {
                var rawImage = child.gameObject.GetComponent<RawImage>();
                if (rawImage)
                {
                   allGraphics.Add(rawImage);
                }
            }
        }
    }
}

Then simply the children of the object attached to this script are stored. Then just add:

public UIColourChanger ColorChanger;

or

[SerializeField]
private UIColourChanger colorChanger

To any other script and drag in this one into it to gain access to that public method.

  • Related