Reputation: 438
I'm using react-native-collapsible to create an accordion. I'm styling the header for each accordion section to look a bit like a list item with some icons, including a chevron. When I tap each section, I'd like to change that section's header chevron from right to down.
I've muddled about with some samples from the "Direct Manipulation" page in the RN docs, and have attempted to employ the use of state variables, but I'm having no luck.
Here's what I've got, and it's telling me onChange() that this.refs['First'] is undefined, though the first chevron's icon ref is "First".
class AccordionView extends React.Component {
constructor(props) {
super(props);
//console.log(props);
this.state = {
icons: "chevron-right",
};
}
_renderHeader(section) {
return (
<View style={styles.accHeader}>
<View style={{flex: 1, flexDirection:'row', alignItems: 'center', justifyContent:'flex-start'}}>
<View style={{flex:.5,flexDirection:'row',alignItems:'center',justifyContent:'flex-start'}}>
<Text style={styles.accHeaderText}>{section.title}</Text>
</View>
<View style={{flex:.5,flexDirection:'row',alignItems:'center',justifyContent:'flex-end'}}>
<FontAwesome name="link" size={24} color="#666" style={{paddingHorizontal:6}} onPress={() => alert('link!')} />
<MaterialIcons name="place" size={24} color="#666" style={{paddingHorizontal:6}} />
<FontAwesome name="phone" size={24} color="#666" style={{paddingHorizontal:6}} />
<FontAwesome name="chevron-right" size={24} color="#999" style={{paddingHorizontal:8}} ref={section.title} />
</View>
</View>
</View>
)
};
_renderContent(section) {
return (
<View style={styles.accContent}>
<Text>{section.content}</Text>
</View>
);
};
_onChange(index) {
this.refs['First'].setNativeProps({name:"chevron-down"});
};
render() {
return (
<Accordion
sections={sections}
renderHeader={this._renderHeader}
renderContent={this._renderContent}
underlayColor="#0972CE"
onChange={this._onChange}
/>
);
} }
Upvotes: 2
Views: 2110
Reputation: 478
The 'isActive' prop of React Native collapsible package can be used to achieve this. The implementation is as follows;
class AccordionView extends React.Component {
constructor(props) {
super(props);
//console.log(props);
this.state = {
icons: "chevron-right"
};
}
_renderHeader(section, index, isActive) {
return (
<View style={styles.accHeader}>
<View
style={{
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start"
}}
>
<View
style={{
flex: 0.5,
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start"
}}
>
<Text style={styles.accHeaderText}>{section.title}</Text>
</View>
<View
style={{
flex: 0.5,
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-end"
}}
>
<FontAwesome
name="link"
size={24}
color="#666"
style={{ paddingHorizontal: 6 }}
onPress={() => alert("link!")}
/>
<MaterialIcons
name="place"
size={24}
color="#666"
style={{ paddingHorizontal: 6 }}
/>
<FontAwesome
name="phone"
size={24}
color="#666"
style={{ paddingHorizontal: 6 }}
/>
{isActive ? (
<FontAwesome
name="chevron-right"
size={24}
color="#999"
style={{ paddingHorizontal: 8 }}
ref={section.title}
/>
) : (
<FontAwesome
name="chevron-down"
size={24}
color="#999"
style={{ paddingHorizontal: 8 }}
ref={section.title}
/>
)}
</View>
</View>
</View>
);
}
_renderContent(section) {
return (
<View style={styles.accContent}>
<Text>{section.content}</Text>
</View>
);
}
_onChange(index) {
this.refs["First"].setNativeProps({ name: "chevron-down" });
}
render() {
return (
<Accordion
sections={sections}
renderHeader={this._renderHeader}
renderContent={this._renderContent}
underlayColor="#0972CE"
onChange={this._onChange}
/>
);
}
}
Upvotes: 0
Reputation: 169
There is a prop which is isActive
just pass the prop in header or content component like this below
_renderHeader(section, index, isActive) {
return(
{isActive ? <Text>icon 1 </Text> : <Text>icon 2 </Text> }
)
}
Upvotes: 0
Reputation: 905
You should store the active index in state, and update the state when a different section becomes active. Then on the icon, check if the index in the state matches the index of the section being rendered, and set the relevant icon.
(I've not been able to test the below code, so I cant guarantee it works, but it should give you the general idea of how it can work.)
class AccordionView extends React.Component {
constructor(props) {
super(props);
//console.log(props);
this.state = {
activeIndex: 0,
};
}
_renderHeader(section, index) {
return (
<View style={styles.accHeader}>
<View style={{flex: 1, flexDirection:'row', alignItems: 'center', justifyContent:'flex-start'}}>
<View style={{flex:.5,flexDirection:'row',alignItems:'center',justifyContent:'flex-start'}}>
<Text style={styles.accHeaderText}>{section.title}</Text>
</View>
<View style={{flex:.5,flexDirection:'row',alignItems:'center',justifyContent:'flex-end'}}>
<FontAwesome name="link" size={24} color="#666" style={{paddingHorizontal:6}} onPress={() => alert('link!')} />
<MaterialIcons name="place" size={24} color="#666" style={{paddingHorizontal:6}} />
<FontAwesome name="phone" size={24} color="#666" style={{paddingHorizontal:6}} />
<FontAwesome name={this.state.activeIndex === index ? "chevron-down" : "chevron-right"} size={24} color="#999" style={{paddingHorizontal:8}} />
</View>
</View>
</View>
)
};
_renderContent(section) {
return (
<View style={styles.accContent}>
<Text>{section.content}</Text>
</View>
);
};
_onChange(index) {
this.setState({
activeIndex: index,
})
};
render() {
return (
<Accordion
sections={sections}
renderHeader={this._renderHeader}
renderContent={this._renderContent}
underlayColor="#0972CE"
onChange={this._onChange}
/>
);
}
}
Upvotes: 1