react-native-flex-image
Advanced tools
Comparing version 1.1.0 to 1.2.0
{ | ||
"name": "react-native-flex-image", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"files": [ | ||
@@ -5,0 +5,0 @@ "flow-typed", |
@@ -103,2 +103,21 @@ # react-native-flex-image | ||
#### Progressive Loading Component | ||
```js | ||
import FlexImage from 'react-native-flex-image'; | ||
function App() { | ||
return ( | ||
<View style={{flex: 1}}> | ||
<FlexImage | ||
source={{ | ||
uri: 'image source uri', | ||
}} | ||
thumbnail={{uri: 'thumbnail image source uri'}} | ||
loadingMethod="progressive" | ||
/> | ||
</View> | ||
); | ||
} | ||
``` | ||
## Properties | ||
@@ -113,2 +132,4 @@ *Note: Other properties will be passed down to underlying image component.* | ||
|**`loadingComponent`**|optional|custom loading indicator when render the image |`<ActivityIndicator animating={true} size="large" />`| | ||
|**`thumbnail`**|optional|source of the thumbnail|*None*| | ||
|**`loadingMethod`**|optional|enum for select loading method, using `indicator` or `progressive`|`indicator`| | ||
@@ -115,0 +136,0 @@ |
@@ -12,24 +12,26 @@ // @flow | ||
TouchableOpacity, | ||
Animated, | ||
} from 'react-native'; | ||
type Cancellable = { | ||
cancel: () => void; | ||
cancel: () => void, | ||
}; | ||
type Props = { | ||
source: number | {uri: string; width?: number; height?: number}; | ||
style?: StyleType; | ||
loadingComponent?: ReactNode; | ||
onPress?: () => void; | ||
source: number | { uri: string, width?: number, height?: number }, | ||
style?: StyleType, | ||
loadingComponent?: ReactNode, | ||
onPress?: () => void, | ||
thumbnail?: number | { uri: string, width?: number, height?: number }, | ||
loadingMethod?: 'spinner' | 'progressive', | ||
}; | ||
type State = { | ||
isLoading: boolean; | ||
ratio: ?number; | ||
error: ?string; | ||
isLoading: boolean, | ||
ratio: ?number, | ||
error: ?string, | ||
thumbnailOpacity: Animated.Value, | ||
}; | ||
export default class FlexImage extends Component { | ||
props: Props; | ||
state: State; | ||
export default class FlexImage extends Component<Props, State> { | ||
_pendingGetSize: ?Cancellable; | ||
@@ -41,3 +43,3 @@ | ||
let {source} = props; | ||
let {source, thumbnail, loadingMethod} = props; | ||
let ratio; | ||
@@ -47,4 +49,5 @@ let error; | ||
if (typeof source === 'number') { | ||
let imageSource = resolveAssetSource(source); | ||
let src = thumbnail && loadingMethod === 'progressive' ? thumbnail : source; | ||
if (typeof src === 'number') { | ||
let imageSource = resolveAssetSource(src); | ||
if (imageSource) { | ||
@@ -61,3 +64,3 @@ let {width, height} = imageSource; | ||
this._pendingGetSize = getImageSize( | ||
source, | ||
src, | ||
this._onLoadSuccess, | ||
@@ -72,2 +75,3 @@ this._onLoadFail | ||
error, | ||
thumbnailOpacity: new Animated.Value(0), | ||
}; | ||
@@ -83,9 +87,17 @@ } | ||
render() { | ||
let {source, style, onPress, loadingComponent, ...otherProps} = this.props; | ||
let {isLoading, ratio, error} = this.state; | ||
let component; | ||
let { | ||
source, | ||
style, | ||
onPress, | ||
loadingComponent, | ||
thumbnail, | ||
loadingMethod, | ||
...otherProps | ||
} = this.props; | ||
let {isLoading, ratio, error, thumbnailOpacity} = this.state; | ||
if (isLoading) { | ||
let loadingIndicator = | ||
loadingComponent || <ActivityIndicator animating={true} size="large" />; | ||
if (isLoading && loadingMethod !== 'progressive') { | ||
let loadingIndicator = loadingComponent || ( | ||
<ActivityIndicator size="large" /> | ||
); | ||
return ( | ||
@@ -101,5 +113,3 @@ <View style={[{justifyContent: 'center', alignItems: 'center'}, style]}> | ||
<View style={[{justifyContent: 'center', alignItems: 'center'}, style]}> | ||
<Text> | ||
{error} | ||
</Text> | ||
<Text>{error}</Text> | ||
</View> | ||
@@ -118,23 +128,47 @@ ); | ||
component = ( | ||
<View style={[{aspectRatio: ratio}, style]}> | ||
<Image | ||
return ( | ||
<TouchableOpacity | ||
onPress={onPress} | ||
disabled={!onPress} | ||
style={[{aspectRatio: ratio}, style]} | ||
> | ||
{thumbnail && | ||
loadingMethod === 'progressive' && ( | ||
<Animated.Image | ||
{...otherProps} | ||
source={thumbnail} | ||
style={{ | ||
width: '100%', | ||
height: '100%', | ||
opacity: thumbnailOpacity, | ||
zIndex: 1, | ||
}} | ||
onLoad={this._onThumbnailLoad} | ||
testID="progressiveThumbnail" | ||
/> | ||
)} | ||
<Animated.Image | ||
{...otherProps} | ||
source={imageSource} | ||
style={{width: '100%', height: '100%'}} | ||
style={{width: '100%', height: '100%', position: 'absolute'}} | ||
onLoad={this._onLoad} | ||
/> | ||
</View> | ||
</TouchableOpacity> | ||
); | ||
if (onPress) { | ||
return ( | ||
<TouchableOpacity onPress={onPress}> | ||
{component} | ||
</TouchableOpacity> | ||
); | ||
} else { | ||
return component; | ||
} | ||
} | ||
_onThumbnailLoad = () => { | ||
Animated.timing(this.state.thumbnailOpacity, { | ||
toValue: 1, | ||
duration: 250, | ||
}).start(); | ||
}; | ||
_onLoad = () => { | ||
Animated.timing(this.state.thumbnailOpacity, { | ||
toValue: 0, | ||
duration: 250, | ||
}).start(); | ||
}; | ||
_onLoadSuccess(width: number, height: number) { | ||
@@ -158,3 +192,3 @@ let ratio = width / height; | ||
export function getImageSize( | ||
source: {uri: string}, | ||
source: { uri: string }, | ||
onSuccess: (width: number, height: number) => void, | ||
@@ -161,0 +195,0 @@ onFail: (error: Error) => void |
8898
205
138