动画视图的样式属性的Typescript定义

20

我有一个组件,其Props接口继承自React Native的ViewProps,即:


export interface Props extends ViewProps {
  // Custom props
}

自然地,这扩展了 style 属性。有一个注意点,我正在使用 Animated.View 并且样式如下:

style={{
  opacity: animationCharacter.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 1]
  }),
  transform: [
    {
      scale: animationCharacter.interpolate({
        inputRange: [0, 1],
        outputRange: [1.2, 1]
      })
    }
  ]
}}

我认为interpolate调用与ViewProps的样式类型不兼容,但是我没有可以扩展的AnimatedViewProps

这里有解决方案吗?还是我必须设置style: any


我认为我没有足够的信息提供答案,但我进行了一些研究,似乎调用插值会产生一个 Animated.Value。请参见:https://facebook.github.io/react-native/docs/animations。另请参阅:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/12202以整合此功能到核心库中。 - Nico Burns
7个回答

20
@types/react-native v0.61.9 开始,您可以使用 Animated.AnimatedProps 代替:

例如 style 属性:

interface Props {
  style?: Animated.AnimatedProps<StyleProp<ViewStyle>>,
}

或者获取所有属性:

export interface Props extends Animated.AnimatedProps<ViewProps> {
  // Custom props
}

4
对我来说,只使用 Animated.AnimatedProps<ViewStyle> 就解决了这个问题。 - Shyam
更新:答案中有一个错别字,应该是 Animated.AnimateProps<ViewProps> 而不是 Animated.AnimatedProps<ViewProps> - Kartikey
Animated.AnimatedProps<ViewProps>['style'] 对我起了作用。 - undefined

10
我已经创建了一种“类似于”的类型,可以将任何视图样式转换为可动画的样式。
type MaybeAnimated<T> = T | Animated.Value;
type AnimatedScalar = string | number;

type AnimatedStyles<T> = {
  [Key in keyof T]: T[Key] extends AnimatedScalar
    ? MaybeAnimated<T[Key]>
    : T[Key] extends Array<infer U>
    ? Array<AnimatedStyles<U>>
    : AnimatedStyles<T[Key]>
};

type ViewAnimatedStyles = AnimatedStyles<ViewStyle>;

const test: ViewAnimatedStyles = {
  transform: [
    {
      rotateY: new Animated.Value(2),
    }
  ]
}

您会获得自动建议并且动画效果也能够正常使用。
限制: Animated.Value 内部定义的只是一个空类,因此从技术上讲,任何值都可以匹配它。因此您可能会将不正确的值分配给它(例如,普通字符串而不是数字)。
了解更多关于推断和条件类型的信息: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html

很酷!谢谢。 - GollyJer
我猜这已经改变了,Animated.Value现在需要一个类型参数。 - gaurav5430

5

我不相信有内置的解决方案。查看React Native的类型定义,Animated命名空间甚至没有为动画组件指定类型,并且只将它们留为空的any类型

/**
 * Animated variants of the basic native views. Accepts Animated.Value for
 * props and style.
 */
export const View: any;
export const Image: any;
export const Text: any;
export const ScrollView: any;

即使是使用FlowType的React Native源代码也将props留给了普通对象类型

class AnimatedComponent extends React.Component<Object> {
  …
}

这可能是因为React Native有包装类来处理内部动画样式属性(甚至变换),具体而言,使得精确指定类型变得更加困难,因为存在抽象。我认为你最好使用any,因为自己创建类型会非常繁琐,并且收益很小。

我认为这就是跟踪问题的问题所在:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/12202 - ncuillery

5

// 导入{Animated}自"react-native"

interface ImageComponentProps {
  height: Animated.Value;
  width: Animated.Value;
  opacity: Animated.Value;
  uri: string;
}

这对我有用!

4

React-Native库已经为此提供了一些小助手:

import { Animated } from "react-native";

type AnimatedViewStyle = Animated.WithAnimatedValue<ViewStyle>;

0

对于我的使用情况,现有的答案都不起作用,所以我自己编写了一个似乎可以工作的解决方案:

import { RecursiveArray } from "lodash";
import {
    Animated,
    Falsy,
    ImageStyle,
    RegisteredStyle,
    TextStyle,
    ViewStyle,
} from "react-native";

export type AnimatedStyleProp<T extends Style> =
    | T
    | AnimatedStyle<T>
    | RegisteredStyle<T>
    | Falsy
    | RecursiveArray<
        | T
        | AnimatedStyle<T>
        | RegisteredStyle<T>
        | Falsy >;

type AnimatedStyle<T extends Style> =
    | T
    | Animated.Value
    | Animated.AnimatedInterpolation
    | Animated.WithAnimatedObject<T>
    | Animated.WithAnimatedArray<T>;

type Style = ViewStyle | TextStyle | ImageStyle;

AnimatedStyleProp<T>StyleProp<T>的定义完全相同,但增加了AnimatedStyle<T>

如果您不使用lodash,这是RecursiveArray<T>的定义(在@types/react-native中使用但未导出):

interface RecursiveArray<T> extends Array<
    | T
    | ReadonlyArray<T>
    | RecursiveArray<T>
> {}

0

对我来说,像这样的类型定义完全可以正常工作:

 const scaleValue = new Animated.Value( 0 );
 const cardScale: Animated.Mapping = scaleValue.interpolate( {
    inputRange: [0, 0.5, 1],
    outputRange: [1, .95, .9],
  } );
 const transformStyle = {transform: [{scale: cardScale}]};
<TouchableWithoutFeedback
  onPressIn={ () => {
    scaleValue.setValue( 0 );
    Animated.timing( scaleValue, {
      toValue: 1,
      duration: 60,
      easing: Easing.lenear
    } ).start();
   } }

   onPressOut={ () => {
    Animated.timing( scaleValue, {
      toValue: 0,
      duration: 550,
      easing: Easing.bounce,
    } ).start();
   } }
>
  <Animated.View style={ transformStyle }>
    {// some stuff}
  </Animated.View>
</TouchableWithoutFeedback>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接