ugui模仿 - InputField的文本选中
效果
代码把光标闪烁拿掉了
using UnityEngine; using UnityEngine.UI; [DisallowMultipleComponent] [RequireComponent(typeof(CanvasRenderer))] [RequireComponent(typeof(RectTransform))] public class MyInputField_TextSelect : MonoBehaviour, ICanvasElement { protected VertexHelper m_CaretVh; protected Mesh m_CaretMesh; public Text m_Text; [Range(1, 5)] public int m_CaretWidth = 1; //光标宽度 public Color m_CaretColor = Color.black; //光标颜色 protected int m_CaretPos; //光标在哪个字符处, 光标处字符指示的是光标后面那个字符 /// <summary> /// 选择到哪个字符处. /// 从光标处往后选时, [m_CaretPos, m_SelectPos]为选中区域; /// 从光标处往前选时, [m_SelectPos, m_CaretPos]为选中区域; /// m_CaretPos==m_SelectPos时表示无选择 /// </summary> protected int m_SelectPos; public Color m_SelectColor = new Color(168f / 255f, 206f / 255f, 255f / 255f, 192f / 255f); private CanvasRenderer m_CaretRenderer; public CanvasRenderer caretRenderer { get { if (null == m_CaretRenderer) m_CaretRenderer = GetComponent<CanvasRenderer>(); return m_CaretRenderer; } } void Start() { m_CaretVh = new VertexHelper(); m_CaretMesh = new Mesh(); var renderer = this.caretRenderer; //设置材质和贴图 renderer.materialCount = 1; var caretMat = Graphic.defaultGraphicMaterial; renderer.SetMaterial(caretMat, 0); var caretTexture = Texture2D.whiteTexture; renderer.SetTexture(caretTexture); } public virtual void Rebuild(CanvasUpdate update) { switch (update) { case CanvasUpdate.LatePreRender: UpdateCaretVerts(); break; } } public void LayoutComplete() { } public void GraphicUpdateComplete() { } public bool IsDestroyed() { return (null == this); } protected virtual bool IsCaretShow() { return true; } private void UpdateCaretVerts() { var renderer = this.caretRenderer; m_CaretVh.Clear(); if (hasSelection) PopulateSelectAreaMesh(m_CaretVh); else if (IsCaretShow()) PopulateCaretMesh(m_CaretVh); m_CaretVh.FillMesh(m_CaretMesh); renderer.SetMesh(m_CaretMesh); } private void PopulateCaretMesh(VertexHelper vh) { var textGen = m_Text.cachedTextGenerator; if (textGen.characterCount <= 0) return; //光标显示在字符位置处 float minX = 0; if (m_CaretPos < textGen.characters.Count) { var chInfo = textGen.characters[m_CaretPos]; minX = chInfo.cursorPos.x; minX /= m_Text.pixelsPerUnit; } //找出光标处字符在哪一行上 var caretLine = textGen.lineCount - 1; for (int i = 1; i < textGen.lineCount; ++i) { var tLineInfo = textGen.lines[i]; if (tLineInfo.startCharIdx > m_CaretPos) { caretLine = i - 1; break; } } var lineInfo = textGen.lines[caretLine]; float maxY = lineInfo.topY / m_Text.pixelsPerUnit; float minY = maxY - lineInfo.height / m_Text.pixelsPerUnit; //这边添加一个四边形 vh.AddVert(new Vector3(minX, maxY), m_CaretColor, new Vector2(0f, 1f)); //左上 vh.AddVert(new Vector3(minX + m_CaretWidth, maxY), m_CaretColor, new Vector2(1f, 1f)); //右上 vh.AddVert(new Vector3(minX + m_CaretWidth, minY), m_CaretColor, new Vector2(1f, 0f)); //右下 vh.AddVert(new Vector3(minX, minY), m_CaretColor, new Vector2(0f, 0f)); //左下 //顺时针 vh.AddTriangle(0, 1, 2); vh.AddTriangle(0, 2, 3); } private int GetCharLine(int charIndex, TextGenerator textGen) { int line = textGen.lineCount - 1; for (int i = 1; i < textGen.lineCount; ++i) { var lineInfo = textGen.lines[i]; if (lineInfo.startCharIdx > charIndex) { return i - 1; } } return line; } private bool hasSelection { get { return m_CaretPos != m_SelectPos; } } void PopulateSelectAreaMesh(VertexHelper vh) { var textGen = m_Text.cachedTextGenerator; if (textGen.characterCount <= 0) return; int selectStartPos = m_CaretPos; int selectEndPos = m_SelectPos - 1; if (m_SelectPos < m_CaretPos) { selectStartPos = m_SelectPos; selectEndPos = m_CaretPos - 1; } int startLine = GetCharLine(selectStartPos, textGen); int endLine = GetCharLine(selectEndPos, textGen); for (int i = startLine, vertStartIndex = 0; i <= endLine; i++, vertStartIndex += 4) { var lineInfo = textGen.lines[i]; UICharInfo lineStartCharInfo; if (i == startLine) lineStartCharInfo = textGen.characters[selectStartPos]; else lineStartCharInfo = textGen.characters[lineInfo.startCharIdx]; UICharInfo lineEndCharInfo; if (i == endLine) { lineEndCharInfo = textGen.characters[selectEndPos]; } else if (i == textGen.lineCount - 1) //最后一行 { lineEndCharInfo = textGen.characters[textGen.characterCount - 1]; } else { var nextLineInfo = textGen.lines[i + 1]; lineEndCharInfo = textGen.characters[nextLineInfo.startCharIdx - 1]; } float minX = lineStartCharInfo.cursorPos.x / m_Text.pixelsPerUnit; float maxX = (lineEndCharInfo.cursorPos.x + lineEndCharInfo.charWidth) / m_Text.pixelsPerUnit; float maxY = lineInfo.topY / m_Text.pixelsPerUnit; float minY = maxY - lineInfo.height / m_Text.pixelsPerUnit; //这边添加一个四边形 vh.AddVert(new Vector3(minX, maxY), m_SelectColor, new Vector2(0f, 1f)); //左上 vh.AddVert(new Vector3(maxX, maxY), m_SelectColor, new Vector2(1f, 1f)); //右上 vh.AddVert(new Vector3(maxX, minY), m_SelectColor, new Vector2(1f, 0f)); //右下 vh.AddVert(new Vector3(minX, minY), m_SelectColor, new Vector2(0f, 0f)); //左下 //顺时针 vh.AddTriangle(vertStartIndex + 0, vertStartIndex + 1, vertStartIndex + 2); vh.AddTriangle(vertStartIndex + 0, vertStartIndex + 2, vertStartIndex + 3); } } void Update() { OnProcessInput(); } protected virtual void OnProcessInput() { if (Input.GetKeyDown(KeyCode.LeftArrow)) { if (Input.GetKey(KeyCode.LeftShift)) //改变选择区域 { if (m_SelectPos > 0) { m_SelectPos--; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); //下一帧统一更新 } } else { if (m_CaretPos > 0) { m_CaretPos--; m_SelectPos = m_CaretPos; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); } else if (m_CaretPos != m_SelectPos) { m_SelectPos = m_CaretPos; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); } } } if (Input.GetKeyDown(KeyCode.RightArrow)) { if (Input.GetKey(KeyCode.LeftShift)) //改变选择区域 { if (m_SelectPos < m_Text.text.Length) { m_SelectPos++; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); } } else { if (m_CaretPos < m_Text.text.Length) { m_CaretPos++; m_SelectPos = m_CaretPos; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); } else if (m_CaretPos != m_SelectPos) { m_SelectPos = m_CaretPos; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); } } } } }
ugui的InputFiled做了,这边简化掉了的:
(ctrl+)shift+下 选中到下一行的同一列处
(ctrl+)shift+上 选中到上一行的同一列处
ctrl+shift+右 选中到行尾
ctrl+shift+左 选中到行首
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!