这有效,但是它会用onLayout
来计算高度,所以它必须开始展开以获得高度,然后快速折叠。在较慢的手机上它不会发生得足够快而且看起来很糟糕。我试图在计算时隐藏可折叠部分,但是我很难顺利完成它。
import React, { Component, PropTypes } from 'react'
import {
Text,
View,
Image,
TouchableHighlight,
Animated,
TouchableOpacity,
} from 'react-native'
import {
Icon,
} from 'native-base';
import EStyleSheet from 'react-native-extended-stylesheet';
class Panel extends Component {
static propTypes = {
expanded: PropTypes.bool,
icon: PropTypes.string,
title: PropTypes.string,
onToggle: PropTypes.func,
}
static defaultProps = {
expanded: false,
}
constructor(props) {
super(props);
this.state = {
expanded: props.expanded,
animation: new Animated.Value(),
};
}
toggle = () => {
const { onToggle } = this.props;
const { expanded, maxHeight, minHeight, animation } = this.state;
const expandedHeight = minHeight + maxHeight;
const collapsedHeight = minHeight;
const initialValue = expanded ? expandedHeight : collapsedHeight;
const finalValue = expanded ? collapsedHeight : expandedHeight;
const animationType = 'spring'; // spring, timing
this.setState({ expanded: !expanded });
animation.setValue(initialValue);
Animated[animationType](animation, {
toValue: finalValue,
}).start();
onToggle();
}
_setMinHeight(event) {
const { minHeight, expanded, animation } = this.state;
if (!minHeight) {
this.setState({ minHeight: event.nativeEvent.layout.height });
if (!expanded) {
animation.setValue(event.nativeEvent.layout.height);
}
}
}
_setMaxHeight(event) {
const { maxHeight } = this.state;
if (!maxHeight) {
this.setState({ maxHeight: event.nativeEvent.layout.height });
}
}
render () {
const { expanded, animation, maxHeight } = this.state;
return (
<Animated.View style={[styles.container, { height: animation }]}>
<TouchableHighlight underlayColor="#C7CAEE" onPress={this.toggle}>
<View
style={styles.titleContainer}
onLayout={event => this._setMinHeight(event)}
>
{this.props.icon && <Icon style={styles.titleIcon} name={this.props.icon} />}
<Text style={styles.title}>{this.props.title}</Text>
{this.props.filtering && <Icon style={styles.filteringIcon} name="md-funnel" />}
<Icon style={styles.toggleIcon} name={expanded ? "ios-arrow-up" : "ios-arrow-down"} />
</View>
</TouchableHighlight>
<View
style={styles.body}
onLayout={event => this._setMaxHeight(event)}
>
{this.props.children}
</View>
</Animated.View>
)
}
}
const styles = EStyleSheet.create({
container: {
backgroundColor: '#fff',
margin: 5,
overflow:'hidden',
borderRadius: 5,
borderColor: '#C7CAEE',
borderWidth: 1,
},
titleContainer: {
flexDirection: 'row',
},
titleIcon: {
color: 'black',
paddingLeft: 10,
alignSelf: 'center',
},
title: {
flex: 1,
padding: 10,
color: '#2a2f43',
fontWeight:'bold',
},
toggleIcon: {
color: '#E91F63',
paddingRight: 10,
alignSelf: 'center',
},
filteringIcon: {
color: '#3F51B5',
paddingRight: 10,
alignSelf: 'center',
fontSize: 20,
},
body: {
padding: 10,
paddingTop: 0,
},
});
export default Panel;
更新
<Animated.View style={[styles.container, { height: animation }, { opacity: (minHeight && maxHeight) ? 1 : 0 }]}>
看起来没问题,但必须有更好的方法来做到这一点!此外,动画会跳过很长的项目列表...
答案 0 :(得分:1)
您可以尝试的一种方法是 LayoutAnimation ,它会在您的UI的上一个和下一个状态之间进行插值。不是Animated.View
而是使用常规View
并在{ height: 0 }
和未指定的高度之间切换,让布局系统为您计算。
要为高度更改设置动画,请在LayoutAnimation.easeInEaseOut()
调用之前调用setState
,以便折叠或展开用户界面。
如果您希望尝试使用onLayout
但没有闪烁的方法,您可以尝试在测量时将面板的不透明度设置为零,或者绝对定位面板以免影响其周围的布局测量它时的组件。
您还可以将这些技术应用于面板的祖先组件。例如,您可以在测量面板时将整个屏幕的不透明度设置为零。