import React from 'react'; import { NativeSyntheticEvent, StyleProp, View, ViewStyle, processColor, } from 'react-native'; import { parsePossibleSources } from './utils'; import type { LottieViewProps } from '../types'; import NativeLottieAnimationView, { Commands, } from '../specs/LottieAnimationViewNativeComponent'; type Props = LottieViewProps & { containerStyle?: StyleProp }; const defaultProps: Props = { source: undefined, progress: 0, speed: 1, loop: true, autoPlay: false, enableMergePathsAndroidForKitKatAndAbove: false, enableSafeModeAndroid: false, cacheComposition: true, useNativeLooping: false, resizeMode: 'contain', colorFilters: [], textFiltersAndroid: [], textFiltersIOS: [], }; export class LottieView extends React.PureComponent { static defaultProps = defaultProps; private lottieAnimationViewRef: | React.ElementRef | undefined; constructor(props: Props) { super(props); this.play = this.play.bind(this); this.reset = this.reset.bind(this); this.pause = this.pause.bind(this); this.resume = this.resume.bind(this); this.onAnimationFinish = this.onAnimationFinish.bind(this); this.captureRef = this.captureRef.bind(this); if (props.hover != undefined && __DEV__) { console.warn('lottie-react-native: hover is only supported on web'); } } play(startFrame?: number, endFrame?: number): void { Commands.play( this.lottieAnimationViewRef, startFrame ?? -1, endFrame ?? -1, ); } reset() { Commands.reset(this.lottieAnimationViewRef); } pause() { Commands.pause(this.lottieAnimationViewRef); } resume() { Commands.resume(this.lottieAnimationViewRef); } private onAnimationFinish = ( evt: NativeSyntheticEvent<{ isCancelled: boolean }>, ) => { this.props.onAnimationFinish?.(evt.nativeEvent.isCancelled); }; private onAnimationFailure = ( evt: NativeSyntheticEvent<{ error: string }>, ) => { this.props.onAnimationFailure?.(evt.nativeEvent.error); }; private onAnimationLoaded = () => { this.props.onAnimationLoaded?.(); }; private captureRef(ref: React.ElementRef) { if (ref === null) { return; } this.lottieAnimationViewRef = ref; if (this.props.autoPlay === true) { this.play(); } } private renderLottieView() { const { style, source, autoPlay, duration, textFiltersAndroid, textFiltersIOS, resizeMode, containerStyle, ...rest } = this.props; const sources = parsePossibleSources(source); const speed = duration && sources.sourceJson && (source as any).fr ? Math.round( (((source as any).op / (source as any).fr) * 1000) / duration, ) : this.props.speed; const colorFilters = this.props.colorFilters?.map((colorFilter) => ({ ...colorFilter, color: processColor(colorFilter.color), })); return ( ); } render(): React.ReactNode { const { source, containerStyle } = this.props; if (source == null) { console.warn( 'LottieView needs `source` parameter, provided value for source:', source, ); return null; } if (containerStyle) { return ( {this.renderLottieView()} ); } return this.renderLottieView(); } }