为什么设置文本后TextMeshPro不更新textBounds?

时间:2019-03-29 12:55:39

标签: c# unity3d

我已经在悬停上实现了工具提示系统。为此,我使用了textmeshpro文本和图像。该图像应为简单的背景,具体取决于文本的长度。

如果我将鼠标悬停在某个元素上,将替换textmeshpro文本。将背景图像移到该元素上,其大小应根据文本的长度进行更改:

// Hover over slot in
public void OnPointerEnter(PointerEventData eventData) {
    if (currentItem != null) {
        Debug.Log("hover over slot item in");
        GamePlay.EnableCanvas(GamePlay.GetHoverCanvas());

        TextMeshProUGUI txtMeshPro = GamePlay.GetHoverCanvas().GetComponentInChildren<TextMeshProUGUI>();

        Debug.Log(currentItem.GetItemDescription(currentItem));
        txtMeshPro.text = currentItem.GetItemDescription(currentItem);

        var hoverCanvasText = txtMeshPro.GetComponent<RectTransform>();
        var hoverCanvasTextBG = GamePlay.GetHoverCanvas().GetComponentInChildren<Image>().GetComponent<RectTransform>();

        hoverCanvasText.position = new Vector3(this.GetComponent<RectTransform>().position.x, this.GetComponent<RectTransform>().position.y + 50, 0);

        hoverCanvasTextBG.position = new Vector3(this.GetComponent<RectTransform>().position.x, this.GetComponent<RectTransform>().position.y + 50, 0);
        hoverCanvasTextBG.sizeDelta = new Vector2(txtMeshPro.textBounds.size.x + 15, txtMeshPro.textBounds.size.y + 15);
        // No clue why image is not resized properly on first hover
    }     
}

我有一个奇怪的问题,就是我第一次将鼠标悬停在元素上时,图像大小不会改变。

替换文本和更改位置始终可以正常工作。

问题说明:

首先将鼠标悬停在元素A上:图像背景大小完全不会改变。

第二个鼠标悬停在元素B上:图像背景大小发生变化,但元素A的大小正确

将鼠标悬停在元素A上的第三次:图像背景大小发生变化,但元素B的大小正确

这怎么可能?我不明白这里发生了什么。该代码对位置没有任何影响,为什么相同的逻辑对大小不起作用。

注意:我刚接触团结,现在已经几天了,所以我可能是一个非常简单的问题,但是经过几个小时的研究,我没有发现任何有用的东西。

3 个答案:

答案 0 :(得分:2)

您可以在分配字符串后立即使用 TMP_Text.ForceMeshUpdate();,而不是刷新所有画布。这可确保您的文本信息在同一框架内正确无误。

如果您的文本的父级使用布局组,则您很有可能也需要更新它们。你用 LayoutRebuilder.ForceRebuildLayoutImmediate( [Layout-Group.RectTransform] ); (read more here)

请注意顺序很重要。

  1. 指定文本
  2. 重建布局组
  3. 强制网格更新

答案 1 :(得分:1)

设置TextMeshProUGUI的文本后,textBounds及其size直到下一帧才更新。这是由Unity延迟的布局重建引起的。在他们的UI Layout Documentation中,其内容为:

  

重建不会立即发生,而是在当前结束时   帧,就在渲染发生之前。它不是立即的原因   是因为这可能会导致布局可能多次重建   在同一帧中,这会降低性能。

我将继续猜测GamePlay.GetHoverCanvas()正在维护一个永不破坏的对象,因此,您的代码在所有情况下都可以正常工作,除了 首次运行。

可能有几种方法可以解决此问题,但最简单的方法是在设置text和读取textbounds的大小之间调用Canvas.ForceUpdateCanvases()。它不是最快的功能,但应该可以解决问题。

另一种选择是代替一个同步功能,启动一个协程,该协程将text设置为一帧,产生下一帧,然后在其第二个执行帧上读取textbounds 。 (这可能会导致尺寸弹出,并且看起来可能不受欢迎)。

答案 2 :(得分:0)

为避免需要强制更新Canvas,可以使用TextMeshProUGUI.GetPreferredValues()提前确定当前分配给它的文本的宽度和高度。它将返回一个Vector2。然后,您可以使用该Vector2代替TextMeshProUGUI.textBounds

或者,如果您需要特定文本的大小而不实际分配它,请使用TextMeshProUGUI.GetPreferredValues(string text)

在给定宽度或高度限制的情况下,该方法还有其他重载方法。