Reputation: 9865
Background
I have a parent component which is a collapsing card. When it is past a child component and shows it when it expands, it renders in a scroll box. I tried to adjust the height of the component when it expands by using,
Dimensions.get('window').height
But the problem with that is that it makes the card the page height. I need it to be the height of the child's data plus some padding.
Example
class CardCollapsible extends Component {
constructor(props) {
super(props);
this.state = {
title: props.title,
expanded: this.props.expanded,
animation: new Animated.Value(),
icon: this.props.icon,
iconStyles: this.props.iconStyles,
};
this.anime = {
height: new Animated.Value(),
expanded: false,
contentHeight: 0,
};
this._initContentHeight = this._initContentHeight.bind(this);
this.getIconStyles = this.getIconStyles.bind(this);
this.toggle = this.toggle.bind(this);
this.anime.expanded = props.expanded;
this.minValue = props.minValue;
this.openIconStyles = props.openIconStyles;
this.closedIconStyles = props.closedIconStyles;
}
componentWillMount() {
this.getIconStyles();
}
getIconStyles() {
let iconStyles = null;
let icon = null;
if (this.state.expanded) {
iconStyles = _.extend({}, this.props.closedIconStyles);
icon = this.props.iconClose;
} else {
iconStyles = _.extend({}, this.props.openIconStyles);
icon = this.props.iconOpen;
}
const expanded = !this.state.expanded;
this.setState({ iconStyles, icon, expanded });
}
_initContentHeight(evt) {
if (this.anime.contentHeight <= 0) {
this.anime.contentHeight = evt.nativeEvent.layout.height;
this.anime.height.setValue(this.anime.expanded ? this._getMaxValue() : this._getMinValue());
}
}
_getMaxValue() { return this.anime.contentHeight + 30; }
_getMinValue() { return this.props.minValue; }
toggle() {
this.getIconStyles();
Animated.timing(this.anime.height, {
toValue: this.anime.expanded ? this._getMinValue() : this._getMaxValue(),
duration: 300,
}).start();
this.anime.expanded = !this.anime.expanded;
}
render() {
return (
<Card style={styles.container}>
<View style={styles.titleContainer}>
<CardTitle>{this.state.title}</CardTitle>
<TouchableHighlight
style={styles.button}
onPress={this.toggle}
underlayColor="#f1f1f1"
>
<Icon
name={this.state.icon}
style={[this.state.iconStyles, styles.icon]}
/>
</TouchableHighlight>
</View>
<Animated.View style={{ height: this.anime.height }} onLayout={this._initContentHeight}>
<Separator />
<CardContent style={styles.CardContent}>
{this.props.children}
</CardContent>
</Animated.View>
</Card>
);
}
}
Using the CardCollapsible
component.
Data renders in a scroll when card is expanded.
<CardCollapsible>
<FlatList>...</FlatList>
</CardCollapsible>
Then when changing these lines to
Dimensions.get('window').height
It is taking the height of the screen and will not close.
_initContentHeight(evt) {
if (this.anime.contentHeight <= 0) {
this.anime.contentHeight = evt.nativeEvent.layout.height;
this.anime.height.setValue(this.anime.expanded ? this._getMaxValue() : this._getMinValue());
}
}
_getMaxValue() { return Dimensions.get('window').height; }
_getMinValue() { return this.props.minValue; }
Question
How can I change the height of the card to be dynamic based on its childs data when rendered?
Upvotes: 4
Views: 1991
Reputation: 3866
What you want to do is a common approach but tricky, since react does not allow communication from children to parent.
How did I accomplish it? By using ref.measures
function. Let's take a look.
export default class MyChild extends Component {
render() {
return (
<TouchableWithoutFeedback onPress={this._onPress} ref={ref => this._options = ref}>
</TouchableWithoutFeedback>
);
}
_onPress() {
this._options.measure((fx, fy, width, height, px, py) => {
if (this.props.setMeasuresOnParent)
this.props.setMeasuresOnParent({
relativeX: fx,
relativeY: fy,
absoluteX: px,
absoluteY: py,
height,
width
});
});
}
}
<MyChild
setMeasuresOnParent={measures => this.props.showChildren(children_id?, measures.absoluteX, measures.absoluteY)}
/>
In my case, I used a Button-styled child, but you could also use componentDidMount
in child to tell the parent its measures.
Upvotes: 3