/* eslint-disable react-native/no-inline-styles */ import React, { useRef, useEffect, forwardRef, ForwardRefRenderFunction, useImperativeHandle, ReactNode, } from 'react'; import { Animated, Easing, View, StyleSheet, StyleProp, ViewStyle, Text, } from 'react-native'; import { Size } from '../Icon/interface'; import { mergeProps } from '../../core/helpers'; import LottieView from 'lottie-react-native'; import { IconMABloading1, IconMAForward1, IconMAWloading1, } from '../../icons'; import styles from './styles/loading.style'; import { useLocale } from '../Locale/locale'; import { useTheme } from '../Theme/Theme'; import { useMemoizedFn } from 'ahooks'; const IconTypeEnum: { [key: string]: any } = { 'loading': IconMABloading1, 'loading-white': IconMAWloading1, 'loading-dot': IconMAForward1, 'loading-line': IconMAForward1, 'loading-o': IconMAForward1, 'loading-xt': IconMABloading1, 'transparent': IconMABloading1, }; const IconSizeEnum: { [key: string]: number } = { mini: Size.Size12, small: Size.Size16, middle: Size.Size32, large: Size.Size48, }; enum LoadingTypeEnum { 'loading' = 'loading', 'loading-white' = 'loading-white', 'loading-dot' = 'loading-dot', 'loading-line' = 'loading-line', 'loading-o' = 'loading-o', 'loading-xt' = 'loading-xt', 'transparent' = 'transparent', } export type LoadingType = | 'loading' | 'loading-white' | 'loading-dot' | 'loading-line' | 'loading-o' | 'loading-xt' | 'transparent'; export type LoadingType2 = | 'dot' | 'circle' | 'goldCoin' | 'whiteCoin' | 'default'; export interface LoadingProps { /** * name="loading-xt"展示预设Lottie动画,否则展示自定义动画 * @default 'loading-xt' | 'loading-white' | 'loading-dot' | 'loading-line' | 'loading-o' | 'loading-xt'; * */ name?: LoadingType; /** 要填充的颜色,目前只针对单色svg生效 */ fill?: string; /** * icon宽度和高度
枚举值Size或者传入number类型或者枚举值控制 * @default Size.Size20 * */ size?: Size | number | 'mini' | 'small' | 'middle' | 'large'; /** * 动画宽度 */ width?: number; /** * 动画高度 */ height?: number; /** loading icon父容器自定义的样式属性 */ style?: StyleProp; /** 文案显示隐藏,默认不显示tip */ tipDisable?: Boolean; /** 有子元素时,是否显示loading,默认显示 * @default true */ loading?: boolean; /** * 提示内容 */ tip?: ReactNode; /** * 子元素 */ children?: ReactNode; /** * 预设的Lottie动画类型 * @default 'goldCoin' */ loadingType?: LoadingType2; /** * 颜色覆盖,用来主题色替换 */ colorFilters?: { keypath: string; color: string }[]; } const LoadingSourceMap: Record = { circle: require('./consts/Circle.json'), dot: require('./consts/Dot.json'), goldCoin: require('./consts/GoldCoin.json'), whiteCoin: require('./consts/WhiteCoin.json'), default: require('./consts/LoadingAnimation.json'), }; const defaultProps: LoadingProps = { name: 'loading-xt', size: Size.Size20, tip: <>, tipDisable: false, loadingType: 'goldCoin', colorFilters: [], loading: true, }; export interface LoadingRef {} const Loading: ForwardRefRenderFunction = ( p, ref ) => { const { loadingText } = useLocale().Loading; const token = useTheme(); if (p.tipDisable) { switch (p.name) { case LoadingTypeEnum['loading-white']: defaultProps.tip = ( {loadingText} ); break; case LoadingTypeEnum['loading-xt']: defaultProps.tip = ( {loadingText} ); break; default: defaultProps.tip = ( {loadingText} ); break; } } const props: LoadingProps = mergeProps(defaultProps, p); const spinAnim = useRef(new Animated.Value(0)).current; const startSpin = () => { spinAnim.setValue(0); Animated.timing(spinAnim, { toValue: 1, duration: 1200, easing: Easing.linear, useNativeDriver: true, }).start(() => startSpin()); }; useEffect(() => { startSpin(); }, []); const spin = spinAnim.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'], }); // 预留向外界暴露的对象 useImperativeHandle(ref, () => ({})); const IconComponent = IconTypeEnum[props.name!]; const renderLoading = () => { const { size } = props; const iSize = ['mini', 'small', 'middle', 'large'].includes(size as string) ? IconSizeEnum[size as string] : (size as unknown as number); if (LoadingTypeEnum['loading-xt'] === props.name) { const colorFilters = props.colorFilters?.length ? props.colorFilters : [ { keypath: 'circle', color: token['--color-primary-6'], }, ]; return ( ); } return ( ); }; const dynamicStyle = props.tipDisable ? styles.wrapper : styles.wrapper_tip; const loadingComponent = useMemoizedFn((style = {}) => { return ( {props.name !== 'transparent' && ( <> {renderLoading()} {props.tipDisable && {props.tip}} )} ); }); if (!props.children) { return loadingComponent(); } const opacity = props.loading && props.name !== 'transparent' ? 0.5 : 1; return ( {props.children} {props.loading && loadingComponent(styles.loading_continer)} ); }; export default forwardRef(Loading);