license import React from 'react' ; import { Animated , Easing , LayoutChangeEvent , Platform , ViewProps , ViewStyle , } from 'react-native' ; import { RTLService } from '../../devsupport' ; export interface TabIndicatorProps extends ViewProps { positions : number ; selectedPosition ? : number ; } export type TabIndicatorElement = React . ReactElement < TabIndicatorProps > ; export class TabIndicator extends React . Component < TabIndicatorProps > { static defaultProps : Partial < TabIndicatorProps > = { selectedPosition : 0 , } ; private indicatorWidth : number = 0 ; private contentOffset : Animated . Value = new Animated . Value ( 0 ) ; public componentDidMount ( ) { this . contentOffset . addListener ( this . onContentOffsetAnimationStateChanged ) ; } public componentDidUpdate ( ) { const { selectedPosition : index } = this . props ; this . scrollToIndex ( { index , animated : true , } ) ; } public componentWillUnmount ( ) { this . contentOffset . removeAllListeners ( ) ; } param params public scrollToIndex ( params ) { const { index , ... rest } = params ; const offset = this . indicatorWidth * index ; this . scrollToOffset ( { offset , ... rest } ) ; } param params public scrollToOffset ( params ) { this . createOffsetAnimation ( params ) . start ( this . onContentOffsetAnimationStateEnd ) ; } private onContentOffsetAnimationStateChanged = ( state ) => { } ; private onContentOffsetAnimationStateEnd = ( result ) => { } ; private createOffsetAnimation = ( params ) : Animated . CompositeAnimation => { return Animated . timing ( this . contentOffset , { toValue : RTLService . select ( params . offset , - params . offset ) , duration : 200 , easing : Easing . linear , useNativeDriver : Platform . OS !== 'web' , } ) ; } ; private onLayout = ( event ) => { this . indicatorWidth = event . nativeEvent . layout . width ; this . scrollToOffset ( { offset : this . indicatorWidth * this . props . selectedPosition , animated : false , } ) ; } ; private getComponentStyle = ( ) : ViewStyle => { const widthPercent = 100 / this . props . positions ; return { width : `${ widthPercent }%` , transform : [ { translateX : this . contentOffset } ] , } ; } ; public render ( ) { const { style , ... viewProps } = this . props ; const evaStyle = this . getComponentStyle ( ) ; return ( < Animated . View { ... viewProps } style = { [ style , evaStyle ] } onLayout = { this . onLayout } / > ) ; } }