Skip to content

Commit

Permalink
Reformatted the code, bumped major version, and updated README
Browse files Browse the repository at this point in the history
  • Loading branch information
ihor committed Aug 28, 2019
1 parent a27c054 commit 788b52c
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 64 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
React Native Scalable Image
===========================
React Native ```<Image/>``` component [does not keep image aspect ratio](https://github.com/facebook/react-native/issues/858) which results in the image being stretched or cropped. ```react-native-scalable-image``` solves this problem by calculating the image size and resizing the image when rendering.
React Native ```<Image/>``` component [does not keep the image aspect ratio](https://github.com/facebook/react-native/issues/858), which results in the image being stretched or cropped. ```react-native-scalable-image``` solves this problem by calculating the image size and resizing the image when rendering.

This library provides an ```<Image/>``` component which scales width or height automatically to keep the aspect ratio. It is useful when you don't know the aspect ratio in advance (e.g. user-uploaded content) but want to display the entire image and limit it only by width or height to fit the container component.

Expand Down Expand Up @@ -38,12 +38,13 @@ Specify width or height which may be calculated dynamically like in the example
| `width` | number | none | Maximum image width |
| `background` | boolean | false | Set to true when used as a background |
| `onPress` | function | none | onPress callback |
| `onSize` | function | none | Is called with ```{ width, height }``` as the arg when image size is calculated |
| `onSize` | function | none | Is called with ```{ width, height }``` as the first arg once image size is calculated |

Versions
========
The latest major version of `react-native-scalable-image` is implemented with hooks. If you are using a pre-hooks React version please use `react-native-scalable-image` version `0.5.1`

| React Native Version | Scalable Image Version |
| -------------------- | ---------------------- |
| <= 0.58 | <= 0.5.1 |
| >= 0.59 | 0.6.0 |
| React Version | Scalable Image Version |
| ------------- | ---------------------- |
| < 16.8 | 0.5.1 |
| >= 16.8 | > 1.0.0 |
157 changes: 100 additions & 57 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,67 +1,108 @@
import React, { useState, useEffect, useRef } from 'react';
import { Image, TouchableOpacity, ImageBackground } from 'react-native';
import React, {
useState,
useEffect,
useRef
} from 'react';

import PropTypes from 'prop-types';

import {
Image,
TouchableOpacity,
ImageBackground
} from 'react-native';

const resolveAssetSource = Image.resolveAssetSource;

export default (props) => {
const ImageComponent = props.background ? ImageBackground : Image;
const ScalableImage = props => {
const ImageComponent = props.background
? ImageBackground
: Image;

const [scalableWidth, setScalableWidth] = useState(null);
const [scalableHeight, setScalableHeight] = useState(null);
const [image, setImage] = useState(<ImageComponent />);
const mounted = useRef(false);
const [scalableWidth, setScalableWidth] = useState(null);
const [scalableHeight, setScalableHeight] = useState(null);
const [image, setImage] = useState(<ImageComponent />);
const mounted = useRef(false);

useEffect(() => {
mounted.current = true;
useEffect(() => {
mounted.current = true;

return () => {
mounted.current = false;
}
}, []);

useEffect(() => {
onProps(props);
})

useEffect(() => {
setImage(<ImageComponent {...props} style={[props.style, { width: scalableWidth, height: scalableHeight }]} />);
}, [props, scalableHeight, scalableWidth]);

const onProps = (localProps) => {
const { source } = localProps;
if (source.uri) {
const sourceToUse = source.uri ? source.uri : source;
Image.getSize(sourceToUse, (width, height) => adjustSize(width, height, props), e => console.log(e));
} else {
const sourceToUse = resolveAssetSource(source);
adjustSize(sourceToUse.width, sourceToUse.height, props);
return () => {
mounted.current = false;
}
}, []);

useEffect(() => {
onProps(props);
});

useEffect(() => {
setImage(
<ImageComponent
{...props}
style={[props.style, {
width: scalableWidth,
height: scalableHeight
}]}
/>
);
}, [props, scalableHeight, scalableWidth]);

const onProps = localProps => {
const { source } = localProps;
if (source.uri) {
const sourceToUse = source.uri
? source.uri
: source;

Image.getSize(
sourceToUse,
(width, height) => adjustSize(width, height, props),
console.err
);
}
else {
const sourceToUse = resolveAssetSource(source);
adjustSize(sourceToUse.width, sourceToUse.height, props);
}
};

const adjustSize = (sourceWidth, sourceHeight, localProps) => {
const { width, height } = localProps;

let ratio = 1;

if (width && height) {
ratio = Math.min(width / sourceWidth, height / sourceHeight);
}
else if (width) {
ratio = width / sourceWidth;
}
else if (height) {
ratio = height / sourceHeight;
}

if (mounted.current) {
const computedWidth = sourceWidth * ratio;
const computedHeight = sourceHeight * ratio;

setScalableWidth(computedWidth);
setScalableHeight(computedHeight);

props.onSize({ width: computedWidth, height: computedHeight });
}
};

if (!props.onPress) {
return image;
}
};

const adjustSize = (sourceWidth, sourceHeight, localProps) => {
const { width, height } = localProps;

let ratio = 1;

if (width && height) ratio = Math.min(width / sourceWidth, height / sourceHeight);
else if (width) ratio = width / sourceWidth;
else if (height) ratio = height / sourceHeight;
if (mounted.current) {
const computedWidth = sourceWidth * ratio;
const computedHeight = sourceHeight * ratio;
setScalableWidth(computedWidth);
setScalableHeight(computedHeight);
props.onSize({ width: computedWidth, height: computedHeight });
else {
return (
<TouchableOpacity onPress={props.onPress}>
{image}
</TouchableOpacity>
);
}
};

if (!props.onPress) return image;
else {
return (
<TouchableOpacity onPress={props.onPress}>
{image}
</TouchableOpacity>
)
};
};

ScalableImage.propTypes = {
Expand All @@ -76,3 +117,5 @@ ScalableImage.defaultProps = {
background: false,
onSize: size => {}
};

export default ScalableImage;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-scalable-image",
"version": "0.6.0",
"version": "1.0.0",
"license": "MIT",
"description": "React Native Image component which scales width or height automatically to keep the aspect ratio",
"keywords": [
Expand Down

0 comments on commit 788b52c

Please sign in to comment.