You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 17:47:17