Reputation: 41685
Following is from instagram which is known for using react-native
As you can see there is a text (더보기, which means More
) after the elipsis (...)
How can I simulate that too?
Upvotes: 1
Views: 1579
Reputation: 2018
Well, that is one of those things that on the surface looks easy enough, but actually is a complicated endeavor.
Due to this thing over here: https://github.com/facebook/react-native/issues/22811 you won't be able to nest the <Text>
tag and use the numberOfLines prop to achieve what you want.
In the past I've tried to deal with something similar: React Native chat bubble flexbox similar to whatsapp
Back then there was no onTextLayout function(or at least I didn't know about it). The onTextLayout callback on the Text component gives you a line prop. The line is an array that contains information about every line of text. You could use this to place the more button where you want.
const MoreInfo = text => {
const [moreLeft, setMoreLeft] = React.useState(0)
const [moreTop, setMoreTop] = React.useState(0)
return (
<View style={{ marginTop: 20 }}>
<Text
numberOfLines={2}
ellipsizeMode={"tail"}
onTextLayout={({ nativeEvent: { lines } }) => {
const width = lines[lines.length - 1].width
const height = lines[lines.length - 1].y
setMoreTop(height)
setMoreLeft(width)
}}
>
{text}
</Text>
<Text
style={{
backgroundColor: "white",
position: "absolute",
left: moreLeft - 30,
top: moreTop,
}}
>
... More
</Text>
</View>
)
}
Obviously the above implementation is not perfect. As you can see I just fake the ... by placing them in the More button. Sometimes it looks good, othertimes it cuts off the last letter in the string in the middle. But it serves to show the direction you need to go to solve this.
Some ideas: inspect the lines array - if it has 2 lines is the last line width smaller than the first line width. Will your "More" text fit in the width difference? If yes, then just set the left position to the width. if the second line is as long as the first one, then the ellepsis is at the end and you'll need to resort to the "... More" trick.
Upvotes: 1
Reputation: 2135
Here is a quick workaround. Create a function which takes text as an argument and show truncated text with a more button. Upon click, we will render full text with a less button.
const MoreLessComponent = ({ truncatedText, fullText }) => {
const [more, setMore] = React.useState(false);
return (
<Text>
{!more ? `${truncatedText}...` : fullText}
<TouchableOpacity onPress={() => setMore(!more)}>
<Text>{more ? 'less' : 'more'}</Text>
</TouchableOpacity>
</Text>
);
};
const MoreInfo = (text, linesToTruncate) => {
const [clippedText, setClippedText] = React.useState(false);
return clippedText ? (
<MoreLessComponent truncatedText={clippedText} fullText={text} />
) : (
<Text
numberOfLines={linesToTruncate}
ellipsizeMode={'tail'}
onTextLayout={(event) => {
//get all lines
const { lines } = event.nativeEvent;
//get lines after it truncate
let text = lines
.splice(0, linesToTruncate)
.map((line) => line.text)
.join('');
//substring with some random digit, this might need more work here based on the font size
//
setClippedText(text.substr(0, text.length - 9));
}}>
{text}
</Text>
);
};
Now call it like this
<View>
{MoreInfo('Change code in the editor and watch it change on your phone! Save to get a shareable url.')}
</View>
Here is the snack https://snack.expo.io/@saachitech/react-native-more-less
Upvotes: 0