├── .gitignore
├── LICENSE
├── README.md
├── index.d.ts
├── index.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea
3 | node_modules/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Ihor Burlachenko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation
7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
8 | to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions
11 | of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
14 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
15 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | React Native Scalable Image
2 | ===========================
3 | React Native `````` 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.
4 |
5 | This library provides an `````` 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.
6 |
7 | The following example creates an image which fits the full screen width and keeps the aspect ratio:
8 |
9 | ```jsx
10 | import React from 'react';
11 | import { Dimensions } from 'react-native';
12 | import Image from 'react-native-scalable-image';
13 |
14 | const image = (
15 | '}}
18 | />
19 | );
20 | ```
21 |
22 |
23 | Install
24 | =======
25 | ```npm install react-native-scalable-image --save```
26 |
27 |
28 | Usage
29 | =====
30 |
31 | Specify width or height which may be calculated dynamically like in the example above. All other props are the same as in regular [React Native `````` component](https://facebook.github.io/react-native/docs/image.html).
32 |
33 | ## props
34 |
35 | | name | type | default | description |
36 | | ------------- | --------------- | --------------------------- | --------------------------------------------------------------------------|
37 | | `height` | number | none | Maximum image height |
38 | | `width` | number | none | Maximum image width |
39 | | `background` | boolean | false | Set to true when used as a background |
40 | | `component` | React.ReactNode | none | Custom image component |
41 | | `onPress` | function | none | onPress callback |
42 | | `onSize` | function | none | Is called with ```{ width, height }``` as the first arg once image size is calculated |
43 |
44 | Versions
45 | ========
46 | 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`
47 |
48 | | React Version | Scalable Image Version |
49 | | ------------- | ---------------------- |
50 | | < 16.8 | 0.5.1 |
51 | | >= 16.8 | > 1.0.0 |
52 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | import { ImageProps } from 'react-native'
2 | import React, { Component } from 'react'
3 |
4 | interface IOnSizeParams {
5 | width: number,
6 | height: number,
7 | }
8 |
9 | interface IImageProps extends ImageProps {
10 | height?: number,
11 | width?: number,
12 | background?: boolean,
13 | component?: React.ReactNode,
14 | onPress?: () => void,
15 | onSize?: (onSizeParams: IOnSizeParams) => void,
16 | }
17 |
18 | export default class Image extends Component {}
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React, {
2 | useState,
3 | useEffect,
4 | useRef
5 | } from 'react';
6 |
7 | import PropTypes from 'prop-types';
8 |
9 | import {
10 | Image,
11 | TouchableOpacity,
12 | ImageBackground
13 | } from 'react-native';
14 |
15 | const resolveAssetSource = Image.resolveAssetSource;
16 |
17 | const ScalableImage = props => {
18 | const ImageComponent = props.component
19 | ? props.component
20 | : props.background
21 | ? ImageBackground
22 | : Image;
23 |
24 | const [scalableWidth, setScalableWidth] = useState(null);
25 | const [scalableHeight, setScalableHeight] = useState(null);
26 | const [image, setImage] = useState(null);
27 | const mounted = useRef(false);
28 |
29 | useEffect(() => {
30 | mounted.current = true;
31 |
32 | return () => {
33 | mounted.current = false;
34 | }
35 | }, []);
36 |
37 | useEffect(() => {
38 | onProps(props);
39 | });
40 |
41 | useEffect(() => {
42 | setImage(
43 |
50 | );
51 | }, [scalableHeight, scalableWidth]);
52 |
53 | const onProps = localProps => {
54 | const { source } = localProps;
55 | if (source.uri) {
56 | const sourceToUse = source.uri
57 | ? source.uri
58 | : source;
59 |
60 | Image.getSize(
61 | sourceToUse,
62 | (width, height) => adjustSize(width, height, props),
63 | console.err
64 | );
65 | }
66 | else {
67 | const sourceToUse = resolveAssetSource(source);
68 | adjustSize(sourceToUse.width, sourceToUse.height, props);
69 | }
70 | };
71 |
72 | const adjustSize = (sourceWidth, sourceHeight, localProps) => {
73 | const { width, height } = localProps;
74 |
75 | let ratio = 1;
76 |
77 | if (width && height) {
78 | ratio = Math.min(width / sourceWidth, height / sourceHeight);
79 | }
80 | else if (width) {
81 | ratio = width / sourceWidth;
82 | }
83 | else if (height) {
84 | ratio = height / sourceHeight;
85 | }
86 |
87 | if (mounted.current) {
88 | const computedWidth = sourceWidth * ratio;
89 | const computedHeight = sourceHeight * ratio;
90 |
91 | setScalableWidth(computedWidth);
92 | setScalableHeight(computedHeight);
93 |
94 | props.onSize({ width: computedWidth, height: computedHeight });
95 | }
96 | };
97 |
98 | if (!props.onPress) {
99 | return image;
100 | }
101 | else {
102 | return (
103 |
104 | {image}
105 |
106 | );
107 | }
108 | };
109 |
110 | ScalableImage.propTypes = {
111 | width: PropTypes.number,
112 | height: PropTypes.number,
113 | onPress: PropTypes.func,
114 | onSize: PropTypes.func,
115 | background: PropTypes.bool,
116 | };
117 |
118 | ScalableImage.defaultProps = {
119 | background: false,
120 | onSize: size => {}
121 | };
122 |
123 | export default ScalableImage;
124 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-scalable-image",
3 | "version": "1.1.0",
4 | "license": "MIT",
5 | "description": "React Native Image component which scales width or height automatically to keep the aspect ratio",
6 | "keywords": [
7 | "react-native",
8 | "image",
9 | "component",
10 | "scalable",
11 | "aspect-ratio",
12 | "scales-width",
13 | "scales-height"
14 | ],
15 | "homepage": "https://github.com/ihor/react-native-scalable-image",
16 | "bugs": {
17 | "url": "https://github.com/ihor/react-native-scalable-image/issues"
18 | },
19 | "author": {
20 | "name": "Ihor Burlachenko",
21 | "email": "ihor.burlachenko@gmail.com",
22 | "url": "http://ihor.burlachenko.com"
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/ihor/react-native-scalable-image.git"
27 | },
28 | "dependencies": {},
29 | "devDependencies": {
30 | "@types/react": "^16.8.23",
31 | "@types/react-native": ">=0.60.2"
32 | },
33 | "peerDependencies": {
34 | "prop-types": "^15.7.2",
35 | "react": "^16.8.3",
36 | "react-native": ">=0.59.0"
37 | },
38 | "scripts": {}
39 | }
40 |
--------------------------------------------------------------------------------