Skip to content

Commit f62a69e

Browse files
author
Wyatt McBain
committed
Merge branch 'v2'
Release version 2. * Animate placeholder while loading.
2 parents ce03ce4 + 2d57680 commit f62a69e

9 files changed

+85
-26
lines changed

AsyncImageAnimated/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ fastlane/screenshots
5454

5555
# Project
5656
lib/
57+
package-lock.json

AsyncImageAnimated/package-lock.json

+1-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

AsyncImageAnimated/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@types/react-native": "^0.47.5",
1616
"react": "16.0.0-alpha.12",
1717
"react-native": "0.47.1",
18-
"react-native-async-image-animated": "^1.0.5",
18+
"react-native-async-image-animated": "^2.0.0",
1919
"typescript": "^2.4.2"
2020
},
2121
"devDependencies": {

README.md

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# AsyncImageAnimated
22

33
<p align="center">
4-
<img src ="https://media.giphy.com/media/X06Nr75bS7k8U/giphy.gif" />
4+
<img src ="https://media.giphy.com/media/l378cTcPS3Ki2Kfq8/giphy.gif" />
55
</p>
66

7-
Simple cross-platform asynchronous image component for React Native 🙌🏻 with a few animation options. Displays a placeholder color while the image loads from the network.
7+
Simple cross-platform asynchronous image component for React Native 🙌🏻 with a few animation options. Displays an animated placeholder color while the image loads from the network.
88

99
Source is available in the `AsyncImageAnimated/src` directory. 🙂
1010

@@ -41,12 +41,10 @@ Fetch an image with a 30x30 dimension and a placeholderColor.
4141

4242
```javacript
4343
source: {
44-
uri: string // Network uri
44+
uri: string,
4545
},
46-
style: { // StyleSheet or Objects will work
47-
[key: string]: string | number | Object
48-
},
49-
key?: string, // For lists
46+
style: '@types/react-native'.ViewStyle,
47+
key?: string,
5048
placeholderColor?: string,
5149
delay?: number,
5250
animationStyle?: 'fade' | 'shrink' | 'explode'
@@ -72,7 +70,7 @@ Then reload to view animations again.
7270

7371
## Planned Updates
7472

75-
* [ ] Animate color of placeholder while loading
73+
* [x] Animate color of placeholder while loading - v2
7674
* [ ] Placeholder image support
7775
* [ ] Progressive image support
7876
* [ ] Tests / Detox Tests

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-async-image-animated",
3-
"version": "1.1.0",
3+
"version": "2.0.0",
44
"description": "Asynchronous loading Image component for React Native.",
55
"main": "index.js",
66
"scripts": {

src/AsyncImageAnimated.tsx

+44-12
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ import { Component } from 'react'
99

1010
import {
1111
Animated,
12+
Easing,
1213
View,
1314
ViewStyle,
1415
} from 'react-native'
1516

17+
import { lightenColor } from './lib/color'
18+
1619
type AnimationStyle = 'fade' | 'shrink' | 'explode'
1720

1821
interface Props {
@@ -32,6 +35,8 @@ interface State {
3235
image: Animated.Value,
3336
placeholder: Animated.Value,
3437
},
38+
placeholderColorAnimated: Animated.Value,
39+
placeholderColorLightened: string,
3540
placeholderScale: Animated.Value,
3641
}
3742

@@ -49,10 +54,18 @@ export default class AsyncImageAnimated extends Component<Props, State> {
4954
image: new Animated.Value(0),
5055
placeholder: new Animated.Value(0.8),
5156
},
57+
placeholderColorAnimated: new Animated.Value(1.0),
58+
placeholderColorLightened: props.placeholderColor
59+
? lightenColor(props.placeholderColor, 20)
60+
: 'transparent',
5261
placeholderScale: new Animated.Value(1.0),
5362
}
5463
}
5564

65+
componentDidMount() {
66+
this.animatePlaceholderColor()
67+
}
68+
5669
render() {
5770
const {
5871
key,
@@ -65,6 +78,8 @@ export default class AsyncImageAnimated extends Component<Props, State> {
6578
loaded,
6679
opacity,
6780
placeholderScale,
81+
placeholderColorAnimated,
82+
placeholderColorLightened,
6883
} = this.state
6984

7085
return (
@@ -90,8 +105,15 @@ export default class AsyncImageAnimated extends Component<Props, State> {
90105
style={[
91106
style,
92107
{
93-
backgroundColor: placeholderColor ||
94-
'transparent',
108+
backgroundColor: placeholderColor
109+
? placeholderColorAnimated.interpolate({
110+
inputRange: [0, 1],
111+
outputRange: [
112+
placeholderColor,
113+
placeholderColorLightened,
114+
],
115+
})
116+
: 'transparent',
95117
opacity: opacity.placeholder,
96118
position: 'absolute',
97119
transform: [{ scale: placeholderScale }],
@@ -126,13 +148,11 @@ export default class AsyncImageAnimated extends Component<Props, State> {
126148
delay,
127149
duration: 200,
128150
toValue: 0,
129-
useNativeDriver: true,
130151
}),
131152
Animated.timing(image, {
132153
delay,
133154
duration: 300,
134155
toValue: 1,
135-
useNativeDriver: true,
136156
}),
137157
]).start(callback)
138158

@@ -143,20 +163,17 @@ export default class AsyncImageAnimated extends Component<Props, State> {
143163
delay,
144164
duration: 200,
145165
toValue: 0,
146-
useNativeDriver: true,
147166
}),
148167
Animated.timing(placeholderScale, {
149168
delay,
150169
duration: 200,
151170
toValue: 0,
152-
useNativeDriver: true,
153171
}),
154172
]),
155173
Animated.timing(image, {
156174
delay,
157175
duration: 300,
158176
toValue: 1,
159-
useNativeDriver: true,
160177
}),
161178
]).start(callback)
162179

@@ -167,35 +184,50 @@ export default class AsyncImageAnimated extends Component<Props, State> {
167184
delay,
168185
duration: 100,
169186
toValue: 0.7,
170-
useNativeDriver: true,
171187
}),
172188
Animated.timing(placeholder, {
173189
duration: 100,
174190
toValue: 0.66,
175-
useNativeDriver: true,
176191
}),
177192
]),
178193
Animated.parallel([
179194
Animated.parallel([
180195
Animated.timing(placeholder, {
181196
duration: 200,
182197
toValue: 0,
183-
useNativeDriver: true,
184198
}),
185199
Animated.timing(placeholderScale, {
186200
duration: 200,
187201
toValue: 1.2,
188-
useNativeDriver: true,
189202
}),
190203
]),
191204
Animated.timing(image, {
192205
delay: 200,
193206
duration: 300,
194207
toValue: 1,
195-
useNativeDriver: true,
196208
}),
197209
]),
198210
]).start(callback)
199211
}
200212
}
213+
214+
private animatePlaceholderColor = () => {
215+
const {
216+
loaded,
217+
placeholderColorAnimated,
218+
} = this.state
219+
220+
if (loaded) return
221+
222+
Animated.sequence([
223+
Animated.timing(placeholderColorAnimated, {
224+
duration: 500,
225+
toValue: 1.0,
226+
}),
227+
Animated.timing(placeholderColorAnimated, {
228+
duration: 400,
229+
toValue: 0.0,
230+
}),
231+
]).start(this.animatePlaceholderColor)
232+
}
201233
}

src/lib/color.tsx

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
// https://css-tricks.com/snippets/javascript/lighten-darken-color/
3+
4+
/* tslint:disable no-bitwise */
5+
export const lightenColor = (color: string, amount: number) => {
6+
if (color [0] === '#') color = color.slice(1)
7+
8+
const colorValue = parseInt(color, 16)
9+
10+
let red = (colorValue >> 16) + amount
11+
12+
if (red > 255) red = 255
13+
else if (red < 0) red = 0
14+
15+
let blue = ((colorValue >> 8) & 0x00FF) + amount
16+
17+
if (blue > 255) blue = 255
18+
else if (blue < 0) blue = 0
19+
20+
let green = (colorValue & 0x0000FF) + amount
21+
22+
if (green > 255) green = 255
23+
else if (green < 0) green = 0
24+
25+
return `#${(green | (blue << 8) | (red << 16)).toString(16)}`
26+
}

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"outDir": "./lib"
99
},
1010
"include": [
11-
"src/*"
11+
"src/**/*"
1212
],
1313
"exclude": [
1414
"node_modules",

tslint.json

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
"member-access": [
3737
true,
3838
"no-public"
39+
],
40+
"curly": [
41+
true,
42+
"ignore-same-line"
3943
]
4044
},
4145
"rulesDirectory": []

0 commit comments

Comments
 (0)