Nested PinchGestureHandler & PanGestureHandler не работает в Android - PullRequest
0 голосов
/ 22 октября 2019

Я пытаюсь создать полноэкранный режим просмотра изображений с возможностями масштабирования и панорамирования в режиме реагирования. Я использую реагирующий родной жест-обработчик для обработки нескольких касаний. Он работает нормально на iOS, но ничего не делает на Android.

Я совершенно не понимаю, почему этот код будет работать на iOS, но не на Android. Я могу подтвердить, что мои настройки обработчика реакции-родного-жеста работают, потому что у меня работает другой PanGestureHandler, как ожидалось.

/*********************** Imports ***********************/
import React, { useRef, useEffect } from 'react';
import {
    View, StyleSheet, Animated,
} from 'react-native';

import ZoomImage from './ZoomableImage';
import { vw, vh, isiPhoneX } from '../Styles/StyleUtils';
/********************* End Imports *********************/

/*********************** ImageView Function ***********************/
const ImageView = ({ dismiss, uri, imageLayout }) => {
    const animation = useRef(new Animated.Value(0));

    useEffect(() => {
        Animated.timing(animation.current, {
            toValue: 1,
            duration: 250,
        }).start();
    }, []);

    function closeImage() {
        Animated.timing(animation.current, {
            toValue: 0,
            duration: 250,
        }).start(() => dismiss());
    }

    return (
        <View style={styles.mainContainer}>
            <Animated.View style={[
                styles.container,
                {
                    backgroundColor: animation.current.interpolate({
                        inputRange: [0, 1],
                        outputRange: ["rgba(0, 0, 0, 0)", "rgba(0, 0, 0, 0.5)"],
                    })
                }
            ]}>
                {/* <View style={styles.header}>
                    <TouchableOpacity style={styles.closeBtn} onPress={closeImage}>
                        <Icon name="close" color={blackColor} size={30} />
                    </TouchableOpacity>
                </View> */}
                <ZoomImage dismiss={closeImage} imageStyle={[
                    {
                        left: animation.current.interpolate({
                            inputRange: [0, 1],
                            outputRange: [imageLayout.pageX, 0]  // 0 : 150, 0.5 : 75, 1 : 0
                        }),

                        top: animation.current.interpolate({
                            inputRange: [0, 1],
                            outputRange: [imageLayout.pageY, vh(24)]  // 0 : 150, 0.5 : 75, 1 : 0
                        }),
                        width: animation.current.interpolate({
                            inputRange: [0, 1],
                            outputRange: [imageLayout.width, vw(100)],
                        }),
                        height: animation.current.interpolate({
                            inputRange: [0, 1],
                            outputRange: [imageLayout.height, vw(100)],
                        })
                    }
                ]}
                source={{ uri: uri }} />
            </Animated.View>
        </View>
    );
};
/********************** End ImageView Function *******************/
export default ImageView;

const styles = StyleSheet.create({
    header: {
        marginTop: isiPhoneX() ? 40 : 25,
        alignItems: "flex-end"
    },
    closeBtn: {
        paddingHorizontal: 20,
    },
    mainContainer: {
        position: "absolute",
        width: vw(100),
        height: vh(100)
    },
    container: {
        position: "absolute",
        top: 0,
        left: 0,
        right: 0, bottom: 0,
    },
    image: {
        position: "absolute",
    }
});
/*********************** Imports ***********************/
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { Animated } from 'react-native';

import {
    State,
    PanGestureHandler,
    PinchGestureHandler
} from 'react-native-gesture-handler';

import { vw, vh } from '../Styles/StyleUtils';
/********************* End Imports *********************/

/*********************** ZoomableImage Function ***********************/
const ZoomableImage = (props) => {
    const panRef = useRef();
    const pinchRef = useRef();

    const closeAnimation = useRef(new Animated.ValueXY({ x: 0, y: 0 }));

    const scaleAnimation = useRef(new Animated.Value(1));
    const baseScale = useRef(new Animated.Value(1));
    const scale = useRef(Animated.multiply(baseScale.current, scaleAnimation.current));
    const [lastScale, setLastScale] = useState(1);

    useEffect(() => {
        console.log('Refs', panRef);
    }, [panRef.current]);

    const onPanHandlerGesture = useCallback(({ nativeEvent }) => {
        console.log('Native Event', nativeEvent);
        closeAnimation.current.setValue({
            x: nativeEvent.translationX,
            y: nativeEvent.translationY
        });
    }, []);

    const onPanHandlerStateChange = useCallback(({ nativeEvent }) => {
        console.log('New Pan Event', nativeEvent);
        if (nativeEvent.oldState === State.ACTIVE) {
            if (
                nativeEvent.translationY > 250
                || nativeEvent.velocityY > 1200
            ) {
                Animated.parallel([
                    Animated.timing(scaleAnimation.current, {
                        toValue: 1,
                        duration: 200
                    }),
                    Animated.timing(baseScale.current, {
                        toValue: 1,
                        duration: 200
                    }),
                    Animated.timing(closeAnimation.current, {
                        toValue: { x: 0, y: 0 },
                        duration: 200
                    })
                ]).start(() => props.dismiss());
            }
            else {
                Animated.timing(closeAnimation.current, {
                    toValue: { x: 0, y: 0 },
                    duration: 100
                }).start();
            }
        }
    }, [lastScale]);

    const onPinchGestureEvent = Animated.event([{ nativeEvent: { scale: scaleAnimation.current } }]);

    useCallback(({ nativeEvent }) => {
        scaleAnimation.current.setValue(nativeEvent.scale);
    }, [lastScale]);

    const onPinchHandlerStateChange = ({ nativeEvent }) => {
        console.log('New Pinch Event', nativeEvent);
        if (nativeEvent.oldState === State.ACTIVE) {
            const newLastScale = lastScale * nativeEvent.scale;
            setLastScale(newLastScale);
            baseScale.current.setValue(newLastScale);
            scaleAnimation.current.setValue(1);
        }
    };

    return (
        <PanGestureHandler maxPointers={2} avgTouches onHandlerStateChange={onPanHandlerStateChange}
        minDist={10} onGestureEvent={onPanHandlerGesture} ref={panRef}>
            <PinchGestureHandler ref={pinchRef} simultaneousHandlers={panRef}
            onHandlerStateChange={onPinchHandlerStateChange} onGestureEvent={onPinchGestureEvent}>
                <Animated.Image style={[
                    props.imageStyle,
                    {
                        transform: [
                            { perspective: 1000 },
                            {
                                translateY: closeAnimation.current.y.interpolate({
                                    inputRange: [-vh(25), vh(25)],
                                    outputRange: [-vh(25), vh(25)],
                                    extrapolate: "clamp"
                                })
                            },
                            {
                                translateX: closeAnimation.current.x.interpolate({
                                    inputRange: [-vw(25), vw(25)],
                                    outputRange: [-vw(10), vw(10)],
                                    extrapolate: "clamp"
                                })
                            },
                            {
                                scale: scale.current.interpolate({
                                    inputRange: [1, 2.5],
                                    outputRange: [1, 2.5],
                                    extrapolate: "clamp"
                                })
                            }
                        ]
                    }
                ]} source={props.source} />
            </PinchGestureHandler>
        </PanGestureHandler>
    );
};

ZoomableImage.defaultProps = {
    imageStyle: {},
    source: { uri: "" }
};
/********************** End ZoomableImage Function *******************/
export default ZoomableImage;

Может кто-нибудь помочь мне?

...