如何在 Unity 的 GridLayoutGroup 中获取儿童的世界位置?
How to get children's world position in a GridLayoutGroup in Unity?
我有一个滚动视图,在它的内容对象中有一个 GridLayoutGroup 组件(内容对象有自己的位置和比例,而不是 (0,0,0) 或 (1,1,1) ),并且在下面它有几张图片。在运行时我想取出一个图像并将其父级设置为其他 UI 对象,但我希望图像保持其在屏幕上的位置。
然而我尝试了以下所有方法,最终都在屏幕上显示错误的位置(图像有时甚至移动到屏幕外)。
1 在图像对象上使用 SetParent 方法(尝试将 True 或 false 作为第二个参数):
imageObject.transform.SetParent(otherObj, True);
2 用方法一的SetParent方法,然后手动给图片一个位置,但是id没有出现在鼠标位置(这段代码对其他不在layoutgroup中的对象没问题):
imageObject.transform.SetParent(otherObj, True);
var p = Camera.main.ScreenToWorldPoint(Input.mousePosition);
imageObject.transform.position = new Vector3(p.x, p.y, 0);
3 调用 SetParent 后将位置设置为其原始值。
var p = imageObject.transform.position;
imageObject.transform.SetParent(otherObj, True);
imageObject.transform.position = new Vector3(p.x, p.y, 0);
4 不使用任何代码,但在运行时在编辑器中,手动将图像拖出到目标父对象。位置还是变了。
5 不使用任何代码,但在编辑器运行时,手动取消选中 GridLayoutGroup 以禁用它。还是图片位置变了。
为什么第三种方法不起作用?我认为可能未使用图像对象的 transform.position,因此未使用该值,因此该值不在屏幕上的位置,或者在帧的末尾发生了一些事情,所以我重新设置了位置没用。
更多信息:我的 canvas 渲染模式设置为 "Screen Space-Camera"。但即使将其更改为叠加,它仍然是相同的结果。 Canvas缩放模式为"Scale with Screen Size",屏幕匹配模式为"Expand"。
那么我应该怎么做才能从 GridLayoutGroup 中取出图像,但让它停留在屏幕上的位置?谢谢!
好的,我做了测试项目。没有完全解决您的问题,但我 parent 更改了位于 0,0,0
的 GridLayoutGroup 的工作方式:
- 使用
RectTransform.anchoredPosition
获取相对位置
GridLayoutGroup
。
- 改变parent
- 确保图像的锚点保持不变(网格布局可以改变图像的锚点)。
- 更改 parent 后等待帧结束以设置新锚点。
- 为您的
RectTransform
设置新的 anchoredPosition
。
- 如果如您所说,您的 GridLayoutGroup 的比例不同于
1,1,1
然后 divide/multiply 相应坐标(除以 2 得到 0.5,
0.5, 0.5
)
- (如果您的网格不在
(0,0,0)
中,您可能还需要制作
一些路线)
经过多次测试,我发现你调用SetParent(objParent, True);
后的位置是对的;但由于与 GridLayoutGroup 相关的原因,位置在这之后和帧结束之前的时间发生了变化。所以把那个位置记录下来,在其他帧中做任何你需要做的事情。
示例:
在主线程中:
imageObject.transform.SetParent(otherObj, True);
originalPosition = imageObject.transform.position;
imageObject.SetObjectActive(false); // If not do this, the image might flicker at it's position before put it into the GridLayoutGroup. My guess is that it gets rendered before the AdjustTransInTheEndOfFrame method is executed.
StartCoroutine(AdjustTransInTheEndOfFrame(imageObject));
private IEnumerator AdjustTransInTheEndOfFrame(GameObject obj)
{
yield return new WaitForEndOfFrame();
obj.transform.position = originalPosition;
obj.SetObjectActive(true);
}
我使用这个功能:
public Vector2 GetChildLocalPosition(RectTransform rectTransformGrid, RectTransform rectTransformChild)
{
var localPositionGrid = (Vector2)rectTransformGrid.localPosition;
var sizeDeltaGrid = rectTransformGrid.sizeDelta;
var deltaGridFromCenterToLeftTop = new Vector2(-0.5f * sizeDeltaGrid.x, 0.5f * sizeDeltaGrid.y);
var anchoredPositionChild = rectTransformChild.anchoredPosition;
var childPosition = localPositionGrid + anchoredPositionChild + deltaGridFromCenterToLeftTop;
return childPosition;
}
如果需要,请更新 GridLayoutGroup,如下所示:
public void UpdateGrid(LayoutGroup gridLayoutGroup)
{
gridLayoutGroup.CalculateLayoutInputHorizontal();
gridLayoutGroup.CalculateLayoutInputVertical();
gridLayoutGroup.SetLayoutHorizontal();
gridLayoutGroup.SetLayoutVertical();
}
我有一个滚动视图,在它的内容对象中有一个 GridLayoutGroup 组件(内容对象有自己的位置和比例,而不是 (0,0,0) 或 (1,1,1) ),并且在下面它有几张图片。在运行时我想取出一个图像并将其父级设置为其他 UI 对象,但我希望图像保持其在屏幕上的位置。
然而我尝试了以下所有方法,最终都在屏幕上显示错误的位置(图像有时甚至移动到屏幕外)。
1 在图像对象上使用 SetParent 方法(尝试将 True 或 false 作为第二个参数):
imageObject.transform.SetParent(otherObj, True);
2 用方法一的SetParent方法,然后手动给图片一个位置,但是id没有出现在鼠标位置(这段代码对其他不在layoutgroup中的对象没问题):
imageObject.transform.SetParent(otherObj, True);
var p = Camera.main.ScreenToWorldPoint(Input.mousePosition);
imageObject.transform.position = new Vector3(p.x, p.y, 0);
3 调用 SetParent 后将位置设置为其原始值。
var p = imageObject.transform.position;
imageObject.transform.SetParent(otherObj, True);
imageObject.transform.position = new Vector3(p.x, p.y, 0);
4 不使用任何代码,但在运行时在编辑器中,手动将图像拖出到目标父对象。位置还是变了。
5 不使用任何代码,但在编辑器运行时,手动取消选中 GridLayoutGroup 以禁用它。还是图片位置变了。
为什么第三种方法不起作用?我认为可能未使用图像对象的 transform.position,因此未使用该值,因此该值不在屏幕上的位置,或者在帧的末尾发生了一些事情,所以我重新设置了位置没用。
更多信息:我的 canvas 渲染模式设置为 "Screen Space-Camera"。但即使将其更改为叠加,它仍然是相同的结果。 Canvas缩放模式为"Scale with Screen Size",屏幕匹配模式为"Expand"。
那么我应该怎么做才能从 GridLayoutGroup 中取出图像,但让它停留在屏幕上的位置?谢谢!
好的,我做了测试项目。没有完全解决您的问题,但我 parent 更改了位于 0,0,0
的 GridLayoutGroup 的工作方式:
- 使用
RectTransform.anchoredPosition
获取相对位置GridLayoutGroup
。 - 改变parent
- 确保图像的锚点保持不变(网格布局可以改变图像的锚点)。
- 更改 parent 后等待帧结束以设置新锚点。
- 为您的
RectTransform
设置新的anchoredPosition
。 - 如果如您所说,您的 GridLayoutGroup 的比例不同于
1,1,1
然后 divide/multiply 相应坐标(除以 2 得到0.5, 0.5, 0.5
) - (如果您的网格不在
(0,0,0)
中,您可能还需要制作 一些路线)
经过多次测试,我发现你调用SetParent(objParent, True);
后的位置是对的;但由于与 GridLayoutGroup 相关的原因,位置在这之后和帧结束之前的时间发生了变化。所以把那个位置记录下来,在其他帧中做任何你需要做的事情。
示例:
在主线程中:
imageObject.transform.SetParent(otherObj, True);
originalPosition = imageObject.transform.position;
imageObject.SetObjectActive(false); // If not do this, the image might flicker at it's position before put it into the GridLayoutGroup. My guess is that it gets rendered before the AdjustTransInTheEndOfFrame method is executed.
StartCoroutine(AdjustTransInTheEndOfFrame(imageObject));
private IEnumerator AdjustTransInTheEndOfFrame(GameObject obj)
{
yield return new WaitForEndOfFrame();
obj.transform.position = originalPosition;
obj.SetObjectActive(true);
}
我使用这个功能:
public Vector2 GetChildLocalPosition(RectTransform rectTransformGrid, RectTransform rectTransformChild)
{
var localPositionGrid = (Vector2)rectTransformGrid.localPosition;
var sizeDeltaGrid = rectTransformGrid.sizeDelta;
var deltaGridFromCenterToLeftTop = new Vector2(-0.5f * sizeDeltaGrid.x, 0.5f * sizeDeltaGrid.y);
var anchoredPositionChild = rectTransformChild.anchoredPosition;
var childPosition = localPositionGrid + anchoredPositionChild + deltaGridFromCenterToLeftTop;
return childPosition;
}
如果需要,请更新 GridLayoutGroup,如下所示:
public void UpdateGrid(LayoutGroup gridLayoutGroup)
{
gridLayoutGroup.CalculateLayoutInputHorizontal();
gridLayoutGroup.CalculateLayoutInputVertical();
gridLayoutGroup.SetLayoutHorizontal();
gridLayoutGroup.SetLayoutVertical();
}