若 Text 設置了 numberOfLines,onTextLayout 在 Android 上可以獲取總文字行數,iOS 則不行,最多只能拿到 numberOfLines 的行數。
比如下方這段文字:
「有人嗎?有…」一條來自高皓軍(劉德華 飾)的神祕訊息從萬呎高空傳來國際安保專家高皓軍和失明的女兒小軍(張子楓 飾)搭乘有「空中巨無霸」之稱的五星級超豪華客機 A380 的國際首航,途中遭遇暴徒劫機。無差別射殺的恐怖手段,讓豪華機艙瞬間變成密閉煉獄,800 多名乘客危在旦夕,高皓軍挺身而出,在數千米的高空上與一眾暴徒周旋,女兒卻受困於機艙中,劫匪頭目 Mike(屈楚蕭 飾)以全機 800 餘人的生命作為籌碼威脅,小軍的媽媽傅源(劉濤飾)也身陷危險之中,飛機能否平安降落,這場失控的危機該如何化解?
在 Android 輸出的行數為 11,但在 iOS 上輸出的行數為 5:
const onTextLayout = (e: NativeSyntheticEvent<TextLayoutEventData>) => {
console.log(e.nativeEvent.lines.length) // iOS: 5, Android: 11
}
<Text numberOfLines={maxLines} onTextLayout={onTextLayout}>
{children}
</Text>
在 iOS 上 e.nativeEvent.lines
的格式如下:
[
{
"ascender": 15.234375,
"capHeight": 13.76,
"descender": 3.859375,
"height": 24,
"text": "「有人嗎?有...」一條來自高皓軍(劉德華 飾)的",
"width": 330.744375,
"x": 0,
"xHeight": 9.6,
"y": 0
},
{
"ascender": 15.234375,
"capHeight": 13.76,
"descender": 3.859375,
"height": 24,
"text": "神祕訊息從萬呎高空傳來國際安保專家高皓軍",
"width": 326.4,
"x": 0,
"xHeight": 9.6,
"y": 24
},
{
"ascender": 15.234375,
"capHeight": 13.76,
"descender": 3.859375,
"height": 24,
"text": "和失明的女兒小軍(張子楓 飾)搭乘有「空中巨",
"width": 325.86125,
"x": 0,
"xHeight": 9.6,
"y": 48
},
{
"ascender": 15.234375,
"capHeight": 13.76,
"descender": 3.859375,
"height": 24,
"text": "無霸」之稱的五星級超豪華客機 A380 的國際",
"width": 325.674375,
"x": 0,
"xHeight": 9.6,
"y": 72
},
{
"ascender": 15.234375,
"capHeight": 13.76,
"descender": 3.859375,
"height": 24,
"text": "首航,途中遭遇暴徒劫機。無差別射殺的恐怖手段,讓豪華機艙瞬間變成密閉煉獄,800 多名乘客危在旦夕,高皓軍挺身而出,在數千米的高空上與一眾暴徒周旋,女兒卻受困於機艙中,劫匪頭目 Mike(屈楚蕭 飾)以全機 800 餘人的生命作為籌碼威脅,小軍的媽媽傅源(劉濤飾)也身陷危險之中,飛機能否平安降落,這場失控的危機該如何化解?",
"width": 326.4,
"x": 0,
"xHeight": 9.6,
"y": 96
}
]
根據上方的格式可以確定前四行的寬度一定是拉滿的才會換行(但不一定都一樣長),所以只要先找到前四行的最短寬度,再和第五行的寬度做比較,若第五行寬度超過(或相等)前四行的最短寬度,就代表總行數超過五行。
const onTextLayout = (e: NativeSyntheticEvent<TextLayoutEventData>) => {
const { lines } = e.nativeEvent
if (lines.length < maxLines) return
const shortestWidth = lines.slice(0, maxLines - 1)
.reduce((acc, cur) => cur.width < acc ? cur.width : acc, lines[0].width)
if (lines[maxLines - 1].width >= shortestWidth) {
setIsLongText(true)
}
}