React-native-реанимированная анимация не работает на ios, работает в android

#ios #react-native #animation #react-native-ios #react-native-reanimated

#iOS #реагировать-родной #Анимация #react-native-ios #react-native-реанимированная #react-native

Вопрос:

У меня есть анимация для нижней панели, которая находится под текстом вкладки, анимация отлично работает в Android, но не в ios. Я использую react-native-reanimated. Любая помощь будет признательна. Спасибо

 const MyTabBar = React.memo((props) => {


const {state, descriptors, navigation, position, setEnableSwipe, swipeEnabled, layout, theme, auth, ui} = props;
  if (state.routes[state.index].state amp;amp; 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' amp;amp; 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 amp;amp; !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' amp;amp; 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>
    );
  }
})
  

это мой код, строка анимирована.View не анимируется в iOS, поэтому я не рендерю его там, но я хочу, чтобы он работал.

Ожидаемое поведение Android (android)

iOS: поведение в iOS

Ответ №1:

У меня есть наблюдение из моего собственного кода, которое может быть или не быть применимо здесь. Это наблюдение справедливо только в том случае, если оба transform свойства используют значения react-native-reanimated animation. Ваш код, похоже, соответствует этому сценарию.

Только в iOS я должен поместить scale свойство перед translateX свойством в моем transform объекте. Если я помещу translateX свойство перед scale свойством, то translateX свойство будет заблокировано.

У меня нет объяснения этому, но я протестировал его, scaleX поскольку это то, что вы используете, и то же самое верно.

Итак, для ясности, работает следующее:

 <Animated.Value
  style={[{
    transform: [{
      scale: animationValue1,
      translateX: animationValue2,
    }]
  }]}
/>
  

.. в то время как в следующем scale работает, но translateX не работает:

 <Animated.Value
  style={[{
    transform: [{
      translateX: animationValue2,
      scale: animationValue1,
    }]
  }]}
/>
  

Вы заметите, что мой синтаксис тоже немного отличается от вашего. Насколько я знаю, вы не должны помещать свойства translateX and scaleX в style объект, не будучи обернутыми в transform свойство, как указано выше. Возможно, reanimated View работает немного иначе, чем родной для react native.. Если она все еще не работает после того, как вы попытаетесь изменить порядок свойств, подумайте и об этом.

Смотрите документацию здесь: https://reactnative.dev/docs/transforms#transform

Это немного запутано, потому что API описывается transform как функция, но пример в верхней части страницы показывает, что он используется так, как я сделал выше.

Комментарии:

1. Спасибо. Когда я переместил translateX в transform, это устранило проблему. Я не перемещал масштаб, чтобы преобразовать его, он все равно работал. И, таким образом, не сталкивался с проблемой, вызванной заказом. Я переместу масштаб внутрь, спасибо за ввод