【问题标题】:How to get children's world position in a GridLayoutGroup in Unity?如何在 Unity 的 GridLayoutGroup 中获取儿童的世界位置?
【发布时间】:2018-05-14 06:06:17
【问题描述】:

我有一个滚动视图,在它的内容对象中有一个 GridLayoutGroup 组件(内容对象有自己的位置和比例,而不是 (0,0,0) 或 (1,1,1) ),在它下面'是几个图像。在运行时,我想取出一个图像并将其父级设置为其他 UI 对象,但我希望图像保持其在屏幕上的位置。

但是我尝试了以下所有方法,最终都在屏幕上出现错误的位置(图像有时甚至移出屏幕)。

1 在图像对象上使用 SetParent 方法(尝试 True 或 false 作为第二个参数):

imageObject.transform.SetParent(otherObj, True);

2 在第一种方式中使用SetParent方法,然后手动给图像一个位置,但是id没有出现在鼠标位置(此代码适用于不在布局组中的其他对象):

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 ,因此未使用该值,因此该值不在屏幕上的位置,或者在帧末尾发生了某些事情,因此我对位置的重置是无用的。

更多信息:我的画布渲染模式设置为“屏幕空间相机”。但即使将其更改为覆盖,它仍然是相同的结果。画布缩放模式为“Scale with Screen Size”,屏幕匹配模式为“Expand”。

那么我应该怎么做才能从 GridLayoutGroup 中取出图像但让它留在屏幕上的位置?谢谢!

【问题讨论】:

  • 我认为在示例 3 中,您应该在设置父对象之前存储位置。
  • @obywan 感谢您的回复。这里是一个错误,只是编辑它。我在代码中做对了。

标签: c# unity3d unity5


【解决方案1】:

好的,我已经制作了测试项目。没有完全解决您的问题,但我让位于 0,0,0 的 GridLayoutGroup 的父更改工作:

  1. 使用RectTransform.anchoredPosition获取相对位置 GridLayoutGroup
  2. 更改父级
  3. 确保图像的锚点保持不变(网格布局可以改变图像的锚点)。
  4. 在更改父级以设置新锚点后等待帧结束。
  5. 为您的RectTransform 设置新的anchoredPosition
  6. 如果如您所说,您的 GridLayoutGroup 的比例与 1,1,1 不同 然后相应地除/乘坐标(0.5, 0.5, 0.5 除以 2)
  7. (如果您的网格不在(0,0,0) 中,您可能还需要制作 一些对齐方式)

【讨论】:

  • 谢谢,为什么要等待帧结束?
  • 我以前只是使用示例中显示的简单方法,并且成功了,但是我有一段时间没有测试,最近在我的项目中更改了太多代码和结构。现在我不能像以前那样让它再次工作了:(
  • 关于 WaitForEndOfFrame — 如果您在更改父项后立即设置锚点,它将保持不变。不知道为什么,可能是因为执行顺序。
【解决方案2】:

经过多次测试,我发现你调用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);
 }

【讨论】:

  • 是的,WaitForEndOfFrame 为我做了这件事,因为我不知道为什么我不能得到这个职位。谢谢!!
【解决方案3】:

我使用这个功能:

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();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多