I have an animation for a bottom bar that goes under the tab text, the animation is working fine in android but not in ios. I am using react-native-reanimated. Any help would be appreciated. Thanks
const MyTabBar = React.memo((props) => {
const {state, descriptors, navigation, position, setEnableSwipe, swipeEnabled, layout, theme, auth, ui} = props;
if (state.routes[state.index].state && state.routes[state.index].state.index !== 0) {
if (swipeEnabled === true) {
setEnableSwipe(false)
}
return null;
}
else {
if (swipeEnabled === false) {
setEnableSwipe(true);
}
var tabWidth = (layout.width - 50)/3
const left = Animated.interpolate(position, {
inputRange: [0, 1, 2],
outputRange: [(tabWidth - 50)/2 , tabWidth + (tabWidth - 50)/2, 2*tabWidth + (tabWidth - 50)/2]
});
const length = Animated.interpolate(position, {
inputRange: [0, 0.5, 1, 1.5, 2],
outputRange: [0.3, 1, 0.3, 1, 0.3],
})
return (
<View style={{ flexDirection: 'row', backgroundColor: Platform.OS === 'ios' && ui.showing_modal ? 'white' : 'white', alignItems: 'center' }}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
const inputRange = state.routes.map((_, i) => i);
const opacity = Animated.interpolate(position, {
inputRange,
outputRange: inputRange.map(i => (i === index ? 1 : 0.4)),
});
return (
<TouchableOpacity
accessibilityRole="button"
accessibilityStates={isFocused ? ['selected'] : []}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
style={{flex: 1}}
>
<Animated.Text style={{
opacity,
fontWeight: index === state.index ? '600' : 'normal',
fontSize: index === state.index ? 19 : 17,
textAlign: 'center',
}}>
{label}
</Animated.Text>
</TouchableOpacity>
);
})}
{Platform.OS === 'ios' && false ?
<View/> : <Animated.View
style={{
backgroundColor: theme.primaryColor,
translateX: left,
scaleX: length,
height: 4,
width: 50,
position: 'absolute',
bottom: 0,
borderRadius: 10,
}} />}
<TouchableOpacity
style={{minWidth: 50, maxWidth: 50}}
onPress={() => {
switch (state.index) {
case 0:
navigation.navigate('AddSchedule');
break;
case 1:
navigation.navigate('AddScene');
break;
case 2:
if (auth.accesstoken) {
navigation.navigate('NewGeoscene');
} else {
ReactNativeHapticFeedback.trigger('notificationWarning', {
ignoreAndroidSystemSettings: true,
enableVibrateFallback: true
})
}
break;
default:
//
}
}}
>
<Text style={{fontSize: 36, color: theme.primaryColor}}> + </Text>
</TouchableOpacity>
</View>
);
}
})
this is my code, the line Animated.View doesn't animate in iOS so I am not rendering it there, but i want it working.
Android Expected behaviour (android)
iOS: behaviour in iOS
I have an observation from my own code which may or may not be applicable here. This observation is only true if both of the transform
properties are using react-native-reanimated animation values. Your code appears to match this scenario.
In iOS only, I must place the scale
property before the translateX
property in my transform
object. If I put the translateX
property before the scale
property then the translateX
property is impeded.
I have no explanation for this, but I have tested it with scaleX
since that's what you are using and the same is true.
So for clarity, the following works:
<Animated.Value
style={[{
transform: [{
scale: animationValue1,
translateX: animationValue2,
}]
}]}
/>
..while in the next, the scale
works but the translateX
does not:
<Animated.Value
style={[{
transform: [{
translateX: animationValue2,
scale: animationValue1,
}]
}]}
/>
You'll notice my syntax is a little different from yours too. As far as I'm aware you shouldn't be putting the translateX
and scaleX
properties in the style
object without being wrapped in a transform
property, as above. Perhaps reanimated's View
works a bit differently to react native's native one.. If it's still not working after you try reordering the properties then give this some thought too.
See the documentation here: https://reactnative.dev/docs/transforms#transform
It's a bit confused because the API describes transform
as a function, but the example at the top of the page shows it used as I have done above.