├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── example.gif ├── example ├── App.js ├── app.json ├── assets │ ├── favicon.png │ ├── icon.png │ └── splash.png ├── babel.config.js ├── package.json ├── src │ └── ShimmerPlaceholder.js └── yarn.lock ├── facebook-load-data.gif ├── index.d.ts ├── lib └── ShimmerPlaceholder.js ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifacts 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | /ios/Pods/ 60 | 61 | # Expo 62 | .expo/* 63 | web-build/ 64 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | example/ 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | example.gif 55 | facebook-load-data.gif 56 | LICENSE 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 tomzaku 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | React Native Shimmer Placeholder 4 |

5 |

6 | 7 | 8 | 9 |

10 |
11 | Placeholder for both IOS and Android 12 |
13 | 14 |

15 | 16 |

17 | 20 | 21 | ## Get Started 22 | ![install size](https://packagephobia.now.sh/badge?p=react-native-shimmer-placeholder@1.0.29) 23 | 24 | ### Installation 25 | 26 | `npm i react-native-shimmer-placeholder --save` 27 | 28 | or 29 | 30 | `yarn add react-native-shimmer-placeholder` 31 | 32 | 33 | ### Usage 34 | 35 | #### Simple 36 | 37 | For `expo` 38 | ``` jsx 39 | import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder' 40 | import { LinearGradient } from 'expo-linear-gradient'; 41 | 42 | const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient) 43 | 44 | 45 | 46 | 47 | Wow, awesome here. 48 | 49 | 50 | ``` 51 | 52 | or 53 | 54 | ``` jsx 55 | import ShimmerPlaceHolder from 'react-native-shimmer-placeholder' 56 | import { LinearGradient } from 'expo-linear-gradient'; 57 | 58 | 59 | 60 | 61 | 62 | Wow, awesome here. 63 | 64 | 65 | ``` 66 | 67 | For `react-native-linear-gradient` 68 | ``` jsx 69 | import LinearGradient from 'react-native-linear-gradient'; 70 | import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder' 71 | 72 | const ShimmerPlaceHolder = createShimmerPlaceholder(LinearGradient) 73 | 74 | ... 75 | 76 | 77 | ``` 78 | or 79 | ```jsx 80 | import LinearGradient from 'react-native-linear-gradient'; 81 | import ShimmerPlaceHolder from 'react-native-shimmer-placeholder' 82 | 83 | ... 84 | 85 | 88 | ``` 89 | 90 | #### Connect more components 91 | 92 |

93 | 94 |

95 | 96 | ```jsx 97 | import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder' 98 | import LinearGradient from 'react-native-linear-gradient'; 99 | 100 | const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient) 101 | const FacebookContent = () => { 102 | 103 | // Handle animation 104 | const avatarRef = React.createRef() 105 | const firstLineRef = React.createRef() 106 | const secondLineRef = React.createRef() 107 | const thirdLineRef = React.createRef() 108 | 109 | React.useEffect(() => { 110 | const facebookAnimated = Animated.stagger( 111 | 400, 112 | [ 113 | avatarRef.current.getAnimated(), 114 | Animated.parallel([ 115 | firstLineRef.current.getAnimated(), 116 | secondLineRef.current.getAnimated(), 117 | thirdLineRef.current.getAnimated() 118 | ]) 119 | ] 120 | ); 121 | Animated.loop(facebookAnimated).start(); 122 | }, []) 123 | 124 | return ( 125 | 126 | 127 | 131 | 132 | 136 | 140 | 144 | 145 | 146 | 147 | ) 148 | } 149 | ``` 150 | 151 | More Detail see [this](https://github.com/tomzaku/react-native-shimmer-placeholder/blob/master/example/App.js) 152 | 153 | ### Props 154 | 155 | | Prop | Description | Type | Default | 156 | | ---------------------------- | ------------------------------------------------------------------------------------------------------ | --------- | ------------------------------------------------- | 157 | | **`LinearGradient`** | Linear Gradient components ('react-native-linear-gradient' or 'expo-linear-gradient') | Component | undefined | 158 | | **`visible`** | Visible child components | boolean | false | 159 | | **`style`** | Container Style | Style | `{backgroundColor: '#ebebeb',overflow: 'hidden'}` | 160 | | **`shimmerStyle`** | Shimmer Style only | Style | {} | 161 | | **`contentStyle`** | Content Style when visible | Style | {} | 162 | | **`location`** | Locations of shimmer | number[] | *[0.3, 0.5, 0.7]* | 163 | | **`width`** | Width of row | number | 200 | 164 | | **`duration`** | Duration of shimmer over a row | number | 1000 | 165 | | **`height`** | Height of row | number | 15 | 166 | | **`shimmerWidthPercent`** | Percent of shimmer width | number | 1.0 | 167 | | **`isReversed`** | Reverse direction of animation | boolean | `false` | 168 | | **`stopAutoRun`** | Stop running shimmer animation at beginning | boolean | `false` | 169 | | **`isInteraction`** | Defines whether or not the shimmer animation creates an interaction handle on the `InteractionManager` | boolean | `true` | 170 | | **`shimmerColors`** | Colors of the shimmer. | string[] | *['#ebebeb', '#c5c5c5', '#ebebeb']* | 171 | | **`containerProps`** | Props passed to the outermost View | ViewProps | undefined | 172 | | **`shimmerContainerProps`** | Props passed to the View which contains the loading animation | ViewProps | undefined | 173 | | **`childrenContainerProps`** | Props passed to the View which contains the children | ViewProps | undefined | 174 | 175 | ### Methods 176 | | Method | Description | Type | 177 | | ----------------- | --------------------------- | -------- | 178 | | **`getAnimated`** | get Animated of Placeholder | Animated | 179 | 180 | ### Helpers 181 | 182 | `createShimmerPlaceholder` 183 | 184 | ``` 185 | /** 186 | * To create ShimmerPlaceholder by Linear Gradient. Only useful when you use 3rd party, 187 | * For example: react-native-linear-gradient 188 | * @param {Linear Gradient Component} LinearGradient - 'expo-linear-gradient' by default 189 | * 190 | * @example 191 | * 192 | * import LinearGradient from 'react-native-linear-gradient'; 193 | * import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder' 194 | * 195 | * const ShimmerPlaceHolder = createShimmerPlaceholder(LinearGradient) 196 | * 197 | * ... 198 | * 199 | * 200 | */ 201 | ``` 202 | 203 | ### Contribute 204 | 205 | Welcome help me to build this awesome lib. 206 | 207 | ### License 208 | 209 | [MIT](https://github.com/tomzaku/react-native-shimmer-placeholder/blob/master/LICENSE) 210 | -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomzaku/react-native-shimmer-placeholder/578a2ec95dc84cf22842291b145d4240aa490c66/example.gif -------------------------------------------------------------------------------- /example/App.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import React, { PureComponent, Component } from 'react'; 4 | import { View, Text, StyleSheet, Animated, Image, ScrollView, FlatList } from 'react-native'; 5 | import { LinearGradient } from 'expo-linear-gradient'; 6 | import ShimmerPlaceholder from './src/ShimmerPlaceholder' 7 | 8 | const FacebookContent = ({ isReversed, shimmerColors, hasData, hasBorder, randomWidth }) => { 9 | // Handle visible 10 | const [visible, setVisible] = React.useState(false) 11 | const [avatarVisible, setAvatarVisible] = React.useState(false) 12 | React.useEffect(() => { 13 | setTimeout(() => { 14 | hasData && setVisible(true) 15 | }, 2000) 16 | }, []) 17 | 18 | // Handle animation 19 | const avatarRef = React.createRef() 20 | const firstLineRef = React.createRef() 21 | const secondLineRef = React.createRef() 22 | const thirdLineRef = React.createRef() 23 | 24 | React.useEffect(() => { 25 | const facebookAnimated = Animated.stagger(400, [avatarRef.current.getAnimated(), Animated.parallel([ 26 | firstLineRef.current.getAnimated(), 27 | secondLineRef.current.getAnimated(), 28 | thirdLineRef.current.getAnimated() 29 | ])]) 30 | Animated.loop(facebookAnimated).start(); 31 | }, []) 32 | 33 | return ( 34 | 35 | 36 | 46 | {hasData && setAvatarVisible(true)} 50 | />} 51 | 52 | 53 | 63 | 64 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy 65 | 66 | 67 | 76 | 85 | 86 | 87 | 88 | ) 89 | } 90 | 91 | 92 | 93 | export default () => { 94 | const [visible, setVisible] = React.useState(false) 95 | const [avatarVisible, setAvatarVisible] = React.useState(false) 96 | React.useEffect(() => { 97 | setTimeout(() => { 98 | setVisible(true) 99 | }, 2000) 100 | }, []) 101 | return ( 102 | 103 | React Native Shimmer Placeholder 104 | Simple 105 | 108 | Avatar 109 | 115 | setAvatarVisible(true)} 119 | /> 120 | 121 | Load text data 122 | 127 | 128 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy 129 | 130 | 131 | 136 | 141 | 142 | Facebook 143 | 144 | Facebook - color 145 | 146 | Facebook - load data 147 | 148 | Facebook - Reverse 149 | 150 | 151 | 152 | ) 153 | } 154 | 155 | const styles = StyleSheet.create({ 156 | container: { 157 | flex: 1, 158 | padding: 16, 159 | marginTop: 60, 160 | 161 | }, 162 | title: { 163 | fontSize: 20, 164 | marginBottom: 12, 165 | fontWeight: "600", 166 | textAlign: "center", 167 | }, 168 | sessionTitle: { 169 | fontSize: 16, 170 | marginTop: 20, 171 | marginBottom: 6, 172 | fontWeight: "600" 173 | } 174 | }); 175 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "expoShimmer", 4 | "slug": "expoShimmer", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "splash": { 9 | "image": "./assets/splash.png", 10 | "resizeMode": "contain", 11 | "backgroundColor": "#ffffff" 12 | }, 13 | "updates": { 14 | "fallbackToCacheTimeout": 0 15 | }, 16 | "assetBundlePatterns": [ 17 | "**/*" 18 | ], 19 | "ios": { 20 | "supportsTablet": true 21 | }, 22 | "web": { 23 | "favicon": "./assets/favicon.png" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomzaku/react-native-shimmer-placeholder/578a2ec95dc84cf22842291b145d4240aa490c66/example/assets/favicon.png -------------------------------------------------------------------------------- /example/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomzaku/react-native-shimmer-placeholder/578a2ec95dc84cf22842291b145d4240aa490c66/example/assets/icon.png -------------------------------------------------------------------------------- /example/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomzaku/react-native-shimmer-placeholder/578a2ec95dc84cf22842291b145d4240aa490c66/example/assets/splash.png -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "web": "expo start --web", 8 | "eject": "expo eject" 9 | }, 10 | "dependencies": { 11 | "expo": "~38.0.8", 12 | "expo-linear-gradient": "~8.2.1", 13 | "expo-status-bar": "^1.0.2", 14 | "react": "~16.11.0", 15 | "react-dom": "~16.11.0", 16 | "react-native": "https://github.com/expo/react-native/archive/sdk-38.0.2.tar.gz", 17 | "react-native-web": "~0.11.7" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.8.6", 21 | "babel-preset-expo": "~8.1.0" 22 | }, 23 | "private": true 24 | } 25 | -------------------------------------------------------------------------------- /example/src/ShimmerPlaceholder.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from "react"; 2 | import { Animated, Platform, StyleSheet, View } from "react-native"; 3 | 4 | const getOutputRange = (width, isReversed) => isReversed ? [width, -width] : [-width, width] 5 | 6 | class ShimmerPlaceholder extends PureComponent { 7 | state = { 8 | beginShimmerPosition: new Animated.Value(-1) 9 | } 10 | getAnimated = () => { 11 | const { delay, duration, isInteraction } = this.props 12 | return Animated.loop(Animated.timing(this.state.beginShimmerPosition, { 13 | toValue: 1, 14 | delay, 15 | duration, 16 | useNativeDriver: true, 17 | isInteraction 18 | })) 19 | } 20 | animatedValue = this.getAnimated() 21 | 22 | render() { 23 | return ( 24 | 25 | ) 26 | } 27 | } 28 | 29 | ShimmerPlaceholder.defaultProps = { 30 | delay: 0, 31 | duration: 1000, 32 | isInteraction: true 33 | } 34 | 35 | const BasedShimmerPlaceholder = (props) => { 36 | const { 37 | width = 200, 38 | height = 15, 39 | duration = 1000, 40 | delay = 0, 41 | shimmerColors = ["#ebebeb", "#c5c5c5", "#ebebeb"], 42 | isReversed = false, 43 | stopAutoRun = false, 44 | visible, 45 | location = [0.3, 0.5, 0.7], 46 | style, 47 | contentStyle, 48 | shimmerStyle, 49 | isInteraction = true, 50 | LinearGradient = global.Expo 51 | ? global.Expo.LinearGradient 52 | : View, 53 | children, 54 | animatedValue, 55 | beginShimmerPosition, 56 | shimmerWidthPercent = 1, 57 | } = props 58 | 59 | const linearTranslate = beginShimmerPosition.interpolate({ 60 | inputRange: [-1, 1], 61 | outputRange: getOutputRange(width, isReversed) 62 | }); 63 | 64 | React.useEffect(() => { 65 | if (!stopAutoRun) { 66 | animatedValue.start() 67 | } 68 | return () => { 69 | animatedValue.stop() 70 | } 71 | }, [stopAutoRun]) 72 | 73 | React.useEffect(() => { 74 | if (visible) { 75 | animatedValue.stop() 76 | } 77 | if (!visible && !stopAutoRun) { 78 | animatedValue.start() 79 | } 80 | }, [visible, stopAutoRun]) 81 | 82 | return ( 83 | 86 | {/* Force render children to restrict rendering twice */} 87 | {children} 88 | { 89 | !visible && ( 90 | 91 | 94 | 107 | 108 | 109 | 110 | ) 111 | } 112 | 113 | ) 114 | } 115 | 116 | const styles = StyleSheet.create({ 117 | container: { 118 | overflow: "hidden" 119 | }, 120 | 121 | }); 122 | 123 | /** 124 | * To create ShimmerPlaceholder by Linear Gradient. Only useful when you use 3rd party, 125 | * For example: react-native-linear-gradient 126 | * @param {Linear Gradient Component} LinearGradient - 'expo-linear-gradient' by default 127 | * 128 | * @example 129 | * 130 | * import LinearGradient from 'react-native-linear-gradient'; 131 | * import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder' 132 | * 133 | * const ShimmerPlaceHolder = createShimmerPlaceholder(LinearGradient) 134 | * 135 | * ... 136 | * 137 | * 138 | */ 139 | export const createShimmerPlaceholder = (LinearGradient = global.Expo 140 | ? global.Expo.LinearGradient 141 | : View) => React.forwardRef((props, ref) => ) 142 | 143 | export default ShimmerPlaceholder -------------------------------------------------------------------------------- /facebook-load-data.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomzaku/react-native-shimmer-placeholder/578a2ec95dc84cf22842291b145d4240aa490c66/facebook-load-data.gif -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-native-shimmer-placeholder' { 2 | 3 | import * as React from 'react'; 4 | import { Animated, ViewProps } from 'react-native'; 5 | 6 | export interface ShimmerPlaceholderProps { 7 | width?: number | string; 8 | height?: number | string; 9 | shimmerWidthPercent?: number; 10 | duration?: number; 11 | delay?: number; 12 | shimmerColors?: string[]; 13 | location?: number[]; 14 | isReversed?: boolean; 15 | stopAutoRun?: boolean; 16 | visible?: boolean; 17 | children?: any; 18 | style?: any; 19 | shimmerStyle?: any; 20 | contentStyle?: any; 21 | isInteraction?: boolean; 22 | LinearGradient?: React.ComponentClass; 23 | containerProps?: ViewProps 24 | shimmerContainerProps?: ViewProps 25 | childrenContainerProps?: ViewProps 26 | } 27 | 28 | class ShimmerPlaceholder extends React.Component { 29 | getAnimated(): Animated.CompositeAnimation; 30 | } 31 | 32 | export const createShimmerPlaceholder = (LinearGradient?: React.ComponentClass) => ShimmerPlaceholder 33 | 34 | export default ShimmerPlaceholder 35 | } -------------------------------------------------------------------------------- /lib/ShimmerPlaceholder.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from "react"; 2 | import { Animated, Platform, StyleSheet, View } from "react-native"; 3 | 4 | const getOutputRange = (width, isReversed) => 5 | isReversed ? [width, -width] : [-width, width]; 6 | 7 | class ShimmerPlaceholder extends PureComponent { 8 | state = { 9 | beginShimmerPosition: new Animated.Value(-1), 10 | }; 11 | getAnimated = () => { 12 | const { delay, duration, isInteraction } = this.props; 13 | return Animated.loop( 14 | Animated.timing(this.state.beginShimmerPosition, { 15 | toValue: 1, 16 | delay, 17 | duration, 18 | useNativeDriver: Platform.OS !== "web", 19 | isInteraction, 20 | }) 21 | ); 22 | }; 23 | animatedValue = this.getAnimated(); 24 | 25 | render() { 26 | return ( 27 | 32 | ); 33 | } 34 | } 35 | 36 | ShimmerPlaceholder.defaultProps = { 37 | delay: 0, 38 | duration: 1000, 39 | isInteraction: true, 40 | }; 41 | 42 | const BasedShimmerPlaceholder = (props) => { 43 | const { 44 | width = 200, 45 | height = 15, 46 | shimmerColors = ["#ebebeb", "#c5c5c5", "#ebebeb"], 47 | isReversed = false, 48 | stopAutoRun = false, 49 | visible, 50 | location = [0.3, 0.5, 0.7], 51 | style, 52 | contentStyle, 53 | shimmerStyle, 54 | LinearGradient = View, 55 | children, 56 | animatedValue, 57 | beginShimmerPosition, 58 | shimmerWidthPercent = 1, 59 | containerProps, 60 | shimmerContainerProps, 61 | childrenContainerProps, 62 | } = props; 63 | 64 | const linearTranslate = beginShimmerPosition.interpolate({ 65 | inputRange: [-1, 1], 66 | outputRange: getOutputRange(width, isReversed), 67 | }); 68 | 69 | React.useEffect(() => { 70 | if (!stopAutoRun) { 71 | animatedValue.start(); 72 | } 73 | return () => { 74 | animatedValue.stop(); 75 | }; 76 | }, [stopAutoRun]); 77 | 78 | React.useEffect(() => { 79 | if (visible) { 80 | animatedValue.stop(); 81 | } 82 | if (!visible && !stopAutoRun) { 83 | animatedValue.start(); 84 | } 85 | }, [visible, stopAutoRun]); 86 | 87 | return ( 88 | 97 | {/* Force render children to restrict rendering twice */} 98 | 105 | {children} 106 | 107 | {!visible && ( 108 | 112 | 115 | 128 | 129 | 130 | )} 131 | 132 | ); 133 | }; 134 | 135 | const styles = StyleSheet.create({ 136 | container: { 137 | overflow: "hidden", 138 | }, 139 | }); 140 | 141 | /** 142 | * To create ShimmerPlaceholder by Linear Gradient. Only useful when you use 3rd party, 143 | * For example: react-native-linear-gradient 144 | * @param {Linear Gradient Component} LinearGradient - 'expo-linear-gradient' by default 145 | * 146 | * @example 147 | * 148 | * import LinearGradient from 'react-native-linear-gradient'; 149 | * import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder' 150 | * 151 | * const ShimmerPlaceHolder = createShimmerPlaceholder(LinearGradient) 152 | * 153 | * ... 154 | * 155 | * 156 | */ 157 | export const createShimmerPlaceholder = (LinearGradient = View) => 158 | React.forwardRef((props, ref) => ( 159 | 160 | )); 161 | 162 | export default ShimmerPlaceholder; 163 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-shimmer-placeholder", 3 | "version": "2.0.8", 4 | "author": "Zaku", 5 | "bugs": { 6 | "url": "https://github.com/tomzaku/react-native-shimmer-placeholder/issues" 7 | }, 8 | "directories": { 9 | "example": "example" 10 | }, 11 | "homepage": "https://github.com/tomzaku/react-native-shimmer-placeholder#readme", 12 | "keywords": [ 13 | "loading", 14 | "placeholder", 15 | "react-native", 16 | "shimmer" 17 | ], 18 | "license": "MIT", 19 | "main": "./lib/ShimmerPlaceholder.js", 20 | "peerDependencies": { 21 | "prop-types": ">=15.6.0", 22 | "react-native-linear-gradient": ">=2.4.0" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/tomzaku/react-native-shimmer-placeholder.git" 27 | }, 28 | "scripts": { 29 | "test": "echo \"Error: no test specified\" " 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------