React Native:Android截断文本末尾图标不显示问题求助
在文本末尾添加图标(兼容iOS/Android截断场景)
需求:无论文本是否截断,都要在末尾附近显示图标。目前iOS端正常运行,但Android端文本截断时图标无法显示,求可行解决方案(含第三方库方案)。
当前实现代码
const Title = styled.Text` color: ${colorPalette.N80}; font-size: 14px; line-height: 16.8px; text-transform: uppercase; ${() => ({ ...fontFamilyForStyledComponents(typeStyles.alternative.bold) })}; `; const DescriptionWrapper = styled.View` width: 100%; flex-direction: row; align-items: center; `; const TextWrapper = styled.Text` flex-direction: row; flex-wrap: wrap; `; const Description = styled.Text` color: ${colorPalette.B1100}; font-size: 14px; line-height: 19.6px; ${() => ({ ...fontFamilyForStyledComponents(typeStyles.regular.regular) })}; `; const PremiumIcon = styled.View` width: 9px; height: 14px; justify-content: flex-end; padding-bottom: ${isAndroid ? 0 : 2}px; `; // .... const [truncatedTitle, setTruncatedTitle] = useState(''); const isTruncated = (lines) => { const numberOfLines = lines.length; if (lines.length < 3) return false; if (isAndroid && lines.length>3) { return true} // lines.length equals to numberOfLines on iOS if text is truncated or it // takes exactly numberOfLines // This is used to trim some chars from the last line chars to display the lock at the end of the 3 dots return lines[numberOfLines-1].text.length > lines[0].text.length-5 } const onTextLayout = (event: any) => { const { lines } = event.nativeEvent; // If the text is truncated we make sure there is space for the lock icon at the end of the // string by removing about 10% of last row characters if last row is too big. if (!truncatedTitle && isTruncated(lines)) { let text = lines.slice(0, 3).map((line: any) => line.text).join(''); const lineLength = Math.max(lines[0].text.length, lines[1].text.length) setTruncatedTitle(text.substr(0, Math.floor(2.8*lineLength)).concat('...')); } } // ... return ( <TextWrapper hasIcon={hasIcon} numberOfLines={3} ellipsizeMode='tail' onTextLayout={onTextLayout} > <Description> {truncatedTitle || title} </Description> <Text> <Spacer /> {!item.props.isPremium && ( <PremiumIcon> <NewsFeedPremiumIcon /> // <-- this is a simple svg icon </PremiumIcon> )} </Text> </TextWrapper> )
解决方案
方案1:使用react-native-read-more-text第三方库
这个库专门处理文本截断场景,支持自定义后缀内容(包括图标),双平台兼容。
安装:
npm install react-native-read-more-text --save # 或 yarn add react-native-read-more-text
使用示例:
import ReadMore from 'react-native-read-more-text'; // ... <ReadMore numberOfLines={3} // 文本截断时显示的尾部(包含省略号和图标) renderTruncatedFooter={() => ( <View style={{flexDirection: 'row', alignItems: 'center', marginLeft: 4}}> <Text>...</Text> <Spacer /> {!item.props.isPremium && ( <PremiumIcon> <NewsFeedPremiumIcon /> </PremiumIcon> )} </View> )} // 文本未截断时显示的尾部(直接显示图标) renderRevealedFooter={() => ( <View style={{flexDirection: 'row', alignItems: 'center', marginLeft: 4}}> <Spacer /> {!item.props.isPremium && ( <PremiumIcon> <NewsFeedPremiumIcon /> </PremiumIcon> )} </View> )} > <Description>{title}</Description> </ReadMore>
方案2:手动调整布局(无第三方依赖)
Android的Text组件嵌套子元素时,截断逻辑会忽略子元素,所以改用View包裹文本和图标,让文本占满剩余空间,图标固定在右侧。
代码实现:
import { useWindowDimensions, useRef, useEffect, useState } from 'react-native'; // ... const { width: screenWidth } = useWindowDimensions(); const textRef = useRef(null); const [isTruncated, setIsTruncated] = useState(false); // 计算文本是否需要截断 useEffect(() => { if (!textRef.current) return; textRef.current.measure((_x, _y, textWidth) => { // 计算3行文本的最大允许宽度(假设容器宽度等于屏幕宽度,根据实际情况调整) const maxAllowedWidth = screenWidth * 3; setIsTruncated(textWidth > maxAllowedWidth); }); }, [title, screenWidth]); // 调整样式 const DescriptionWrapper = styled.View` width: 100%; flex-direction: row; align-items: flex-end; flex-wrap: wrap; `; const Description = styled.Text` color: ${colorPalette.B1100}; font-size: 14px; line-height: 19.6px; flex: 1; ${() => ({ ...fontFamilyForStyledComponents(typeStyles.regular.regular) })}; `; // ... return ( <DescriptionWrapper> <Description ref={textRef} numberOfLines={isTruncated ? 3 : undefined} ellipsizeMode='tail' > {title} </Description> {!item.props.isPremium && ( <PremiumIcon> <NewsFeedPremiumIcon /> </PremiumIcon> )} </DescriptionWrapper> );
方案3:Android专属优化(尝试性)
给TextWrapper添加Android专属的textBreakStrategy属性,可能改善截断时子元素的显示问题,不过这个方法不保证所有场景生效:
const TextWrapper = styled.Text` flex-direction: row; flex-wrap: wrap; ${isAndroid ? 'textBreakStrategy: simple;' : ''}; `;
内容的提问来源于stack exchange,提问作者Florin Dobre
相关产品推荐
相关产品推荐

