I have two views with texts inside, acting like labels. These labels are put inside a card view with a fixed width. I want the first label to always be fully visible regardless of length of text, as much as possible.
To achieve this, the second label should be shortened as much as possible with Ellipsis Mode
and FlexShrink
but once the second label is shortened such that its width is < 25 px, I want to hide it.
What I've tried:
The method I have right now is to read the width of the second label using
onTextLayout
and hide accordingly, but I'm not sure if there's a better way to achieve this effect, hopefully purely with styling.I have also tried
TextWrap
then hiding the second row but it wraps as long as both tags exceed the width - I want the second label to shorten as much as possible first, before wrapping.
Current Code Setup
const [showLabel, setShowLabel] = React.useState(true);
...
return (
<View style={styles.tagsContainer}>
{labels.slice(0, 2).map((tag: string, index: number) => {
if (index === 1 && !showLabel) {
return;
}
return (
<View
key={index}
style={[styles.tagWrapper,{flexShrink: index,}]}
>
<Text
style={styles.tag}
numberOfLines={1}
onTextLayout={(e) => {
if (index === 1 && e.nativeEvent.lines[0].width < 17) {
setShowLabel(false);
}
}}
>
{tag}
</Text>
</View>
);
})}
</View>;
)
const TAG_HEIGHT = 15
const styles = StyleSheet.create({
tagsContainer: {
flexDirection: 'row',
minHeight: TAG_HEIGHT,
},
tagWrapper: {
minHeight: TAG_HEIGHT,
alignItems: 'center',
borderWidth: 0.5,
marginRight: 4,
paddingHorizontal: 2,
},
tag: {
...font(10, 'regular'),
lineHeight: 14,
},
})
ps. Does using useState make this component stateful? That's probably not encouraged?
CodePudding user response:
There's nothing inherently wrong about your current solution. There are other ways:
- conditionally render the second View based on the width of the outer View. You can measure the width using the outer View's onLayout prop:
onLayout={({ nativeEvent }) => setWidth(nativeEvent.layout.width)}
- measure the width the same way, but set the size of your
.slice
instead based on the result
Yes, using useState makes the component stateful, but there's nothing bad about that. State is a good tool to hold local data like this.