1. 程式人生 > 其它 >「Unity3D」UGUI Text <quad/> 使用詳解:一種實現圖文混排的策略

「Unity3D」UGUI Text <quad/> 使用詳解:一種實現圖文混排的策略

技術標籤:Unity3DUGUIugui textugui text quadunity 圖文混排ugui text 圖文混排

首先,我們看一下官方說明。

This is only useful for text meshes and renders an image inline with
the text.

關鍵詞在於:text meshesimage inline ——這說明,<quad/>設計是用在TextMesh而不是Text,並且它是一個文字內嵌圖片,即可以自動圖文混排

其次,看一下官方例子。

<quad material=1 size=20 x=0.1 y=0.1 width=0.5 height=0.5>

This selects the material at position in the renderer’s material array
and sets the height of the image to 20 pixels.

  • material——是TextMesh對應MeshRenderMaterials陣列的索引。
  • size——是圖片的畫素高度
    在這裡插入圖片描述

The rectangular area of image starts at given by the x, y, width and height values, which are all given as a fraction of the unscaled width and height of the texture.

  • x,y——是圖片在texture上的百分比偏移,如果texture是一個紋理集合,上面有很多表情,就可以用xy偏移到其中任意一個表情。
  • width——是圖片顯示寬度的百分比縮放,即:顯示寬度 = size * width。也就是說,width越大,圖片顯示寬度越大,反之越小。
<quad material=1 size=0300 width=2    height=1 />
<quad material=1 size=0300 width=1    height=1 />
<quad material=1 size=0300 width=0.5  height=1 />

在這裡插入圖片描述

  • height——是圖片顯示高度的縮放百分比
    ,即:圖片顯示高度 = 實際高度 / height。也就是說,height越大,圖片顯示高度越小,反之越大。
<quad material=1 size=0300 width=1  height=2/>
<quad material=1 size=0300 width=1  height=1/>
<quad material=1 size=0300 width=1  height=0.5/>

在這裡插入圖片描述
因此,我們可以看出:畫素寬度 = size * (width / height)。也就是說,只要width和height保持1:1,畫素寬度就不變,同時width越大顯示寬度越大,height越大顯示高度越小,反之width越小顯示寬度越小,height越小顯示高度越大。

<quad material=1 size=0300 width=2   height=2/>
<quad material=1 size=0300 width=1   height=1 />
<quad material=1 size=0300 width=0.5 height=0.5 />

在這裡插入圖片描述

接著,在Text中使用<quad/>的情況。

  • 第一,顯然就是無法與MeshRender配合,正確檢索到material的索引。
  • 第二,不僅無法正確使用material,還會顯示前文所示的亂碼。

但好的一面就是:<quad/>的屬性可以正確設定圖片大小,而<quad/>的大小會自動排版,那麼我們就可以用<quad/>來做佔位,進行圖文混排的實現。

然後,使用<quad/>在Text中圖文混排,需要解決的問題。

  • 第一,消除亂碼。
  • 第二,用正確的圖片替換佔位符。
  • 第三,控制佔位符大小。

第一個問題,可以使用重寫Textprotected override void OnPopulateMesh(VertexHelper toFill)方法來解決,即找到<quad/>佔位的四個頂點,然後將四個頂點的座標設定成同一個即可。

第二個問題,可以利用<quad/>頂點的position直接,將正確的圖片替換到正確的未知。

如何確定<quad/>的頂點,在toFill中索引?

這裡有一個技巧,就是如果<quad material=1,2,3,4,5,6,7 />即material!=0,那麼所有<quad/>頂點的就會集中在toFill的尾部——這樣我們就可以,把Text中的<quad/>的陣列按照順序,從toFill的尾部替換即可。

核心的實現程式碼如下:

protected override void OnPopulateMesh(VertexHelper toFill)
{
    base.OnPopulateMesh(toFill);

    var count = this.spriteInfoList.Count;

    if (count > 0)
    {
        var vertexLastIndex = toFill.currentVertCount - 1;
        var spriteLastIndex = count                   - 1;
        var leftBottom      = new UIVertex();

        // if <quad material!=0/> then the <quad/> data at the end of toFill
        for (var i = spriteLastIndex; i > -1; --i)
        {
            // remove <quad/> display from last
            var index = vertexLastIndex - (spriteLastIndex - i) * 4;

            toFill.PopulateUIVertex(ref leftBottom, index);     // LB
            toFill.SetUIVertex     (    leftBottom, index - 1); // RB
            toFill.SetUIVertex     (    leftBottom, index - 2); // RT
            toFill.SetUIVertex     (    leftBottom, index - 3); // LT

            // get image from last
            var imageRT = this.transform.GetChild(i).GetComponent<Image>().rectTransform;
            var pos     = (Vector2) leftBottom.position + imageRT.sizeDelta / 2;
            // set sprite pos by <quad/> vertex pos
            imageRT.SetLocalPositionXY(pos);
        }                  
    }
}

第三個問題, 由前文可知,我們可以使用<quad/>屬性來控制佔位符的大小,即:畫素 height = size畫素width = size * (width / height)

那麼,令height = 1,則:size = 畫素heightwidth = 畫素width / size

例如:一個圖片的大小是——width = 300px,height = 500px——對應的就是:<quad size=500, width=0.6 />

最後,使用<quad/>實現Text圖文混排的限制。

這些限制,其實是Text實現的bug。

  • 第一,如果Text VerticalWrapModeTruncate且text內容已經truncated,那麼<quad/>將顯示亂碼,並且toFill vertexes將會出現大量重複冗餘頂點。
  • 第二,如果<quad/>的size超過500,那麼<quad/>的height和position將會在cachedTextGeneratorForLayout.GetPreferredHeight的計算中出現錯誤的數值。