ugui学习 - 自己实现InputField鼠标点击调整光标位置,拖拽修改选中区域

发布时间 2023-07-31 23:31:50作者: yanghui01

效果

 

代码

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class MyInputField_CaretDragOp : MyInputField_TextSelect, IDragHandler, IPointerDownHandler
{

    public void OnPointerDown(PointerEventData eventData)
    {
        if (!isActiveAndEnabled) return;
        if (eventData.button != PointerEventData.InputButton.Left) return;
        if (null == m_Text) return;

        Vector2 localPosInText; //相对Text的local坐标, 以Text的pivot为原点
        RectTransformUtility.ScreenPointToLocalPointInRectangle(m_Text.rectTransform, eventData.position, eventData.pressEventCamera, out localPosInText);
        m_CaretPos = m_SelectPos = GetCharIndexFromPosition(localPosInText);
        CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); //下一帧统一更新光标
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (!isActiveAndEnabled) return;
        if (eventData.button != PointerEventData.InputButton.Left) return;
        if (null == m_Text) return;

        Vector2 localPosInText; //相对Text的local坐标, 以Text的pivot为原点
        RectTransformUtility.ScreenPointToLocalPointInRectangle(m_Text.rectTransform, eventData.position, eventData.pressEventCamera, out localPosInText);
        m_SelectPos = GetCharIndexFromPosition(localPosInText);
        CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); //下一帧统一更新光标

        eventData.Use();
    }

    /// <summary>
    /// 该行最后一个字符的索引
    /// </summary>
    private static int GetLineEndCharIndex(TextGenerator textGen, int line)
    {
        line = Mathf.Max(line, 0);
        int nextLine = line + 1;
        if (nextLine < textGen.lines.Count)
            return textGen.lines[nextLine].startCharIdx - 1; //下一行结束字符的前一个字符

        return textGen.characterCountVisible;
    }

    private int GetCharLineFromPosition(TextGenerator textGen, Vector2 localPos)
    {
        float localPosY = localPos.y * m_Text.pixelsPerUnit;
        float lastLineBottomY = 0.0f;

        for (int i = 0; i < textGen.lineCount; ++i)
        {
            var tLineInfo = textGen.lines[i];
            float lineTopY = tLineInfo.topY;
            float lineBottomY = lineTopY - tLineInfo.height; //往下为减

            if (localPosY > lineTopY)
            {
                float halfLeading = (lineTopY - lastLineBottomY) * 0.5f; //行间距
                if (localPosY > (lineTopY - halfLeading)) //超过行间距一半, 算上一行
                    return i - 1;
                else
                    return i;
            }

            if (localPosY > lineBottomY)
                return i;

            lastLineBottomY = lineBottomY;
        }

        return textGen.lineCount; //没找到, 用最后一行
    }

    protected int GetCharIndexFromPosition(Vector2 localPos)
    {
        TextGenerator textGen = m_Text.cachedTextGenerator;

        if (0 == textGen.lineCount)
            return 0;

        int line = GetCharLineFromPosition(textGen, localPos);
        if (line < 0)
            return 0;

        if (line >= textGen.lineCount)
            return textGen.characterCountVisible;

        int startCharIndex = textGen.lines[line].startCharIdx;
        int endCharIndex = GetLineEndCharIndex(textGen, line);

        //在找到的行的字符间找
        for (int i = startCharIndex; i < endCharIndex; i++)
        {
            if (i >= textGen.characterCountVisible)
                break;

            UICharInfo charInfo = textGen.characters[i];
            Vector2 charPos = charInfo.cursorPos / m_Text.pixelsPerUnit;

            //以字符宽度一半为前后字符的分界
            if (localPos.x <= (charPos.x + charInfo.charWidth * 0.5f / m_Text.pixelsPerUnit))
                return i;
        }

        return endCharIndex;
    }

}