react-native-flex-image
Advanced tools
+1
-1
| { | ||
| "name": "react-native-flex-image", | ||
| "version": "1.1.0", | ||
| "version": "1.2.0", | ||
| "files": [ | ||
@@ -5,0 +5,0 @@ "flow-typed", |
+21
-0
@@ -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 @@ |
+74
-40
@@ -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
21.72%205
19.19%138
17.95%