如何让这个可折叠的面板开始崩溃而没有onLayout延迟?

时间:2017-01-19 00:27:17

标签: reactjs react-native

这有效,但是它会用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 }]}>

看起来没问题,但必须有更好的方法来做到这一点!此外,动画会跳过很长的项目列表...

1 个答案:

答案 0 :(得分:1)

您可以尝试的一种方法是 LayoutAnimation ,它会在您的UI的上一个和下一个状态之间进行插值。不是Animated.View而是使用常规View并在{ height: 0 }和未指定的高度之间切换,让布局系统为您计算。

要为高度更改设置动画,请在LayoutAnimation.easeInEaseOut()调用之前调用setState,以便折叠或展开用户界面。

如果您希望尝试使用onLayout但没有闪烁的方法,您可以尝试在测量时将面板的不透明度设置为零,或者绝对定位面板以免影响其周围的布局测量它时的组件。

您还可以将这些技术应用于面板的祖先组件。例如,您可以在测量面板时将整个屏幕的不透明度设置为零。