发包前禁用了UI上面一个调试页面A后,发现无法正确获取某一个用了LayoutGroup>GridLayoutGroup组件的所有子物体的世界坐标。
一顿研究之后发现,在Start的时候想要正确获取其坐标,需要强制刷新一次布局,方法如下:
UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(this.GetComponent<RectTransform>());
至于为什么启用了调试页面A之后就能正确获取子物体的世界坐标,我猜是因为启用调试页面A后,整个预制体的Start时间变长,或者页面计算布局耗时更久,导致可以正确获取坐标。(有待验证)。
以下是在demo里总结的一些经验,非常容易理解,直接贴代码了。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TestLayoutGroup : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){// 游戏第一帧无法直接获取LayoutGroup>GridLayoutGroup组件下子物体的世界坐标Debug.Log("LayoutGroup: " + this.transform.position);foreach (Transform transform in this.transform){// 这里会连续打印多个相同的坐标Debug.Log(transform.name + ": " + transform.position);}// 方法1:获取坐标前强制刷新布局ForceRebuildLayoutImmediate// 这是一个静态方法,用于立即重建指定 RectTransform 上的布局,确保所有布局组件// (如 HorizontalLayoutGroup、VerticalLayoutGroup、LayoutGroup>GridLayoutGroup)更新它们的子元素。/* UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(this.GetComponent<RectTransform>());Debug.Log("LayoutGroup: " + this.transform.position);foreach (Transform transform in this.transform){Debug.Log(transform.name + ": " + transform.position);}*/// 方法2:在当前帧结束后再获取子物体坐标//StartCoroutine(IEGetChildPosition());}IEnumerator IEGetChildPosition(){Debug.Log("LayoutGroup: " + this.transform.position);yield return new WaitForEndOfFrame();foreach (Transform transform in this.transform){Debug.Log(transform.name + ": " + transform.position);}}
}
写到这里,发现yield return new WaitForEndOfFrame()未必靠谱,假如帧时间过长,这么处理可能未必可以正确获取到想要的坐标。
所以建议在获取坐标前先使用ForceRebuildLayoutImmediate强制刷新布局。