Компонент для автоматического маштабирования высоты картинки в ReactNative, относительно ее ширины
В React Native, когда вам нужно создать макет для разных мобильных устройств, обычно вы используете относительные единицы измерения для установки ширины изображений. Однако высота не вычисляется автоматически, что может привести к проблемам с макетом.
Для того чтобы высота контейнера изображения сохраняла пропорции самого изображения, мы можем использовать подход из веб-разработки.
Создадим контейнер, в котором установим свойство paddingTop в процентах. Поскольку значение paddingTop вычисляется относительно ширины элемента, на котором он установлен, мы можем использовать этот подход.
Для вычисления процентного соотношения сторон исходного изображения мы можем использовать следующую формулу:
const aspectRatio = height / (width / 100);
Где height
- высота исходного изображения, а width
- его ширина.
Значение aspectRatio
мы будем использовать для установки paddingTop
нашего контейнера. Таким образом, контейнер будет иметь те же пропорции высоты и ширины, что и исходное изображение, при этом значения ширины и высоты будут указаны в процентах, что позволяет встраивать этот контейнер в любой макет.
Для размещения изображения внутри этого контейнера мы можем использовать следующий подход:
<View style={{ position: 'relative', paddingTop: `${aspectRatio}%` }}>
<View style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }}>
<Image source={imageSource} style={{ width: '100%', height: '100%' }} />
</View>
</View>
Здесь aspectRatio
- это значение, которое мы рассчитали ранее. imageSource
- это источник изображения.
Таким образом, изображение будет автоматически масштабироваться по высоте относительно ширины контейнера с сохранением пропорций.
Вот полный код компонента:
import React from 'react';
import {Image, ImageProps, ImageResizeMode, StyleSheet, View, ViewProps} from 'react-native';
interface ScaleImageProps {
/**
* if you don’t need the image width as a percentage and automatic height scaling,
* then perhaps you need to use component Image
*/
containerWidth: `${number}%` | number;
imageWidth: number;
imageHeight: number;
source: ImageProps['source'];
containerStyle?: ViewProps['style'];
resizeMode: ImageResizeMode;
}
export const ScaleImage: React.FC<ScaleImageProps> = ({
containerWidth,
imageWidth,
imageHeight,
source,
containerStyle,
resizeMode
}) => {
const paddingTop: `${number}%` = `${imageHeight / (imageWidth / 100)}%`;
return (
<View
style={[
{
width: containerWidth,
paddingTop,
},
containerStyle,
]}>
<View style={styles.wrapper}>
<Image style={styles.image} resizeMode={resizeMode} source={source} />
</View>
</View>
);
};
const styles = StyleSheet.create({
wrapper: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
},
image: {
width: '100%',
height: '100%',
},
});