Почему дочерняя кнопка выбора, расположенная под основной родительской кнопкой, срабатывает при нажатии определенного места на родительской кнопке? - PullRequest
0 голосов
/ 01 мая 2020

У меня есть анимированная кнопка (touchableOpacity, обертывающая анимированное изображение), которая при нажатии вращается и открывает множество параметров (анимированные виды, оборачивающие сенсорную непрозрачность).

проблема заключается в том, что при нажатии определенного места родительской кнопки, выполняется onPress() дочерних кнопок. Придирчиво к тому, что нажатие родительской кнопки выполняет дочерние кнопки onPress(). Кажется, что это не всегда одинаково. это не всегда предсказуемо, например, если нажат прямой центр родителя, выполняется только родитель onPress(). если нажать 10px справа от центра, выполняется дочерний элемент onPress(). однако, если нажать 10px слева от центра, дочерний элемент onPress() не будет выполнен, только ожидаемая родительская функция.

вот основной компонент анимированной кнопки:

export default class OptionFan extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            animatedRotate: new Animated.Value(0),
            expanded: false
        };
        this.refOptions = [];
    }
    handlePress = () => {
        if (this.state.expanded) {
            Animated.spring(this.state.animatedRotate, {
                toValue: 0
            }).start();
            for (var i = 0; i < this.refOptions.length; i++) {
                this.refOptions[i].collapse();
            }
            this.setState({ expanded: !this.state.expanded });
        } else {
            Animated.spring(this.state.animatedRotate, {
                toValue: 1
            }).start();
            for (var i = 0; i < this.refOptions.length; i++) {
                this.refOptions[i].expand();
            }
            this.setState({ expanded: !this.state.expanded });
        }
    };

    render () {
        const animatedRotation = this.state.animatedRotate.interpolate({
            inputRange: [ 0, 0.5, 1 ],
            outputRange: [ '0deg', '90deg', '180deg' ]
        });
        return (
            <TouchableOpacity
                style={[ styles.touchableContainer, this.props.style ]}
                onPress={() => this.handlePress()}
            >
                {this.props.options.map((item, index) => (
                    <FanItem
                        ref={(ref) => {
                            this.refOptions[index] = ref;
                        }}
                        icon={item.icon}
                        onPress={() => alert("pressed button " + index)}
                        collapse={this.handlePress}
                        index={index}
                        key={item.key}
                    />
                ))}
                <Animated.Image
                    resizeMode={'contain'}
                    source={require('../assets/img/arrow-up.png')}
                    style={{ transform: [ { rotateZ: animatedRotation } ], ...styles.icon }}
                />
            </TouchableOpacity>
        );
    }
}

вот дочерний элемент Компонент опции:

export default class FanItem extends React.Component {
    constructor (props) {
        super(props);
        this.animatedOffset = new Animated.ValueXY(0);
        this.animatedOpacity = new Animated.Value(0);
    }

    expand () {
        let offset = { x: 0, y: 0 };
        switch (this.props.index) {
            case 0:
                offset = { x: 0, y: -70 };
                break;
            case 1:
                offset = { x: 0, y: -125 };
                break;
            case 2:
                offset = { x: 0, y: -180 };
                break;
        }
        Animated.parallel([
            Animated.spring(this.animatedOffset, { toValue: offset }),
            Animated.timing(this.animatedOpacity, { toValue: 1, duration: 500 })
        ]).start();
    }

    collapse () {
        Animated.parallel([
            Animated.spring(this.animatedOffset, { toValue: 0 }),
            Animated.timing(this.animatedOpacity, { toValue: 0, duration: 300 })
        ]).start();
    }

    render () {
        return (
            <Animated.View
                style={
                    (this.props.style,
                    {
                        left: this.animatedOffset.x,
                        top: this.animatedOffset.y,
                        opacity: this.animatedOpacity
                    })
                }
            >
                <TouchableOpacity
                    style={styles.touchableContainer}
                    onPress={() => {
                        this.props.onPress();
                        this.props.collapse();
                    }}
                >
                    <Image resizeMode={'contain'} source={this.props.icon} style={styles.icon} />
                </TouchableOpacity>
            </Animated.View>
        );
    }
}

единственное явное позиционирование определяется на дочерних кнопках опции:

touchableContainer: {
    justifyContent: 'center',
    alignItems: 'center', 
    borderRadius: 30,
    backgroundColor: Colors.PRIMARY_GREEN,
    elevation: 15,
    shadowOffset: {
        height: 3,
        width: 3
    },
    shadowColor: '#333',
    shadowOpacity: 0.5,
    shadowRadius: 5,
    height: 42,
    width: 42,
    position: 'absolute',
    left: -22,
    bottom: -30
}

Каждый раз, когда выполняется дочерняя функция, консоль всегда регистрирует «Нажатую кнопку 1». поэтому второй дочерний параметр onPress() всегда выполняется. никогда не первый индекс.

Любой совет, как решить эту проблему?

...