最近研究了很久图文混排,本来一开始想研究UILabel的源码,从底层去添加聊天表情。可惜自己刚刚接触Unity 很多东西都不懂,没办法只能另辟蹊径。好在在网上终于找到了解决方案。现在的做法对性能来说肯定不是最好的。不过暂时用用还可以。。等到以后Unity学习得好一点的时候再重新做一个。
Demo : ChatDemo
DownLoad : DownLoad 密码:png0
下面的代码其实很简单。相信都能看懂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using System.Text; using System.IO; /// <summary> /// 聊天界面 /// </summary> public class ChatPanel : MonoBehaviour { //聊天渲染prefabs public GameObject ChatCell; //滚动条 public UIScrollBar scrollBar; //输入框 public UIInput input; //背景框 public UISprite background; //发送消息按钮 public UIImageButton buttonSend; //聊天框最多显示多少数据 public int MaxCount = 30; //----------------------- private --------------------// //聊天记录历史记录最大条数 private const int MAXHISTORY = 128; //聊天GRID private ChatGrid grid; //聊天prefabs缓存区 private List<GameObject> mList; //缓动坐标 private TweenPosition tween; //发送消息历史记录 private List<string> mTextHistorys; //记录位置 private int mIndexHistory; //界面当前是否显示 private bool mIsShow = true; // Use this for initialization void Start () { mList = new List<GameObject>(); mTextHistorys = new List<string>(); grid = GetComponentInChildren<ChatGrid>(); tween = gameObject.GetComponentInChildren<TweenPosition>(); UIEventListener.Get(buttonSend.gameObject).onClick = OnSendBtnClick; AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); AddSpeechInfos("Test", "{0}{1}{2}{3}{4}这就是聊天记录,不知道有什么问题。嘿呀,哟呼。哈哈。嘿嘿!"); } void Update() { //聊天界面显示 if (mIsShow) { if (Input.GetKeyDown(KeyCode.UpArrow)) { input.value = GetHistoryDown(); } else if (Input.GetKeyDown(KeyCode.DownArrow)) { input.value = GetHistoryUp(); } else if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter)) { OnSendBtnClick(); } } } /// <summary> /// 添加系统聊天信息 /// </summary> /// <param name="text"></param> /// <param name="bytes"></param> public void AddSysInfos(string name , string text , byte[] bytes = null) { Add(name, "[ff0000]", text, "[ff0000]", bytes); } /// <summary> /// 添加公共聊天信息 /// </summary> /// <param name="text"></param> /// <param name="bytes"></param> public void AddSpeechInfos(string name , string text , byte[] bytes = null) { Add(name, "[0000ff]", text, "[ffff00]", bytes); } /// <summary> /// 聊天缓动结束 /// </summary> private void OnTweenComplete() { if (tween.value == tween.to) { mIsShow = true; } else if (tween.value == tween.from) { mIsShow = false; } } /// <summary> /// 发送消息 /// </summary> /// <param name="go"></param> private void OnSendBtnClick(GameObject go = null) { string text = input.value; if (!string.IsNullOrEmpty(text)) { if (text.StartsWith("/")) { AddSysInfos("GM ",text); } else { AddSpeechInfos("Test",text); } AddHistorys(text); input.value = ""; input.isSelected = false; } else { return; } } /// <summary> /// 添加内容到聊天窗口 /// </summary> /// <param name="text"></param> private void Add(string name, string nameColor, string text, string textColor, byte[] bytes) { GameObject go; if (mList.Count >= MaxCount) { go = mList[0]; mList.Remove(go); } else { go = Instantiate(ChatCell) as GameObject; } ChatItem cell = go.GetComponent<ChatItem>(); go.transform.parent = grid.transform; go.transform.localScale = ChatCell.transform.localScale; cell.nameColor = nameColor; cell.infoColor = textColor; cell.nameText = name; cell.text = text; mList.Add(go); grid.Reposition(); scrollBar.value = 1; } //添加聊天历史记录,用于快捷发送 private void AddHistorys(string text) { if(!string.IsNullOrEmpty(text)) { if (mTextHistorys.Contains(text)) mTextHistorys.Remove(text); if (mTextHistorys.Count >= MAXHISTORY) mTextHistorys.Remove(mTextHistorys[0]); mTextHistorys.Add(text); mIndexHistory = mTextHistorys.Count; } } private string GetHistoryUp() { if (mTextHistorys.Count > 0) { mIndexHistory--; if (mIndexHistory < 0) { mIndexHistory = 0; } return mTextHistorys[mIndexHistory]; } else { return ""; } } private string GetHistoryDown() { if (mTextHistorys.Count > 0) { mIndexHistory++; if (mIndexHistory > (mTextHistorys.Count - 1)) { mIndexHistory = mTextHistorys.Count - 1; } return mTextHistorys[mIndexHistory]; } else { return ""; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
using UnityEngine; using System.Collections; using System.Collections.Generic; public class ChatGrid : UIWidgetContainer { public delegate void OnReposition(); public enum Arrangement { Horizontal, Vertical, } public Arrangement arrangement = Arrangement.Horizontal; public int maxPerLine = 0; public bool animateSmoothly = false; public bool sorted = false; public bool hideInactive = true; public OnReposition onReposition; public bool repositionNow { set { if (value) { mReposition = true; enabled = true; } } } bool mStarted = false; bool mReposition = false; UIPanel mPanel; UIScrollView mDrag; bool mInitDone = false; void Init() { mInitDone = true; mPanel = NGUITools.FindInParents<UIPanel>(gameObject); mDrag = NGUITools.FindInParents<UIScrollView>(gameObject); } void Start() { if (!mInitDone) Init(); mStarted = true; bool smooth = animateSmoothly; animateSmoothly = false; Reposition(); animateSmoothly = smooth; enabled = false; } void Update() { if (mReposition) Reposition(); enabled = false; } static public int SortByName(Transform a, Transform b) { return string.Compare(a.name, b.name); } [ContextMenu("Execute")] public void Reposition() { if (Application.isPlaying && !mStarted) { mReposition = true; return; } if (!mInitDone) Init(); mReposition = false; Transform myTrans = transform; int x = 0; int y = 0; int height = 0; for (int i = 0; i < myTrans.childCount; ++i) { Transform t = myTrans.GetChild(i); UISprite cell = t.FindChild("back").gameObject.GetComponent<UISprite>(); if (!NGUITools.GetActive(t.gameObject) && hideInactive) continue; float depth = t.localPosition.z; Vector3 pos = new Vector3(0, -height, depth); height += cell.height; if (animateSmoothly && Application.isPlaying) { SpringPosition.Begin(t.gameObject, pos, 15f); } else t.localPosition = pos; if (++x >= maxPerLine && maxPerLine > 0) { x = 0; ++y; } } if (mDrag != null) { mDrag.UpdateScrollbars(true); mDrag.RestrictWithinBounds(true); } else if (mPanel != null) { mPanel.ConstrainTargetToBounds(myTrans, true); } if (onReposition != null) onReposition(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; public class ChatItem : MonoBehaviour { //背景的高度 public int cellHeight = 30; public int MaxLineWidth = 540; //内容颜色 [HideInInspector] public string infoColor; //名字颜色 [HideInInspector] public string nameColor; //发送消息名称 [HideInInspector] public string nameText; public GameObject FacePrefab; public List<string> Prefabs; public GameObject Label; public Font font; public enum InfoType { Text, Face, } public class LabelType { public string info; public InfoType type; public LabelType(string text,InfoType tp) { info = text; type = tp; } } private int positionX = 10; private int positionY = -6; //聊天内容显示label //private UILabel label; //背景 private UISprite back; //名字label的宽度 private int labelNameWidth; //声音字节数组 //private byte[] m_audioBytes; //private List<string> sybloms; //label缓存区 private List<UILabel> labelCaches; //label当前使用的数据 private List<UILabel> labelCur; //表情缓存区 private List<GameObject> prefabCeches; //当前使用的数据 private List<GameObject> prefabCur; private static List<LabelType> list; private string m_text; void Awake() { labelCur = new List<UILabel>(); prefabCur = new List<GameObject>(); labelCaches = new List<UILabel>(); prefabCeches = new List<GameObject>(); list = new List<LabelType>(); back = transform.FindChild("back").GetComponent<UISprite>(); } /// <summary> /// 文本内容 /// </summary> public string text { get { return m_text; } set { m_text = value; Reset(); list.Add(new LabelType(nameColor+nameText+" : [-]", InfoType.Text)); ParseSymbol(value); ShowSymbol(list); NGUITools.UpdateWidgetCollider(back.gameObject); } } private static void ParseSymbol(string value) { if (string.IsNullOrEmpty(value)) return; int startIndex = 0; int endIndex = 0; string startString; string endString = value; string pattern = "\\{\\d\\d*\\}"; MatchCollection matchs = Regex.Matches(value, pattern); string str; if (matchs.Count > 0) { foreach (Match item in matchs) { str = item.Value; startIndex = endString.IndexOf(str); endIndex = startIndex + str.Length; if (startIndex > -1) { startString = endString.Substring(0, startIndex); if (!string.IsNullOrEmpty(startString)) list.Add(new LabelType(startString, InfoType.Text)); if (!string.IsNullOrEmpty(str)) list.Add(new LabelType(str, InfoType.Face)); endString = endString.Substring(endIndex); } } if (!string.IsNullOrEmpty(endString)) list.Add(new LabelType(endString, InfoType.Text)); } else { list.Add(new LabelType(endString, InfoType.Text)); } } private void ShowSymbol(List<LabelType> list) { foreach (LabelType item in list) { switch (item.type) { case InfoType.Text : CreateTextLabel(item.info); break; case InfoType.Face : CreateFace(item.info); break; } } } private void CreateTextLabel(string value) { UILabel label; if (labelCaches.Count > 0) { label = labelCaches[0]; labelCaches.Remove(label); label.gameObject.SetActive(true); } else { GameObject go = GameObject.Instantiate(Label) as GameObject; go.transform.parent = transform; label = go.GetComponent<UILabel>(); go.transform.localScale = Vector3.one; } string sbstr = ""; string text = ""; NGUIText.size = label.fontSize; NGUIText.finalSize = label.fontSize; NGUIText.dynamicFont = label.trueTypeFont; NGUIText.lineWidth = MaxLineWidth - positionX; NGUIText.maxLines = 10000; NGUIText.lineHeight = 10000; NGUIText.WrapText(value, out sbstr); int index = sbstr.IndexOf("\n"); if (index > -1) { text = sbstr.Substring(0, index); } else { text = sbstr; } label.text = infoColor + text + "[-]"; label.gameObject.transform.localPosition = new Vector3(positionX, positionY, 0); positionX += label.width; labelCur.Add(label); sbstr = sbstr.Remove(0, text.Length); if (labelNameWidth == 0) labelNameWidth = label.width; if (sbstr.Length > 0) { positionX = 12 + labelNameWidth; positionY -= cellHeight; back.height += cellHeight; sbstr = sbstr.Replace("\n", ""); CreateTextLabel(sbstr); } } private void CreateFace(string value) { int index = Prefabs.IndexOf(value); if (index > -1) { GameObject face; UIWidget widget; if (prefabCeches.Count > 0) { face = prefabCeches[0]; prefabCeches.Remove(face); face.SetActive(true); } else { face = GameObject.Instantiate(FacePrefab) as GameObject; face.transform.parent = gameObject.transform; face.transform.localScale = FacePrefab.transform.localScale; } UISprite sprite = face.GetComponent<UISprite>(); sprite.spriteName = value; widget = face.GetComponent<UIWidget>(); widget.pivot = UIWidget.Pivot.TopLeft; if (MaxLineWidth < (positionX + widget.width)) { positionX = 12 + labelNameWidth; positionY -= cellHeight; back.height += cellHeight; } face.transform.localPosition = new Vector3(positionX, positionY, 0); positionX += widget.width; prefabCur.Add(face); } else { CreateTextLabel(value); } } private void Reset() { positionX = 10; positionY = -6; labelNameWidth = 0; back.height = cellHeight; list.Clear(); while (labelCur.Count > 0) { UILabel lab = labelCur[0]; labelCur.Remove(lab); labelCaches.Add(lab); lab.gameObject.SetActive(false); } while (prefabCur.Count > 0) { GameObject go = prefabCur[0]; prefabCur.Remove(go); prefabCeches.Add(go); go.SetActive(false); } } } |
6 Comments
有些问题希望请教,我QQ139570714,希望能加到您
ChatItem.cs里
NGUIText.size = label.fontSize;
NGUIText.finalSize = label.fontSize;
NGUIText.dynamicFont = label.trueTypeFont;
NGUIText.lineWidth = MaxLineWidth – positionX;
NGUIText.maxLines = 10000;
NGUIText.lineHeight = 10000;
NGUIText.WrapText(value, out sbstr);
UILabel里有Wrap方法的
//修改为固定宽,自适应高度
label.overflowMethod = UILabel.Overflow.ResizeHeight;
label.width = MaxLineWidth – positionX;
label.Wrap(value, out sbstr);
//赋值前修改为全自适应
label.overflowMethod = UILabel.Overflow.ResizeFreely;
label.text = text;
老版本没有NGUIText怎么办,新版的label.wrap也是调用了NGUIText.wrap
最近在做一个网络聊天的UI界面
发送消息这块正常 但接收别人的消息一直都在循环 我是用的UITextList做的 搞了很久也没找到BUG
求帮助 !!!
这个应该是自身逻辑代码,有bug吧。估计不会是NGUI的问题。
[…] 之前发过一个图文混排的文章《[Unity3D学习]NGUI UILabel 图文混排》、一直感觉那样比较消耗。又由于公司项目也需要做图文混排,就想了另一种图文混排思路,从性能来说比之前的思路要好很多,不过也有弊端,现在这种解决方案,做动态表情不太适应。不过我想的是,手机游戏对聊天功能其实已经比较弱化了,所以个人认为聊天不需要做得太复杂,一切从简就好。 […]