onTextLayout은 React Native <Text> 컴포넌트의 prop이다. 텍스트가 화면에 실제로 레이아웃(배치)될 때마다 호출되며, 각 줄(line) 단위의 위치·크기 정보를 콜백으로 전달한다. JS 측에서 미리 알 수 없는 "텍스트가 몇 줄로 나뉘는가", "각 줄의 폭이 얼마인가" 같은 정보를 네이티브 측정 결과 그대로 받아올 수 있다는 점이 핵심이다.
<Text onTextLayout={(e) => console.log(e.nativeEvent.lines)}>
측정하고 싶은 텍스트
</Text>
콜백은 TextLayoutEventData를 담은 합성 이벤트를 받는다.
type TextLayoutEvent = NativeSyntheticEvent<TextLayoutEventData>;
interface TextLayoutEventData {
lines: TextLayoutLine[];
}
interface TextLayoutLine {
text: string; // 해당 줄에 실제로 렌더링된 텍스트
x: number; // 줄의 x 좌표 (Text 기준)
y: number; // 줄의 y 좌표 (Text 기준)
width: number; // 줄의 폭
height: number; // 줄의 높이
ascender: number; // 베이스라인 위 상단까지의 거리
descender: number; // 베이스라인 아래 하단까지의 거리
capHeight: number; // 대문자 높이
xHeight: number; // 소문자 x 높이
}
lines 배열의 길이가 곧 실제로 렌더링된 줄 수이다. numberOfLines로 잘린 경우에는 잘린 후의 줄 수가 반영된다.
numberOfLines로 제한한 텍스트가 실제로 잘렸는지를 판별할 때 쓴다. 제한 없이 한 번 측정한 뒤 줄 수가 임계값을 넘는지 확인하는 패턴이다.
function ExpandableText({ children }: { children: string }) {
const [needsExpand, setNeedsExpand] = useState(false);
const [expanded, setExpanded] = useState(false);
const measured = useRef(false);
return (
<View>
<Text
numberOfLines={expanded ? undefined : 3}
onTextLayout={(e) => {
// 최초 측정 시 한 번만 줄 수 판별
if (measured.current) return;
measured.current = true;
if (e.nativeEvent.lines.length > 3) {
setNeedsExpand(true);
}
}}
>
{children}
</Text>
{needsExpand && (
<Text onPress={() => setExpanded((v) => !v)}>
{expanded ? '접기' : '더보기'}
</Text>
)}
</View>
);
}
주의:
numberOfLines로 잘린 상태에서는lines.length가 제한값을 넘지 않는다. 잘림 여부를 정확히 판별하려면 제한 없이 측정하는 별도 단계를 두거나,onTextLayout과numberOfLines의 호출 순서를 고려해 설계해야 한다.
각 줄의 x, y, width, height를 이용해 줄마다 하이라이트 배경, 밑줄, 오버레이 등을 절대 위치로 그릴 수 있다.
<View>
<Text onTextLayout={(e) => setLines(e.nativeEvent.lines)}>
{content}
</Text>
{lines.map((line, i) => (
<View
key={i}
style={{
position: 'absolute',
left: line.x,
top: line.y,
width: line.width,
height: line.height,
backgroundColor: 'rgba(255,235,59,0.3)',
}}
/>
))}
</View>
폰트 메트릭(ascender, descender, capHeight, xHeight)을 활용해 정밀한 베이스라인 정렬이나 커스텀 타이포그래피 레이아웃을 구현할 때 참고값으로 쓴다.
ref 가드로 보호한다.numberOfLines와의 상호작용: 잘린 결과가 lines에 반영되므로, 원본 줄 수가 필요하면 제한 없는 측정이 필요하다.lines가 빈 배열일 수 있다.onTextLayout 안에서 무조건 setState를 호출하면 측정→리렌더→재측정 루프에 빠질 수 있으므로, 값이 실제로 바뀔 때만 상태를 갱신하도록 비교 후 업데이트한다.