unity3d在UGUI中显示带表情的微信昵称

本人是搬砖党,都是网上处处搜集的知识点,这里作个总结或者说笔记html

一、需求:有的微信昵称是含有表情的。当你的应用对接微信SDK后,获取到的昵称放到unity中,会显示异常。咱们要作的就是让包含表情的微信昵称正常显示。

     若是你的需求与上面的误差比较大,那么建议不用继续往下看了。看完不必定能有所收获。java

二、普及知识:

  1) 微信昵称中的表情是emoji表情,先了解它是什么?反正不是图片。eg:1(🇨🇳)2(🇯🇵)3(😳)git

  2)须要作的映射关系是:😳与某图片,不是0与某图片,除非你能说服服务端小伙伴帮你把emoji表情转换成“0”或者某种格式。因此这也是没有选择TextMeshPro的缘由之一github

 3)不要认为一个emoji表情占用一个字符串长度。能够试试 string str = 😳;Debug.Log(str);有的是2,有的是4,有的是...微信

三、最终效果

 首先用到网友的EmojiText组件,如图 app

 

only one component,简便,一目了然,仅显示一行昵称足以ide

 这是我修改后的最终效果,工程中的是[0]对应图片  个人是😳对应图片函数

网友的工程git地址: https://github.com/zouchunyi/EmojiText 字体

四、如何找出字符串中的emoji表情

 网上找到一篇文章,讲解了emoj与Unicode之间的联系,代码是用java写的ui

 http://www.noobyard.com/article/p-klqpzffr-ku.html 

 咱们能够用到其中的isEmojiCharacter函数。C#没有codePointAt函数,可是有其余办法。

System.Globalization.StringInfo si = new System.Globalization.StringInfo(str);

for (int i = 0; i < si.LengthInTextElements; i++)
{
            string ele = si.SubstringByTextElements(i, 1);

}

获得ele的unicode就能够判断ele是否是表情了。有的表情占用多个长度,须要把整个表情长度找出来

五、找出了表情就好办了,把表情翻译成本身想要的名称格式就能够了。我这里把表情😁翻译成"1f601"。由于我下载的1000多个emoji表情图片都是这种格式😂。到此就实现了 😁 ==>1f601==>1f601.png

六、算了,不说了,不知道怎么讲清楚。直接贴代码

/// <summary>
    /// codePoint是不是表情字符
    /// 参考java的codePointAt
    /// </summary>
    private static bool isEmojiCharacter(int codePoint)
    {
        return (codePoint >= 0x2600 && codePoint <= 0x27BF) // 杂项符号与符号字体
                || codePoint == 0x303D
                || codePoint == 0x2049
                || codePoint == 0x203C
                || (codePoint >= 0x2000 && codePoint <= 0x200F)//
                || (codePoint >= 0x2028 && codePoint <= 0x202F)//
                || codePoint == 0x205F //
                || (codePoint >= 0x2065 && codePoint <= 0x206F)//
                                                               /* 标点符号占用区域 */
                || (codePoint >= 0x2100 && codePoint <= 0x214F)// 字母符号
                || (codePoint >= 0x2300 && codePoint <= 0x23FF)// 各类技术符号
                || (codePoint >= 0x2B00 && codePoint <= 0x2BFF)// 箭头A
                || (codePoint >= 0x2900 && codePoint <= 0x297F)// 箭头B
                || (codePoint >= 0x3200 && codePoint <= 0x32FF)// 中文符号
                || (codePoint >= 0xD800 && codePoint <= 0xDFFF)// 高低位替代符保留区域
                || (codePoint >= 0xE000 && codePoint <= 0xF8FF)// 私有保留区域
                || (codePoint >= 0xFE00 && codePoint <= 0xFE0F)// 变异选择器
                || codePoint >= 0x10000; // Plane在第二平面以上的,char都不能够存,所有都转
    }
    /// <summary>
    /// 将中文或者表情放到list中
    /// 参考java的codePoint
    /// 两个表情挨着的状况暂时没处理
    /// out的resultText,将表情符号替换为█,用来计算Text的cachedTextGenerator
    /// </summary>
    public static List<EmojiElement> getEmojiList(string str,out string resultText)
    {
        resultText = str;
        List<EmojiElement> arr = new List<EmojiElement>();
        StringInfo si = new StringInfo(str);
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < si.LengthInTextElements; i++)
        {
            string ele = si.SubstringByTextElements(i, 1);
            string unicode = "0x" + toUnicode(ele);
            //Debug.Log("i : " + i);
            try
            {
                int e = Convert.ToInt32(unicode, 16);
                bool isEmoji = isEmojiCharacter(e);
                if (isEmoji)
                {
                    builder.Append(ele);
                }
                else
                {
                    if (!string.IsNullOrEmpty(builder.ToString()))
                    {
                        EmojiElement ee1 = new EmojiElement();
                        ee1.isEmoji = true;
                        ee1.unicode = toUnicode(builder.ToString());
                        ee1.originalText = builder.ToString();
                        resultText = resultText.Replace(ee1.originalText, "█");
                        arr.Add(ee1);
                        builder.Remove(0, builder.Length);
                    }
                    EmojiElement ee = new EmojiElement();
                    ee.isEmoji = false;
                    arr.Add(ee);
                }
                if(i == si.LengthInTextElements - 1)
                {
                    if (!string.IsNullOrEmpty(builder.ToString()))
                    {
                        EmojiElement ee1 = new EmojiElement();
                        ee1.isEmoji = true;
                        ee1.unicode = toUnicode(builder.ToString());
                        ee1.originalText = builder.ToString();
                        resultText = resultText.Replace(ee1.originalText, "█");
                        arr.Add(ee1);
                        builder.Remove(0, builder.Length);
                    }
                }
            }
            catch(Exception ex)
            {
                Debug.Log(ex.ToString());
            }
            
        }
        return arr;
    }
    /// <summary>
    /// 将表情字符串转成unicode(result eg1:1f60a(微笑) eg2:1f1e8_1f1f3(国旗表情))
    /// 结果与表情图片相对应
    /// </summary>
    public static string toUnicode(string s)
    {
        var bytes = Encoding.UTF32.GetBytes(s);
        var stringBuilder = new StringBuilder();
        List<List<byte>> resultList = new List<List<byte>>();
        List<byte> tempList = new List<byte>();
        for (int i = 0, length = bytes.Length; i < length; i++)
        {
            tempList.Add(bytes[i]);
            if (tempList.Count == 4)
            {
                tempList.Reverse();
                resultList.Add(tempList);
                tempList = new List<byte>();
            }
        }
        for (int i = 0, length = resultList.Count; i < length; i++)
        {
            List<byte> elist = resultList[i];
            bool isFirst = false;
            for (int j = 0; j < elist.Count; j++)
            {
                string b = elist[j].ToString("x2");
                if (b == "00" && j < 2)
                    continue;
                if (!isFirst)
                {
                    isFirst = true;
                    if (j < 2)
                        b = elist[j].ToString("x");
                    stringBuilder.Append(b);
                }
                else
                {
                    stringBuilder.Append(b);
                }
                //Debug.Log(b);
            }
            if (isFirst && i != length - 1)
            {
                stringBuilder.Append("_");
            }
        }
        return stringBuilder.ToString().Replace("_0000", "");
    }

 toUnicode函数我本身写的,确定有更简便的。。

EmojiText也直接贴出来吧

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using System;
using System.Globalization;

public class EmojiText : Text {

    private const bool EMOJI_LARGE = true;
    private static Dictionary<string,EmojiInfo> EmojiIndex = null;

    struct EmojiInfo
    {
        public float x;
        public float y;
        public float size;
        public int len;
    }

    readonly UIVertex[] m_TempVerts = new UIVertex[4];
    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        if (font == null)
            return;

        if (EmojiIndex == null) {
            EmojiIndex = new Dictionary<string, EmojiInfo>();

            //load emoji data, and you can overwrite this segment code base on your project.
            TextAsset emojiContent = Resources.Load<TextAsset> ("emoji");
            string[] lines = emojiContent.text.Split ('\n');
            for(int i = 1 ; i < lines.Length; i ++)
            {
                if (! string.IsNullOrEmpty (lines [i])) {
                    string[] strs = lines [i].Split ('\t');
                    EmojiInfo info;
                    info.x = float.Parse (strs [3]);
                    info.y = float.Parse (strs [4]);
                    info.size = float.Parse (strs [5]);
                    info.len = 0;
                    EmojiIndex[strs[0]] = info;
                }
            }
        }
        Dictionary<int,EmojiInfo> emojiDic = new Dictionary<int, EmojiInfo> ();
        string resultText = string.Empty;
        if (supportRichText)
        {
            List<EmojiElement> emojiList = EmojiUtil.getEmojiList(text,out resultText);
            //Debug.Log("resultText:"+ resultText+",len:"+ resultText.Length);
            //Debug.Log("emojiList:"+ emojiList.Count);
            for (int i = 0, length= emojiList.Count; i < length; i++)
            {
                EmojiElement element = emojiList[i];
                if (element.isEmoji)
                {
                    EmojiInfo info;
                    string unicodeValue = element.unicode;
                    //Debug.Log("unicodeValue:" + unicodeValue + ",i:" + i);
                    if (EmojiIndex.TryGetValue(unicodeValue, out info))
                    {
                        //Debug.Log("1 unicodeValue:" + unicodeValue);
                        info.len = 1;
                        emojiDic.Add(i, info);
                    }
                }
            }
        }

        // We don't care if we the font Texture changes while we are doing our Update.
        // The end result of cachedTextGenerator will be valid for this instance.
        // Otherwise we can get issues like Case 619238.
        m_DisableFontTextureRebuiltCallback = true;

        Vector2 extents = rectTransform.rect.size;

        var settings = GetGenerationSettings(extents);
        if (supportRichText && !string.IsNullOrEmpty(resultText))
        {
            cachedTextGenerator.Populate(resultText, settings);
        }
        else
        {
            cachedTextGenerator.Populate(text, settings);
        }

        Rect inputRect = rectTransform.rect;

        // get the text alignment anchor point for the text in local space
        Vector2 textAnchorPivot = GetTextAnchorPivot(alignment);
        Vector2 refPoint = Vector2.zero;
        refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x);
        refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y);

        // Determine fraction of pixel to offset text mesh.
        Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;

        // Apply the offset to the vertices
        IList<UIVertex> verts = cachedTextGenerator.verts;
        float unitsPerPixel = 1 / pixelsPerUnit;
        //Last 4 verts are always a new line...
        int vertCount = verts.Count - 4;
        //Debug.Log("verts:" + verts.Count);
        toFill.Clear();
        if (roundingOffset != Vector2.zero)
        {
            for (int i = 0; i < vertCount; ++i)
            {
                int tempVertsIndex = i & 3;
                m_TempVerts[tempVertsIndex] = verts[i];
                m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
                m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
                if (tempVertsIndex == 3)
                    toFill.AddUIVertexQuad(m_TempVerts);
            }
        }
        else
        {
            float repairDistance = 0;
            float repairDistanceHalf = 0;
            float repairY = 0;
            if (vertCount > 0) {
                repairY = verts [3].position.y;
            }
            for (int i = 0; i < vertCount; ++i) {
                EmojiInfo info;
                int index = i / 4;
                if (emojiDic.TryGetValue (index, out info)) {
                    //compute the distance of '[' and get the distance of emoji 
                    float charDis = (verts [i + 1].position.x - verts [i].position.x) * 3;
                    m_TempVerts [3] = verts [i];//1
                    m_TempVerts [2] = verts [i + 1];//2
                    m_TempVerts [1] = verts [i + 2];//3
                    m_TempVerts [0] = verts [i + 3];//4

                    //the real distance of an emoji
                    m_TempVerts [2].position += new Vector3 (charDis, 0, 0);
                    m_TempVerts [1].position += new Vector3 (charDis, 0, 0);

                    //make emoji has equal width and height
                    float fixValue = (m_TempVerts [2].position.x - m_TempVerts [3].position.x - (m_TempVerts [2].position.y - m_TempVerts [1].position.y));
                    m_TempVerts [2].position -= new Vector3 (fixValue, 0, 0);
                    m_TempVerts [1].position -= new Vector3 (fixValue, 0, 0);

                    float curRepairDis = 0;
                    if (verts [i].position.y < repairY) {// to judge current char in the same line or not
                        repairDistance = repairDistanceHalf;
                        repairDistanceHalf = 0;
                        repairY = verts [i + 3].position.y;
                    } 
                    curRepairDis = repairDistance;
                    int dot = 0;//repair next line distance
                    for (int j = info.len - 1; j > 0; j--) {
                        if (verts [i + j * 4 + 3].position.y >= verts [i + 3].position.y) {
                            repairDistance += verts [i + j * 4 + 1].position.x - m_TempVerts [2].position.x;
                            break;
                        } else {
                            dot = i + 4 * j;

                        }
                    }
                    if (dot > 0) {
                        int nextChar = i + info.len * 4;
                        if (nextChar < verts.Count) {
                            repairDistanceHalf = verts [nextChar].position.x - verts [dot].position.x;
                        }
                    }

                    //repair its distance
                    for (int j = 0; j < 4; j++) {
                        m_TempVerts [j].position -= new Vector3 (curRepairDis, 0, 0);
                    }

                    m_TempVerts [0].position *= unitsPerPixel;
                    m_TempVerts [1].position *= unitsPerPixel;
                    m_TempVerts [2].position *= unitsPerPixel;
                    m_TempVerts [3].position *= unitsPerPixel;

                    float pixelOffset = emojiDic [index].size / 32 / 2;
                    m_TempVerts [0].uv1 = new Vector2 (emojiDic [index].x + pixelOffset, emojiDic [index].y + pixelOffset);
                    m_TempVerts [1].uv1 = new Vector2 (emojiDic [index].x - pixelOffset + emojiDic [index].size, emojiDic [index].y + pixelOffset);
                    m_TempVerts [2].uv1 = new Vector2 (emojiDic [index].x - pixelOffset + emojiDic [index].size, emojiDic [index].y - pixelOffset + emojiDic [index].size);
                    m_TempVerts [3].uv1 = new Vector2 (emojiDic [index].x + pixelOffset, emojiDic [index].y - pixelOffset + emojiDic [index].size);

                    toFill.AddUIVertexQuad (m_TempVerts);

                    i += 4 * info.len - 1;
                } else {
                    int tempVertsIndex = i & 3;
                    if (tempVertsIndex == 0 && verts [i].position.y < repairY) {
                        repairY = verts [i + 3].position.y;
                        repairDistance = repairDistanceHalf;
                        repairDistanceHalf = 0;
                    }
                    m_TempVerts [tempVertsIndex] = verts [i];
                    m_TempVerts [tempVertsIndex].position -= new Vector3 (repairDistance, 0, 0);
                    m_TempVerts [tempVertsIndex].position *= unitsPerPixel;
                    if (tempVertsIndex == 3)
                        toFill.AddUIVertexQuad (m_TempVerts);
                }
            }

        }
        m_DisableFontTextureRebuiltCallback = false;
    }
}
1000多张emoji表情图片,不知道怎么修改下载积分

https://download.csdn.net/download/cheng219101/10963349 

这里也能够下载,不过得一个个点

https://apps.timwhitlock.info/emoji/tables/unicode

遗留问题:两个表情挨在一块儿,会解析成一个没法识别的符号