0

In my Unity 2021.2.6f1 project, I have a ScrollRect object (carNameList) with several Image items that are added dynamically via prefab instancing. They are switched between each other by KeyPress events. The unselected item has its alpha value 0, and the selected one must have alpha 1.

When I clear my list and fill it up again with new items (that action is also performed by key press), the first item must be selected automatically (without pressing the 'switch' key). Actually the method works and prints the message. But I don't see any changes ingame until I change the alpha value manually via editor.

When called inside Start() it works. It also changes when I press the "switch" key after pressing "refill list" key, but it's wrong (the second element selects then). None of solutions that i found on the internet worked.

List item prefab

On Start()

On Refilling List

Code for selecting menu item:

void SelectMenuItem(int index)
    {
        if(carNameList.content.childCount > 0)
        {
            // deselect all items first
            foreach(Image item in carNameList.content.GetComponentsInChildren<Image>())
            {
                Color color = item.color;
                color.a = 0f;
                item.color = color;
            }
            // select the desired one
            if(index >= 0 && index < carNameList.content.childCount)
            {
                Image selectedItem = carNameList.content.GetComponentsInChildren<Image>()[index];
                Color color = selectedItem.color;
                color.a = 1f;
                selectedItem.color = color;
                Debug.Log(string.Format("Item {0} selected", index));
            }
        }
    }

Clearing the list:

void ClearCarNameList()
    {
        if(carNameList)
        {
            var grid = carNameList.content.GetComponent<VerticalLayoutGroup>();
            for(int i = 0; i < grid.transform.childCount; i++)
            {
                Destroy(grid.transform.GetChild(i).gameObject);
            }
        }
    }

Adding items to list:

void AddItemToCarNameList(string text)
    {
        if(carNameList)
        {
            Image prefab = Resources.Load<Image>("FrontEnd/Prefabs/ListItem");
            Image instance = Instantiate<Image>(prefab);
            instance.rectTransform.SetParent(carNameList.content.transform, false);
            instance.GetComponentInChildren<Text>().text = text;
        }
    }

Start method:

void Start()
    {
        ...
        prevVehicleBtnPressed.AddListener(PreviousVehicleInCategory);
        nextVehicleBtnPressed.AddListener(NextVehicleInCategory);
        prevCatBtnPressed.AddListener(PreviousCategory);
        nextCatBtnPressed.AddListener(NextCategory);
        ...
        LoadAllVehicles(); // this calls the LoadAllVehiclesInCategory(string catName)
    }

Load all vehicles in category (clear list and add new items):

private void LoadAllVehiclesInCategory(string catName)
    {
        ...

        FillCarNameList(namesList);
        SelectMenuItem(0);

        ...
    }

Update method:

void Update()
    {
        #region Events firing when pressing on keyboard keys
        if(Input.GetKeyDown(KeyCode.LeftArrow))
        {
            prevCatBtnPressed.Invoke(); // refill list call
        }
        if(Input.GetKeyDown(KeyCode.RightArrow))
        {
            nextCatBtnPressed.Invoke(); // refill list call
        }

        if(Input.GetKeyDown(KeyCode.UpArrow)) // previous vehicle in category list
        {
            prevVehicleBtnPressed.Invoke();
        }
        if(Input.GetKeyDown(KeyCode.DownArrow)) // next vehicle in category list
        {
            nextVehicleBtnPressed.Invoke();
        }
...
        #endregion
    }
  • First use your VS debugger to figure out what you're actually getting then you can't rely on GetComponentsInChildren to be deterministic. https://stackoverflow.com/questions/42375242/unity-getcomponentsinchildrent-return-order – jiveturkey Mar 09 '22 at 16:35
  • @jiveturkey I've checked that by using `Transform.GetSiblingIndex()` and it's correct (zero). The `Transform.GetChild(int index)` also returns zero (first element). But it still doesn't become red as expected. – Sergey Borisov Mar 10 '22 at 07:25
  • @jiveturkey I even appended to the name of the GameObject of each item an index to know how they are added to the list, and it's again 0, 1, 2, 3 and so on. So everything seems to be correct, but the alpha still doesn't want to be 1 – Sergey Borisov Mar 10 '22 at 07:40
  • I found the error, it occurs when i clear the list of items that was filled on Start() and on "list change" event it became filled up again, and some references broke. How to recreate the list without breaking any references? – Sergey Borisov Mar 10 '22 at 14:48

1 Answers1

0

This UI bug happens sometimes, when you have many UI elements in one canvas. Because the UI rendering doesn't update on time.

There are some functions to force update them before or after your transparent changes. Each UI element should have this function, below is just an example.

ScrollRect.GraphicUpdateComplete();
Image.GraphicUpdateComplete();

and at the end of the frame, you may use this function to force the canvas update immediately.

Canvas.ForceUpdateCanvases();

If above solution didn't work, the most dummy solution would be disable and re-enable the UI GameObject itself.

All these solution will solve any UI update issues, alpha is just one of the most common situation. It can also solve other situation like wrong scroll content position, wrong slider position..etc.

sharimken
  • 169
  • 5
  • Doesn't work... The disabling and re-enabling also had no effect. Only 'switch to next item' key pressing and manual change via inspector... I've checked the actual index of the item that gets "selected" and it's correct (zero) – Sergey Borisov Mar 10 '22 at 07:29
  • then the last thing it may help is, assigning a material with shader. and change the material values. Those are the methods I solved for UI bugs. – sharimken Mar 14 '22 at 07:11
  • I found the problem, it has nothing to do with canvas/image updating. It was because i cleared my list of instances thus i lost the references. Then the "active" menu item retained the "old" reference which was deleted at that time. How can I rebind new references to my instances? They are only binded on ```Start()``` method and never bind after clearing the item list. – Sergey Borisov Mar 17 '22 at 19:39