Ответ 1
Используйте style={{ aspectRatio: 3/2 }}
для горизонтального изображения с отношением ширины к высоте 3: 2.
Документы: https://facebook.github.io/react-native/docs/layout-props.html#aspectratio
(Доступно в RN 0. 40+)
У меня есть запрос относительно тега. Я хочу, чтобы изображение занимало всю ширину родительского элемента, которое я использую с помощью alignSelf: stretch, но я также хочу, чтобы высота соответствовала соотношению сторон изображения. Как я могу достичь чего-то подобного?
Итак, я хочу, чтобы указать высоту как отношение ширины изображения.
Используйте style={{ aspectRatio: 3/2 }}
для горизонтального изображения с отношением ширины к высоте 3: 2.
Документы: https://facebook.github.io/react-native/docs/layout-props.html#aspectratio
(Доступно в RN 0. 40+)
Мне нравится подход BDV, и я использую этот вид изображений почти везде в моем приложении. Вот почему я создал собственный компонент, который использует onLayout
для поддержки вращения устройства.
import resolveAssetSource from 'resolveAssetSource';
import React, {Component} from 'react';
import {Image, View} from 'react-native';
export default class FullWidthImage extends Component {
constructor() {
super();
this.state = {
width: 0,
height: 0
};
}
_onLayout(event) {
const containerWidth = event.nativeEvent.layout.width;
if (this.props.ratio) {
this.setState({
width: containerWidth,
height: containerWidth * this.props.ratio
});
} else if (typeof this.props.source === 'number') {
const source = resolveAssetSource(this.props.source);
this.setState({
width: containerWidth,
height: containerWidth * source.height / source.width
});
} else if (typeof this.props.source === 'object') {
Image.getSize(this.props.source.uri, (width, height) => {
this.setState({
width: containerWidth,
height: containerWidth * height / width
});
});
}
}
render() {
return (
<View onLayout={this._onLayout.bind(this)}>
<Image
source={this.props.source}
style={{
width: this.state.width,
height: this.state.height
}} />
</View>
);
}
}
Это на самом деле довольно просто.
Класс Image
имеет метод getSize
. [1]
Допустим, вы создали компонент для вашего aspectRatioImage
и вычисляете соответствующие значения каждый раз, когда запускается componentWillMount
.
Тогда ваш код будет выглядеть примерно так:
componentDidMount() {
Image.getSize(this.props.source.uri, (srcWidth, srcHeight) => {
const maxHeight = Dimensions.get('window').height; // or something else
const maxWidth = Dimensions.get('window').width;
const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
this.setState({ width: srcWidth * ratio, height: srcHeight * ratio });
}, error => {
console.log('error:', error);
});
}
Теперь, когда высота и ширина изображения сохранены в состоянии вашего компонента, вы можете просто запустить
<Image
style={{ width: this.state.width, height: this.state.height }}
source={this.props.source}
resizeMode="cover"
/>
[1] - https://facebook.github.io/react-native/docs/image.html#getsize.
Вы можете рассчитать высоту изображения на основе соотношения ширина/высота.
Поэтому, если изображение изначально имеет размер 200x100, после установки его resizeMode для растяжения:
var deviceWidth: Dimensions.get('window').width;
...
myImage {
width: deviceWidth,
height: deviceWidth * 0.5
}
Я знаю, может быть, это не лучшая практика, но она мне очень помогла с изображениями всех размеров, которые необходимы для поддержания определенной связи с другими изображениями и т.д.
Вы можете использовать response-native-scalable-image. Следующий пример сделает работу:
import React from 'react';
import { Dimensions } from 'react-native';
import Image from 'react-native-scalable-image';
const image = <Image width={Dimensions.get('window').width} source={{uri: '<image uri>'}} />;
<Image
source={require('../../assets/img/headers/image-1.jpg')}
style={styles.responsiveImage}
/>
const styles = StyleSheet.create({
responsiveImage: {
width: '100%',
// Without height undefined it won't work
height: undefined,
// figure out your image aspect ratio
aspectRatio: 135 / 76,
},
});
Как правило, выполнение следующих действий даст нам изображение, отрисованное до максимальной ширины/высоты в зависимости от ориентации, при сохранении соотношения сторон самого изображения:
render(){
return(<Image style={{'width': Dimensions.get('window').width,
'height': Dimensions.get('window').height}}
resizeMode='contain'
source='[URL here]'
</Image>);
}
Использование "Содержать" с resizeMode: равномерно масштабировать изображение (поддерживать пропорции изображения) так, чтобы оба размера (ширина и высота) изображения были равны или меньше соответствующего размера вида (за вычетом отступов).
Обновление: * К сожалению, похоже, что есть общая ошибка с resizeMode "содержать", в частности, при использовании реактивного натива для Android: https://github.com/facebook/react-native/pull/5738 *
Я попробовал подход Image.getSize, но у меня были проблемы, так как мы собираем все ссылки на изображения в конфигурационном файле, а затем передаем ImageURISource в исходную базу Image.
Моим решением для этого было подождать обратного вызова Image onLayout, чтобы получить свойства макета и использовать его для обновления измерений. Я создал компонент для этого:
import * as React from 'react';
import { Dimensions, Image, ImageProperties, LayoutChangeEvent, StyleSheet, ViewStyle } from 'react-native';
export interface FullWidthImageState {
width: number;
height: number;
stretched: boolean;
}
export default class FullWidthImage extends React.Component<ImageProperties, FullWidthImageState> {
constructor(props: ImageProperties) {
super(props);
this.state = { width: 100, height: 100, stretched: false };
}
render() {
return <Image {...this.props} style={this.getStyle()} onLayout={this.resizeImage} />;
}
private resizeImage = (event: LayoutChangeEvent) => {
if (!this.state.stretched) {
const width = Dimensions.get('window').width;
const height = width * event.nativeEvent.layout.height / event.nativeEvent.layout.width;
this.setState({ width, height, stretched: true });
}
};
private getStyle = (): ViewStyle => {
const style = [StyleSheet.flatten(this.props.style)];
style.push({ width: this.state.width, height: this.state.height });
return StyleSheet.flatten(style);
};
}
Это обновит размеры изображения в соответствии с шириной экрана.
Вы можете использовать что-то вроде этого:
<View style={{height:200}} >
<Image source={require('image!MyImage') style={{ resizeMode:Image.resizeMode.ratio, flex:1 }}} />
</View>
Пожалуйста, обратите внимание, что вам все еще нужно установить высоту на контейнере вида.