2015-09-14 14:35:58 +00:00
/ * *
* Copyright ( c ) 2015 - present , Facebook , Inc .
* All rights reserved .
*
* This source code is licensed under the BSD - style license found in the
* LICENSE file in the root directory of this source tree . An additional grant
* of patent rights can be found in the PATENTS file in the same directory .
*
* @ providesModule Image
* @ flow
* /
'use strict' ;
var ImageResizeMode = require ( 'ImageResizeMode' ) ;
var ImageStylePropTypes = require ( 'ImageStylePropTypes' ) ;
2017-03-02 15:32:08 +00:00
var NativeMethodsMixin = require ( 'NativeMethodsMixin' ) ;
var NativeModules = require ( 'NativeModules' ) ;
2015-09-14 14:35:58 +00:00
var React = require ( 'React' ) ;
2017-04-12 23:09:48 +00:00
var PropTypes = require ( 'prop-types' ) ;
2015-09-14 14:35:58 +00:00
var ReactNativeViewAttributes = require ( 'ReactNativeViewAttributes' ) ;
2017-03-02 15:32:08 +00:00
var Set = require ( 'Set' ) ;
2015-09-14 14:35:58 +00:00
var StyleSheet = require ( 'StyleSheet' ) ;
var StyleSheetPropType = require ( 'StyleSheetPropType' ) ;
var View = require ( 'View' ) ;
2017-04-12 23:09:48 +00:00
var ViewPropTypes = require ( 'ViewPropTypes' ) ;
2017-03-02 15:32:08 +00:00
var ViewStylePropTypes = require ( 'ViewStylePropTypes' ) ;
2015-09-14 14:35:58 +00:00
2017-07-07 21:24:25 +00:00
var createReactClass = require ( 'create-react-class' ) ;
2017-03-02 15:32:08 +00:00
var filterObject = require ( 'fbjs/lib/filterObject' ) ;
2015-09-14 14:35:58 +00:00
var flattenStyle = require ( 'flattenStyle' ) ;
var merge = require ( 'merge' ) ;
2015-11-18 16:24:26 +00:00
var requireNativeComponent = require ( 'requireNativeComponent' ) ;
2015-09-14 14:35:58 +00:00
var resolveAssetSource = require ( 'resolveAssetSource' ) ;
2016-04-13 14:29:10 +00:00
var {
ImageLoader ,
} = NativeModules ;
2016-07-18 19:07:29 +00:00
let _requestId = 1 ;
function generateRequestId ( ) {
return _requestId ++ ;
}
2015-09-14 14:35:58 +00:00
/ * *
* < Image > - A react component for displaying different types of images ,
* including network images , static resources , temporary local images , and
* images from local disk , such as the camera roll . Example usage :
*
* renderImages : function ( ) {
* return (
* < View >
* < Image
* style = { styles . icon }
2016-01-27 21:21:42 +00:00
* source = { require ( './myIcon.png' ) }
2015-09-14 14:35:58 +00:00
* / >
* < Image
* style = { styles . logo }
2017-10-04 21:33:20 +00:00
* source = { { uri : 'https://facebook.github.io/react/logo-og.png' } }
2015-09-14 14:35:58 +00:00
* / >
* < / V i e w >
* ) ;
* } ,
*
* More example code in ImageExample . js
* /
var ImageViewAttributes = merge ( ReactNativeViewAttributes . UIView , {
src : true ,
2015-12-06 23:44:47 +00:00
loadingIndicatorSrc : true ,
2016-09-09 12:00:52 +00:00
resizeMethod : true ,
2015-09-14 14:35:58 +00:00
resizeMode : true ,
2015-11-16 19:39:19 +00:00
progressiveRenderingEnabled : true ,
fadeDuration : true ,
2015-11-26 01:06:59 +00:00
shouldNotifyLoadEvents : true ,
2015-09-14 14:35:58 +00:00
} ) ;
Fixed incorrect style props passed to Android Image when using children
Summary:
Hi there,
Here is a fix for #7538 (and #5085).
I had originally discovered this issue when using `resizeMode` through the style props. Although this might arguably be an incorrect usage (see https://github.com/facebook/react-native/issues/4759#issuecomment-164301166) the same issue would happen with the `tintColor` and `overlayColor` style props.
To test this, you can render the following:
```jsx
const imageContainerStyle = {width: 100, height: 100, backgroundColor: 'green', marginLeft: 10, marginTop: 10, };
const imageStyle = {flex: 1, width: undefined, height: undefined, resizeMode: 'contain', };
return (
<View style={styles.container}>
<View style={imageContainerStyle}>
<Image style={imageStyle} source={
{uri:'http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg'}
}>
</Image>
</View>
<View style={imageContainerStyle}>
<Image style={imageStyle} source={
{
Closes https://github.com/facebook/react-native/pull/8410
Differential Revision: D3488010
Pulled By: andreicoman11
fbshipit-source-id: e9d1283cce8426c8878f9c3c66a43a2141232277
2016-06-27 10:17:33 +00:00
var ViewStyleKeys = new Set ( Object . keys ( ViewStylePropTypes ) ) ;
var ImageSpecificStyleKeys = new Set ( Object . keys ( ImageStylePropTypes ) . filter ( x => ! ViewStyleKeys . has ( x ) ) ) ;
2017-07-07 21:24:25 +00:00
var Image = createReactClass ( {
displayName : 'Image' ,
2015-09-14 14:35:58 +00:00
propTypes : {
2017-03-24 07:22:57 +00:00
... ViewPropTypes ,
2016-02-10 03:15:52 +00:00
style : StyleSheetPropType ( ImageStylePropTypes ) ,
2015-12-07 18:44:41 +00:00
/ * *
2015-10-09 16:31:51 +00:00
* ` uri ` is a string representing the resource identifier for the image , which
2016-01-27 21:21:42 +00:00
* could be an http address , a local file path , or a static image
* resource ( which should be wrapped in the ` require('./path/to/image.png') ` function ) .
2017-02-18 12:33:59 +00:00
*
* ` headers ` is an object representing the HTTP headers to send along with the request
* for a remote image .
*
2016-06-13 21:04:19 +00:00
* This prop can also contain several remote ` uri ` , specified together with
* their width and height . The native side will then choose the best ` uri ` to display
* based on the measured size of the image container .
2015-10-09 16:31:51 +00:00
* /
source : PropTypes . oneOfType ( [
PropTypes . shape ( {
uri : PropTypes . string ,
2017-02-18 12:33:59 +00:00
headers : PropTypes . objectOf ( PropTypes . string ) ,
2015-10-09 16:31:51 +00:00
} ) ,
// Opaque type returned by require('./image.jpg')
PropTypes . number ,
2016-06-13 21:04:19 +00:00
// Multiple sources
PropTypes . arrayOf (
PropTypes . shape ( {
uri : PropTypes . string ,
width : PropTypes . number ,
height : PropTypes . number ,
2017-10-03 06:19:31 +00:00
headers : PropTypes . objectOf ( PropTypes . string ) ,
2016-06-13 21:04:19 +00:00
} ) )
2016-02-10 03:15:52 +00:00
] ) ,
2017-03-02 15:32:08 +00:00
/ * *
* blurRadius : the blur radius of the blur filter added to the image
* /
blurRadius : PropTypes . number ,
2015-12-06 23:44:47 +00:00
/ * *
* similarly to ` source ` , this property represents the resource used to render
* the loading indicator for the image , displayed until image is ready to be
* displayed , typically after when it got downloaded from network .
* /
loadingIndicatorSource : PropTypes . oneOfType ( [
PropTypes . shape ( {
uri : PropTypes . string ,
} ) ,
// Opaque type returned by require('./image.jpg')
PropTypes . number ,
] ) ,
2015-11-16 19:39:19 +00:00
progressiveRenderingEnabled : PropTypes . bool ,
fadeDuration : PropTypes . number ,
2015-11-26 01:06:59 +00:00
/ * *
* Invoked on load start
* /
onLoadStart : PropTypes . func ,
2016-11-15 03:42:34 +00:00
/ * *
* Invoked on load error
* /
onError : PropTypes . func ,
2015-11-26 01:06:59 +00:00
/ * *
* Invoked when load completes successfully
* /
onLoad : PropTypes . func ,
/ * *
* Invoked when load either succeeds or fails
* /
onLoadEnd : PropTypes . func ,
2015-09-14 14:35:58 +00:00
/ * *
* Used to locate this view in end - to - end tests .
* /
testID : PropTypes . string ,
2016-09-09 12:00:52 +00:00
/ * *
* The mechanism that should be used to resize the image when the image ' s dimensions
* differ from the image view ' s dimensions . Defaults to ` auto ` .
*
* - ` auto ` : Use heuristics to pick between ` resize ` and ` scale ` .
*
* - ` resize ` : A software operation which changes the encoded image in memory before it
* gets decoded . This should be used instead of ` scale ` when the image is much larger
* than the view .
*
* - ` scale ` : The image gets drawn downscaled or upscaled . Compared to ` resize ` , ` scale ` is
* faster ( usually hardware accelerated ) and produces higher quality images . This
* should be used if the image is smaller than the view . It should also be used if the
* image is slightly bigger than the view .
*
* More details about ` resize ` and ` scale ` can be found at http : //frescolib.org/docs/resizing-rotating.html.
*
* @ platform android
* /
resizeMethod : PropTypes . oneOf ( [ 'auto' , 'resize' , 'scale' ] ) ,
2016-08-01 07:49:14 +00:00
/ * *
* Determines how to resize the image when the frame doesn ' t match the raw
* image dimensions .
*
* 'cover' : Scale the image uniformly ( maintain the image ' s aspect ratio )
* so that both dimensions ( width and height ) of the image will be equal
* to or larger than the corresponding dimension of the view ( minus padding ) .
*
* 'contain' : Scale the image uniformly ( maintain the image ' s aspect ratio )
* so that both dimensions ( width and height ) of the image will be equal to
* or less than the corresponding dimension of the view ( minus padding ) .
*
* 'stretch' : Scale width and height independently , This may change the
* aspect ratio of the src .
2016-08-16 11:01:39 +00:00
*
* 'center' : Scale the image down so that it is completely visible ,
* if bigger than the area of the view .
* The image will not be scaled up .
2016-08-01 07:49:14 +00:00
* /
2016-08-16 11:01:39 +00:00
resizeMode : PropTypes . oneOf ( [ 'cover' , 'contain' , 'stretch' , 'center' ] ) ,
2015-09-14 14:35:58 +00:00
} ,
statics : {
resizeMode : ImageResizeMode ,
2016-05-21 01:40:59 +00:00
getSize (
url : string ,
success : ( width : number , height : number ) => void ,
2017-04-05 17:16:30 +00:00
failure ? : ( error : any ) => void ,
2016-05-21 01:40:59 +00:00
) {
return ImageLoader . getSize ( url )
. then ( function ( sizes ) {
success ( sizes . width , sizes . height ) ;
} )
. catch ( failure || function ( ) {
console . warn ( 'Failed to get size for image: ' + url ) ;
} ) ;
} ,
2016-04-13 14:29:10 +00:00
/ * *
* Prefetches a remote image for later use by downloading it to the disk
* cache
* /
2016-07-18 19:07:29 +00:00
prefetch ( url : string , callback : ? Function ) {
const requestId = generateRequestId ( ) ;
callback && callback ( requestId ) ;
return ImageLoader . prefetchImage ( url , requestId ) ;
} ,
/ * *
* Abort prefetch request
* /
abortPrefetch ( requestId : number ) {
2016-07-23 07:16:32 +00:00
ImageLoader . abortRequest ( requestId ) ;
2016-04-13 14:29:10 +00:00
} ,
2016-08-31 12:06:10 +00:00
/ * *
* Perform cache interrogation .
*
* @ param urls the list of image URLs to check the cache for .
* @ return a mapping from url to cache status , such as "disk" or "memory" . If a requested URL is
* not in the mapping , it means it ' s not in the cache .
* /
async queryCache ( urls : Array < string > ) : Promise < Map < string , 'memory' | 'disk' >> {
return await ImageLoader . queryCache ( urls ) ;
2016-11-15 05:01:02 +00:00
} ,
/ * *
* Resolves an asset reference into an object which has the properties ` uri ` , ` width ` ,
* and ` height ` . The input may either be a number ( opaque type returned by
* require ( './foo.png' ) ) or an ` ImageSource ` like { uri : '<http location || file path>' }
* /
resolveAssetSource : resolveAssetSource ,
2015-09-14 14:35:58 +00:00
} ,
mixins : [ NativeMethodsMixin ] ,
/ * *
* ` NativeMethodsMixin ` will look for this when invoking ` setNativeProps ` . We
2017-09-18 04:26:17 +00:00
* make ` this ` look like an actual native component class .
2015-09-14 14:35:58 +00:00
* /
viewConfig : {
uiViewClassName : 'RCTView' ,
2016-03-01 02:02:11 +00:00
validAttributes : ReactNativeViewAttributes . RCTView ,
2015-09-14 14:35:58 +00:00
} ,
2015-11-13 18:51:09 +00:00
contextTypes : {
2017-04-12 23:09:48 +00:00
isInAParentText : PropTypes . bool
2015-11-13 18:51:09 +00:00
} ,
2015-09-14 14:35:58 +00:00
render : function ( ) {
2016-06-13 21:04:19 +00:00
const source = resolveAssetSource ( this . props . source ) ;
const loadingIndicatorSource = resolveAssetSource ( this . props . loadingIndicatorSource ) ;
2015-10-05 10:59:02 +00:00
2016-06-13 21:04:19 +00:00
// As opposed to the ios version, here we render `null` when there is no source, source.uri
// or source array.
2015-10-05 10:59:02 +00:00
if ( source && source . uri === '' ) {
console . warn ( 'source.uri should not be an empty string' ) ;
}
2016-03-04 15:31:38 +00:00
if ( this . props . src ) {
console . warn ( 'The <Image> component requires a `source` property rather than `src`.' ) ;
}
2017-09-26 04:55:56 +00:00
if ( this . props . children ) {
throw new Error ( 'The <Image> component cannot contain children. If you want to render content on top of the image, consider using aboslute positioning.' ) ;
}
2016-06-13 21:04:19 +00:00
if ( source && ( source . uri || Array . isArray ( source ) ) ) {
let style ;
let sources ;
if ( source . uri ) {
const { width , height } = source ;
style = flattenStyle ( [ { width , height } , styles . base , this . props . style ] ) ;
sources = [ { uri : source . uri } ] ;
} else {
style = flattenStyle ( [ styles . base , this . props . style ] ) ;
sources = source ;
}
2016-11-15 03:42:34 +00:00
const { onLoadStart , onLoad , onLoadEnd , onError } = this . props ;
2016-06-13 21:04:19 +00:00
const nativeProps = merge ( this . props , {
2015-09-14 14:35:58 +00:00
style ,
2016-11-15 03:42:34 +00:00
shouldNotifyLoadEvents : ! ! ( onLoadStart || onLoad || onLoadEnd || onError ) ,
2016-06-13 21:04:19 +00:00
src : sources ,
2017-02-18 12:33:59 +00:00
headers : source . headers ,
2015-12-06 23:44:47 +00:00
loadingIndicatorSrc : loadingIndicatorSource ? loadingIndicatorSource . uri : null ,
2015-09-14 14:35:58 +00:00
} ) ;
2017-09-18 04:26:17 +00:00
if ( this . context . isInAParentText ) {
return < RCTTextInlineImage { ... nativeProps } / > ;
2015-09-14 14:35:58 +00:00
} else {
2017-09-18 04:26:17 +00:00
return < RKImage { ... nativeProps } / > ;
2015-09-14 14:35:58 +00:00
}
}
return null ;
}
} ) ;
var styles = StyleSheet . create ( {
base : {
overflow : 'hidden' ,
} ,
} ) ;
2015-11-18 16:24:26 +00:00
var cfg = {
nativeOnly : {
src : true ,
2017-02-18 12:33:59 +00:00
headers : true ,
2015-12-06 23:44:47 +00:00
loadingIndicatorSrc : true ,
2015-11-26 01:06:59 +00:00
shouldNotifyLoadEvents : true ,
2015-11-18 16:24:26 +00:00
} ,
} ;
var RKImage = requireNativeComponent ( 'RCTImageView' , Image , cfg ) ;
var RCTTextInlineImage = requireNativeComponent ( 'RCTTextInlineImage' , Image , cfg ) ;
2015-09-14 14:35:58 +00:00
module . exports = Image ;