我使用MapView.Marker创建了一个地图视图和一些标记。我正在使用滚动视图在标记之间切换。开关工作正常,使当前标记居中。
我还在用户切换到当前标记时创建了一些动画。我为此使用了插值(不透明度和比例(。但是动画不起作用。我现在正在安卓上测试。这是我的代码:
const interpolations = this.state.markers.map((marker, index) => {
const inputRange = [
(index - 1) * CARD_WIDTH,
index * CARD_WIDTH,
((index + 1) * CARD_WIDTH),
];
const scale = this.animation.interpolate({
inputRange,
outputRange: [1, 2.5, 1],
extrapolate: "clamp",
});
const opacity = this.animation.interpolate({
inputRange,
outputRange: [0.35, 1, 0.35],
extrapolate: "clamp",
});
return { scale, opacity };
});
return (
<View style={styles.container}>
<MapView
ref={map => this.map = map}
initialRegion={this.state.region}
style={styles.container}
>
{this.state.markers.map((marker, index) => {
const scaleStyle = {
transform: [
{
scale: interpolations[index].scale,
},
],
};
const opacityStyle = {
opacity: interpolations[index].opacity,
};
return (
<MapView.Marker key={index} coordinate= {{latitude: marker.location.coordinates[0], longitude: marker.location.coordinates[1]}}>
<Animated.View style={[styles.markerWrap,opacityStyle]}>
<Animated.View style={[styles.ring, scaleStyle]} />
<View style={styles.marker} />
</Animated.View>
</MapView.Marker>
);
})}
</MapView>
markerWrap: {
alignItems: "center",
justifyContent: "center",
borderRadius: 17,
borderWidth: 2,
overflow: "hidden",
width: 24,
height: 24,
borderColor: "rgba(130,4,150, 0.5)",
backgroundColor: "rgba(130,4,150, 0.3)",
position: "absolute",
},
marker: {
borderRadius: 4,
borderWidth: 1,
width: 8,
height: 8,
backgroundColor: "rgba(130,4,150, 0.9)"
},
ring: {
width: 24,
height: 24,
},
请告知您的建议。
谢谢
这是我为<MapView.Marker />
制作的包装器
包装纸
import React, { useCallback, useRef, useEffect, ReactNode } from
'react';
import { Animated, ViewStyle, View } from 'react-native';
interface AnimatedMarkerProp {
size?: number;
children: ReactNode;
showAnimation?: boolean;
containerStyle?: ViewStyle | ViewStyle[];
animatedViewStyle?: ViewStyle | ViewStyle[];
childrenWrapperStyle?: ViewStyle | ViewStyle[];
}
/**
*
* @param size defines the height, width & borderRadius of each view. The container View will plus 20px (animation area).
* @param showAnimation start or stop the animation.
* @param containerStyle styles for container view. (1st)
* @param animatedViewStyle styles for the animated view. (2nd)
* @param childrenWrapperStyle styles for the animated view containing the children. (3rd)
* @returns An animated wrapper for markers.
*/
const PulseAnimation = ({
size,
showAnimation,
children,
containerStyle,
animatedViewStyle,
childrenWrapperStyle,
}: AnimatedMarkerProp) => {
const fadeAnimation = useRef(new Animated.Value(1)).current;
const pulseAnimation = useRef(new Animated.Value(1)).current;
const animationArea = 20;
const startAnimation = useCallback(() => {
Animated.parallel([
Animated.loop(
Animated.sequence([
Animated.timing(pulseAnimation, {
delay: 250,
toValue: showAnimation ? 1.5 : 1,
duration: 750,
useNativeDriver: false,
}),
Animated.timing(pulseAnimation, {
toValue: 1,
duration: 750,
useNativeDriver: false,
}),
Animated.timing(pulseAnimation, {
toValue: showAnimation ? 1.5 : 1,
duration: 250,
useNativeDriver: false,
}),
Animated.timing(fadeAnimation, {
toValue: 0,
duration: 1000,
useNativeDriver: false,
}),
])
),
]).start();
}, [fadeAnimation, pulseAnimation, showAnimation]);
const stopAnimation = useCallback(() => {
pulseAnimation.stopAnimation(() => {
pulseAnimation.setValue(1);
});
fadeAnimation.stopAnimation();
}, [fadeAnimation, pulseAnimation]);
useEffect(() => {
if (showAnimation) {
startAnimation();
} else {
stopAnimation();
}
}, [showAnimation, startAnimation, stopAnimation]);
return (
<View
style={[
!!size && {
height: size + animationArea,
width: size + animationArea,
borderRadius: (size + animationArea) / 2,
},
{
alignItems: 'center',
justifyContent: 'center',
},
containerStyle,
]}
>
<Animated.View
style={[
!!size && { height: size, width: size, borderRadius: size / 2 },
{
transform: [
{
scale: pulseAnimation,
},
],
backgroundColor: fadeAnimation.interpolate({
inputRange: [0, 1],
outputRange: [
'rgba(41, 182, 246, 0)',
'rgba(41, 182, 246, 0.30)',
],
}),
alignItems: 'center',
justifyContent: 'center',
},
animatedViewStyle,
]}
>
<Animated.View
style={[
!!size && { height: size, width: size, borderRadius: size / 2 },
{
transform: [
{
scale: pulseAnimation.interpolate({
inputRange: [1, 1.5],
outputRange: [1, 0.67],
extrapolate: 'clamp',
}),
},
],
},
childrenWrapperStyle,
]}
>
{children}
</Animated.View>
</Animated.View>
</View>
);
};
export default PulseAnimation;
用法
<Marker
id="userMarker"
anchor={anchor}
coordinate={{ latitude, longitude }}
zIndex={105}
onPress={onPressMarker}
hitSlop={hitSlop}
>
<PulseAnimation
size={32}
showAnimation={userMarkerSelected}
animatedViewStyle={[styles.pinShadow]}
childrenWrapperStyle={styles.pinBg}
>
<Animated.View
style={{
transform: [
{
rotate: mapIsRotating ? '0deg' : anglePlusMap,
},
],
}}
>
<UserPointerIcon />
</Animated.View>
</PulseAnimation>
</Marker>
在这种情况下,还必须对子组件进行动画处理。
动画
这是一个已知的问题。以下是 3 年前在官方文档中添加的——
问题:由于 android 需要将其标记视图呈现为位图,因此动画 API 可能与标记视图不兼容。不确定这是否可以解决。
你可以在这里找到它-https://github.com/react-native-community/react-native-maps, 在"将地图视图与动画 API 结合使用"部分下。