Анимация ширины ‹Rect /› в react-native-svg

У меня есть простая интерполяция анимации для элемента <Rect />, однако я не вижу изменений в моем пользовательском интерфейсе, как будто ширина остается равной 0.

Я вручную добавил свое конечное значение к компоненту как width={149.12}, и он отобразил его правильно, поэтому теперь я немного смущен тем, почему он не получает такое же значение из анимации?

[email protected]

[email protected]

Ориентация на iOS 12

Вот полная реализация, по сути, полоса маны и здоровья, которая принимает текущее значение и общее значение, то есть 50 и 100 должны отображать половину ширины прямоугольника. (В примере используется машинописный текст, но при необходимости ответ может быть в виде простого js)

import * as React from 'react'
import { Animated } from 'react-native'
import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg'
import { deviceWidth } from '../services/Device'

const barWidth = deviceWidth * 0.3454
const barHeight = barWidth * 0.093
const AnimatedRect = Animated.createAnimatedComponent(Rect)

/**
 * Types
 */
export interface IProps {
  variant: 'MANA' | 'HEALTH'
  currentValue: number
  totalValue: number
}

export interface IState {
  width: Animated.Value
}

/**
 * Component
 */
class HealthManaBar extends React.Component<IProps, IState> {
  state = {
    width: new Animated.Value(0)
  }

  componentDidMount() {
    const { currentValue, totalValue } = this.props
    this.animate(currentValue, totalValue)
  }

  componentDidUpdate({ currentValue, totalValue }: IProps) {
    this.animate(currentValue, totalValue)
  }

  animate = (current: number, total: number) =>
    Animated.timing(this.state.width, {
      toValue: current !== 0 ? current / total : 0,
      duration: 400
    }).start()

  render() {
    const { variant } = this.props
    const { width } = this.state

    return (
      <Svg width={barWidth} height={barHeight}>
        <Defs>
          <LinearGradient
            id={`HeathManaBar-gradient-${variant}`}
            x1="0"
            y1="0"
            x2="0"
            y2={barHeight}
          >
            <Stop
              offset="0"
              stopColor={variant === 'HEALTH' ? '#EC561B' : '#00ACE1'}
              stopOpacity="1"
            />
            <Stop
              offset="0.5"
              stopColor={variant === 'HEALTH' ? '#8D1B00' : '#003FAA'}
              stopOpacity="1"
            />
            <Stop
              offset="1"
              stopColor={variant === 'HEALTH' ? '#9F3606' : '#007C97'}
              stopOpacity="1"
            />
          </LinearGradient>
        </Defs>
        <AnimatedRect
          x="0"
          y="0"
          rx="3"
          ry="3"
          width={width.interpolate({
            inputRange: [0, 1],
            outputRange: [0, barWidth]
          })}
          height={barHeight}
          fill={`url(#HeathManaBar-gradient-${variant})`}
        />
      </Svg>
    )
  }
}

export default HealthManaBar

Связанная библиотека: https://github.com/react-native-community/react-native-svg


person Ilja    schedule 07.10.2018    source источник
comment
Какое значение имеет width, когда вы распечатываете его в render и в функции componentDidUpdate?   -  person krjw    schedule 11.10.2018


Ответы (2)


Первоначально это было невозможно с react-native-svg, но решение в настоящее время находится в стадии разработки, и вы можете следить за прогрессом здесь.

https://github.com/react-native-community/react-native-svg/issues/803

person Ilja    schedule 12.10.2018

Попробуйте использовать lottie-react-native

https://github.com/react-community/lottie-react-native

На мой взгляд, это лучший инструмент для работы с анимацией в React Native.

person Florin Dobre    schedule 15.10.2018