赞
踩
AI对话界面,一左一右显示,对方输入两种状态,1.输入中… 2.显示文本内容(文本内容做了打字机效果显示),因为我们数据是不需要做缓存的,做场景切换等操作是重置的,所以就没考虑数据存储 单纯展示。需求点:文本框自适应大小 有最大宽度没有高度限制,可以滑动查看,每次展示位置都保持在最新
因为不考虑数据存储,所以没有复用Item,就用就生成一个新的,收到消息就生成一个新的Item,区分是右侧还是左侧,整个布局用的unity自带的排版组件,在确定左右侧之后修改verticalLayout.childAlignment
public void SetMessage(bool isSelf, string content) { var item = Instantiate(chatItemPre, itemContent); chatItem = item; itemObj.Add(item); var verticalLayout = chatItem.GetComponent<VerticalLayoutGroup>(); if (isSelf) { leftOrRightContent = chatItem.transform.Find("Right"); verticalLayout.childAlignment = TextAnchor.UpperRight; //请求数据 cts = new CancellationTokenSource(); voiceComponentAI.RequestAI(content, cts); } else { leftOrRightContent = chatItem.transform.Find("Left"); verticalLayout.childAlignment = TextAnchor.UpperLeft; } leftOrRightContent.localScale = Vector3.zero; leftOrRightContent.gameObject.SetActive(true); chatMessage = leftOrRightContent.GetComponent<VociceChatMessage>(); chatMessage.SetMessage(content, RefreshLayout, isSelf); ShowPhonyItem(isSelf); } public void RefreshLayout() { StartCoroutine(RefreshContentLayout()); } IEnumerator RefreshContentLayout() { yield return new WaitForSeconds(0.1f); var content = chatItem.GetComponent<RectTransform>(); LayoutRebuilder.ForceRebuildLayoutImmediate(content); leftOrRightContent.localScale = Vector3.one; } IEnumerator SetScrollBarValue() { yield return new WaitForSeconds(0.1f); scrollbar.value = 0; }
Item内容赋值,自动换行,打字机实现,也是依靠Unity自己的控件 这样自己就不用在吧啦啦啦算吧
public class VociceChatMessage : MonoBehaviour { public TMP_Text textComponent; public RectTransform contentRectTransform; public float maxWidth = 340f; public RectTransform bgRect; public Action onSucceed; private string fullText; private bool isRight; //是不是需要计算text private bool isShowText = false; //回答的内容是否逐字显示中 private bool isIEnumeratorIng = false; public void SetMessage(string message,Action callBack,bool _isRight) { DOTween.KillAll(); fullText = message; onSucceed = callBack; isRight = _isRight; isShowText = false; isIEnumeratorIng = false; if (isRight)//右侧内容 { isShowText = true; textComponent.text = message; } else { StartCoroutine(ShowText()); } RefreshLayout(); } public void RefreshLayout() { StartCoroutine(RefreshContentLayout()); } IEnumerator RefreshContentLayout() { yield return new WaitForSeconds(0.1f); LayoutRebuilder.ForceRebuildLayoutImmediate(contentRectTransform); onSucceed?.Invoke(); } IEnumerator ShowText() { isShowText = true; isIEnumeratorIng = true; for (int i = 0; i <= fullText.Length; i++) { textComponent.text = fullText.Substring(0, i); yield return new WaitForSeconds(0.1f); if (i == fullText.Length) { isShowText = false; isIEnumeratorIng = false; } } } public void Update() { if (isShowText) { // 计算文本宽度 float textWidth = textComponent.preferredWidth; // 如果文本宽度超过最大宽度,自动换行 if (textWidth > maxWidth) { // Text控件的Content Size Fitter由水平Preferred Size改为垂直Preferred Size textComponent.GetComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.Unconstrained; textComponent.GetComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize; // 调整文本框的大小以容纳所有文本 contentRectTransform.sizeDelta = new Vector2(maxWidth, contentRectTransform.sizeDelta.y); if(isRight == false) bgRect.sizeDelta = new Vector2(maxWidth + 20, contentRectTransform.sizeDelta.y + 20); // int lineCount = Mathf.CeilToInt(textWidth / maxWidth); // float lineHeight = textComponent.preferredHeight / textComponent.textInfo.lineCount; // float newHeight = lineHeight * lineCount; } else { // Text控件的Content Size Fitter由水平Preferred Size改为垂直Preferred Size textComponent.GetComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize; textComponent.GetComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize; if(isRight == false) bgRect.sizeDelta = new Vector2(contentRectTransform.sizeDelta.x + 20, contentRectTransform.sizeDelta.y + 20); } if(isIEnumeratorIng == false) isShowText = false; } } }
最后要根据打字机显示的效果Item自动扩容
private Vector2 lastSize; void Start() { lastSize = itemContent.GetComponent<RectTransform>().sizeDelta; } public void Update() { Vector2 currentSize = itemContent.GetComponent<RectTransform>().sizeDelta; if (currentSize != lastSize) { //Debug.Log("Content size changed!"); // 在这里可以编写处理Content大小改变时的逻辑 StartCoroutine(SetScrollBarValue()); lastSize = currentSize; } }
因为没收到消息时候要做一个假的输入中的效果,我就简单处理了,做一个假的item,然后再没收到消息的时候放在Scrollerview下面然后显示播放DOTween动画,收到消息之后 在移除Scrollerview隐藏不显示。有好多实现方式 我这种不精细 嘿嘿嘿~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。