This is what I would like to achieve:
and it’s working for iOS but Android refuses to display the icon for truncated text:
Code:
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>
)
Any workaround/solution including using a react native library to add the icon at the end of the last word of text will be tested and accepted if it works.
2
Answers
As workaround for this I had to add a
View
(with the icon aligned bottom) next to the text component for the case when text is truncated.Attention:
below code handles only the case of
maxNumberOfLines=3
, to have the code work you will have to add an extra parameter to the below component.the returned tree might be simplified and remove some of the extra wrappers.
Your issue may be that your wrapping a View component in a Text component, which is not allowed. Likely iOS is just more tolerant of it. Try to rearrange the elements so that any Text is within a View, but not vise-versa.
See related discussion here: React Native Can't nest View Inside Text