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

C# 为什么TextMeshPro在设置文本后不更新textBounds?,c#,unity3d,C#,Unity3d,我在hover上实现了一个工具提示系统。为此,我使用textmeshpro文本和图像。此图像应为简单背景,具体取决于文本的长度,而文本的长度总是不同的 如果将鼠标悬停在某个元素上,则会替换textmeshpro文本。背景图像被移动到元素,其大小应根据文本的长度而改变: // Hover over slot in public void OnPointerEnter(PointerEventData eventData) { if (currentItem != null) {

我在hover上实现了一个工具提示系统。为此,我使用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
    }     
}
//将鼠标悬停在中的插槽上
公共void OnPointerEnter(pointereventdataeventdata){
如果(currentItem!=null){
Log(“将鼠标悬停在中的插槽项上”);
GamePlay.EnableCanvas(GamePlay.GetHoverCanvas());
TextMeshProUGUI txtMeshPro=GamePlay.GetHoverCanvas().getComponentChildren();
Log(currentItem.GetItemDescription(currentItem));
txtMeshPro.text=currentItem.GetItemDescription(currentItem);
var hoverCanvasText=txtmashpro.GetComponent();
var hoverCanvasTextBG=GamePlay.GetHoverCanvas().getcomponentchildren().GetComponent();
hoverCanvasText.position=newvector3(this.GetComponent().position.x,this.GetComponent().position.y+50,0);
hoverCanvasTextBG.position=newvector3(this.GetComponent().position.x,this.GetComponent().position.y+50,0);
hoverCanvasTextBG.sizeDelta=newvector2(txtmashpro.textBounds.size.x+15,txtmashpro.textBounds.size.y+15);
//不知道为什么图像在第一次悬停时没有正确调整大小
}     
}
我遇到的一个奇怪的问题是,当我第一次将鼠标悬停在元素上时,图像大小不会改变

替换文本和更改位置始终没有问题。

发行说明:

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

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

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

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


注意:我对unity非常陌生,现在在附近修修补补了几天,所以我可能是一个非常简单的问题,但是在研究了几个小时之后,我没有发现任何有用的东西。

在设置了
TextMeshProUGUI
的文本后,
textBounds
及其
大小在下一帧之前不会更新。这是由于Unity推迟了布局重建。在他们的报告中,内容如下:

重建不会立即进行,而是在当前任务结束时进行 帧,就在渲染发生之前。原因是它不是即时的 这将导致布局可能被多次重建 在同一帧中,这对性能不利

我会继续猜测
游戏性。GetHoverCanvas()
正在维护一个从未被破坏的对象,因此,除了第一次运行之外,您的代码在所有情况下都能正常工作

可能有几种方法可以解决这个问题,但最简单的方法是在设置
文本
和读取
文本边界
的大小之间调用。这不是最快的功能,但它应该可以做到这一点


另一种选择是,代替同步函数,启动一个协同程序,将
文本设置为一帧,生成下一帧,然后在第二帧执行时读取
textbounds
。(这可能会导致大小弹出,看起来可能不太理想)。

为了避免强制更新画布,可以使用
TextMeshProUGUI.GetPreferredValues()
提前确定当前分配给画布的文本的宽度和高度。它将返回一个
向量2
。然后可以使用该
Vector2
而不是
TextMeshProUGUI.textBounds

或者,如果您需要某个文本的大小而不实际分配它,请使用
TextMeshProUGUI.GetPreferredValues(字符串文本)


该方法还有其他重载,用于获取给定宽度或高度的大小约束。

您可以使用
TMP_Text.ForceMeshUpdate(),而不是刷新所有画布在分配字符串后立即执行。这样可以确保您的文本信息在同一帧中是正确的

如果文本的父级使用布局组,则很有可能您也需要更新这些布局组。您可以使用
LayoutRebuilder.forcerebuildlayoutimediate([Layout Group.RectTransform])来实现这一点()

请注意,订单很重要

  • 分配文本
  • 重建布局组
  • 强制网格更新

  • 非常感谢您的详细解释。这对我很有帮助。