在 React Native 的功能组件中使用 animateCamera

Using animateCamera in functional components in react native

总结

我正在使用 react-native-map 并尝试同时使用 animateCameraanimateMarkerToCoordinate 但根本无法为 animateCamera 设置动画。

到目前为止的工作部分

我在下面分享的 gif 中的“红色圆圈”应该是从一个位置移动到另一个位置的动画。 我已经利用 this 注释来移动带有动画的标记,将代码转换为功能组件并且它确实有效。 Moving marker gif

我的目标

我希望相机在标记之外也移动,这样红色圆圈应该始终感觉像是在 phone 屏幕的中心。当我按下下面的“动画”按钮时,所有这一切都会发生。

我已尝试对地图视图执行与对标记所做的相同的操作。

我创建了一个状态

const [mapRef, setMapRef] = useState(null);

并提供 <MapView>mapRef 状态之间的连接,使用以下以 ref

开头的行
 return (
            <View style={...}>
                <MapView
                    ref= {mapRef => {setMapRef(mapRef);}}
                    initialRegion = {
                        ...
                      }
                    ...
                 />

所以当按钮被按下时它进入这个函数并尝试工作 animateCamera 函数

function animateMarkerAndCamera() {

    let newCoordinate = {
        latitude: 32.601,
        longitude: 44.0172,
        latitudeDelta: 0.012,
        longitudeDelta: 0.012,
    };
    let Camera = {
        ...
    }
    if (myMarker) {
       
        myMarker.animateMarkerToCoordinate(newCoordinate, 4000);
        mapRef.animateCamera({Camera}, 4000)
    }

}

顺便说一句 Camera 按照 docs

中提到的方式进行了调整
 let Camera = {
        center: {
            latitude: newCoordinate.latitude,
            longitude: newCoordinate.longitude,
        },
        pitch: 2,
        heading: 20,
        zoom: 40
    }

所以我希望它能像标记的动画一样进行动画处理,但不起作用。

请告诉我我的错。

完整代码...

import React, {useState} from 'react'
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
import MapView, { AnimatedRegion, MarkerAnimated } from 'react-native-maps';

const PlayScreen = (props) => {

    const [myMarker, setMyMarker] = useState(null);
    const [mapRef, setMapRef] = useState(null);

    const [coordinate, setCoordinate] = useState(new AnimatedRegion({ 
        latitude: 32.5983,
        longitude: 44.0175,
        latitudeDelta: 0.012,
        longitudeDelta:0.012,
    }));
  
     function animateMarkerAndCamera() {
        
        let newCoordinate = {
            latitude: 32.601,
            longitude: 44.0172,
            latitudeDelta: 0.012,
            longitudeDelta: 0.012,
        };
        
        if(myMarker){
            myMarker.animateMarkerToCoordinate(newCoordinate,4000);
            mapRef.animateCamera(newCoordinate, 4000);
        }
        
    }
  
        return (
            <View style={styles.container}>
                <MapView
                    ref= {mapRef => {setMapRef(mapRef);}}
                    style={styles.map}
                    initialRegion={{
                        latitude: 32.5983,
                        longitude: 44.0175,
                        latitudeDelta: 0.012,
                        longitudeDelta: 0.012,
                    }}

                >
                    <MarkerAnimated 
                         ref={marker => {
                            setMyMarker(marker);
                        }} 
                        image={require('../../../Assets/Images/curlingStone.png')}
                        coordinate={coordinate}
                    />
                        
                </MapView>
                <View style={styles.buttonContainer}>
                    <TouchableOpacity
                        onPress={() => animateMarkerAndCamera()}
                        style={[styles.bubble, styles.button]}
                    >
                        <Text>Animate</Text>
                    </TouchableOpacity>
                </View>
            </View>
        );

}

const styles = StyleSheet.create({
    container: {
        ...StyleSheet.absoluteFillObject,
        justifyContent: 'flex-end',
        alignItems: 'center',
    },
    map: {
        ...StyleSheet.absoluteFillObject,
    },
    bubble: {
        flex: 1,
        backgroundColor: 'rgba(255,255,255,0.7)',
        paddingHorizontal: 18,
        paddingVertical: 12,
        borderRadius: 20,
    },
    latlng: {
        width: 200,
        alignItems: 'stretch',
    },
    button: {
        width: 80,
        paddingHorizontal: 12,
        alignItems: 'center',
        marginHorizontal: 10,
    },
    buttonContainer: {
        flexDirection: 'row',
        marginVertical: 20,
        backgroundColor: 'transparent',
    },
});
export default PlayScreen

因此,正如我之前解释的那样,我尝试同时使用 animateCameraanimateMarkerToCoordinate,这样我的标记(红色圆圈)就好像始终位于中心,并且只有坐标似乎在变化。

经过一番研究,我发现 this and made mine similar to this code. Now I obtained what I wanted to achieve.Gif is here

我所做的更改已写为评论

代码如下

import {useState, useRef} from 'react'
import ... //same as before

const PlayScreen = (props) => {
    const markerLatitude=32.5983
    const markerLongitude=44.0175
    //changed from useState to useRef
    const mapRef = useRef (null);
    const [myMarker, setMyMarker] = useState(null);
    const [coordinate, setCoordinate] = useState(new AnimatedRegion({
        latitude: markerLatitude,
        longitude: markerLongitude,
        latitudeDelta: 0.012,
        longitudeDelta: 0.012,
    }));

    function animateMarkerAndCamera() {

        let newCoordinate = {
            latitude: 32.601,
            longitude: 44.0172,
            latitudeDelta: 0.012,
            longitudeDelta: 0.012,
        };
        //camera will position itself to these coordinates.
        const newCamera= {
            center: {
                latitude: 32.601,
                longitude: 44.0172,
            },
            pitch: 0,
            heading: 0,
            //zoom: 17  --Use it when required
        }
        
        
        if (myMarker) {
            myMarker.animateMarkerToCoordinate(newCoordinate, 4000);
            //camera type, `newCamera`, used inside animateCamera
            mapRef.current.animateCamera(newCamera, {duration: 4000})
        }
        

    }

    return (
        <View style={styles.container}>
            <MapView
                ref={ mapRef } //There is also change here
                style={styles.map}
                initialRegion={{
                    latitude: 32.5983,
                    longitude: 44.0175,
                    latitudeDelta: 0.012,
                    longitudeDelta: 0.012,
                }}
                //These are newly added
                pitchEnabled ={false}
                zoomEnabled ={false}
            >
                <MarkerAnimated
                    ref={marker => {
                        setMyMarker(marker);
                    }}
                    {/*any kind of image can be replaced here */}
                    image={require('../../../Assets/Images/curlingStone.png')}
                    coordinate={coordinate}
                    
                />

            </MapView>
            <View style={styles.buttonContainer}>
                <TouchableOpacity
                    onPress={() => animateMarkerAndCamera()}
                    style={[styles.bubble, styles.button]}
                >
                    <Text>Animate</Text>
                </TouchableOpacity>
            </View>
        </View>
    );

}
export default PlayScreen

const styles = StyleSheet.create({ ... //same as before