Unity TextMeshPro — Count Displayed Lines and Get Last Character Position
Updated: October 30, 2025 — by Appalo
This Unity tutorial teaches you how to count displayed lines and find the position of the last visible character in a TextMeshProUGUI text — without using Update().
The method uses onTextChanged for optimized performance and instant layout updates.
🔹 The Problem with Update()
Many Unity developers call Update() every frame to detect text changes in TextMeshPro.
This consumes unnecessary CPU resources when the text doesn’t change.
🔹 The Optimized Solution
Using TextMeshPro’s onTextChanged event allows your script to update only when text content changes.
Below is the full optimized script:
// TMPTextAnalyzer.cs
using UnityEngine;
using TMPro;
public class TMPTextAnalyzer : MonoBehaviour
{
[Header("References")]
public TextMeshProUGUI text; // The TMP component to analyze
public RectTransform target; // Object to position at the end of text
public float offsetX = 0f;
public float offsetY = 0f;
void OnEnable()
{
if (text == null) text = GetComponent();
AnalyzeText();
text.onTextChanged.AddListener(OnTextChanged);
}
void OnDisable()
{
text.onTextChanged.RemoveListener(OnTextChanged);
}
private void OnTextChanged(Object obj)
{
AnalyzeText();
}
private void AnalyzeText()
{
if (text.textInfo == null || text.text.Length == 0)
return;
text.ForceMeshUpdate();
// ---- Count and Log Each Line ----
for (int i = 0; i < text.textInfo.lineCount; i++)
{
int startIndex = text.textInfo.lineInfo[i].firstCharacterIndex;
int endIndex = (i == text.textInfo.lineCount - 1)
? text.text.Length
: text.textInfo.lineInfo[i + 1].firstCharacterIndex;
int length = endIndex - startIndex;
Debug.Log($"Line {i + 1}: " + text.text.Substring(startIndex, length));
}
// ---- Get Last Character Position ----
if (text.textInfo.characterCount > 0 && target != null)
{
var lastChar = text.textInfo.characterInfo[text.textInfo.characterCount - 1];
Vector3 bottomLeft = lastChar.bottomLeft;
Vector3 worldBottomLeft = text.transform.TransformPoint(bottomLeft);
Vector3 local = target.parent.InverseTransformPoint(worldBottomLeft);
target.localPosition = new Vector3(local.x - offsetX, local.y - offsetY, 0);
}
}
}
💡 How It Works
- onTextChanged — fires automatically when TextMeshPro content changes.
- ForceMeshUpdate() — instantly refreshes text layout data.
- lineInfo — provides start and end indices for each line.
- characterInfo — gives position data for each visible character.
⚙️ Setup Guide: Attach Text & Target in Canvas
- In your Unity Canvas, create a new TextMeshPro - Text (UI) element.
- Type some sample text (e.g., “This is a test for line detection”).
- Create an empty GameObject and name it
TMPTextAnalyzer. - Add the above script to it (drag & drop into Inspector).
- Drag your TextMeshProUGUI object into the script’s
Textfield. - Create an Image or UI Icon inside the same Canvas (for example, a cursor).
- Assign that image’s
RectTransforminto theTargetfield — this will move to the end of text. - Press Play — the console will display all text lines and the target will position at the end automatically.
🚀 Benefits of This Approach
- ✅ No
Update()loop — better performance. - ✅ Automatically updates only when text changes.
- ✅ Perfect for subtitles, chat systems, typing effects, or reading apps.
🧩 SEO Keywords
Unity TextMeshPro line count, TextMeshPro last character, Unity UI text tutorial, Appalo Unity tools, TMP text analyzer, Unity text position, TextMeshProUGUI event
📘 Conclusion
By using onTextChanged instead of Update(), you can significantly optimize your Unity UI logic.
This method delivers precise line and character position data while saving CPU resources — ideal for performance-critical games and reading apps.
Appalo Learn more at Appalo.net.
0 Comments