在“反应本机”中维护全宽图像的纵横比

我有个关于标签的问题。我想要一个图像采取整个宽度的父,我使用 alignSelf: 伸展,但我也希望高度是根据图像的纵横比。我怎么才能做到这样呢?

所以我想要一种方法来指定高度作为图像宽度的比例。

127515 次浏览

You may use something like this:

<View style=\{\{height:200}} >
<Image source={require('image!MyImage') style=\{\{ resizeMode:Image.resizeMode.ratio, flex:1 }}} />
</View>

Please not that you still have to set the height on the view container.

Typically, doing the following would give us an image rendered to max width/height depending on orientation while maintaining the aspect ratio of the image itself:

render(){
return(<Image style=\{\{'width': Dimensions.get('window').width,
'height': Dimensions.get('window').height}}
resizeMode='contain'
source='[URL here]'
</Image>);
}

Using 'contain' with resizeMode: 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).

Update: * Unfortunately, it seems that there is a common bug with resizeMode's 'contain' specifically when using react native for Android: https://github.com/facebook/react-native/pull/5738*

You can calculate the image height based on the width/height ratio.

So if the image originally is 200x100, after setting its resizeMode to stretch:

var deviceWidth: Dimensions.get('window').width;


...


myImage {
width: deviceWidth,
height: deviceWidth * 0.5
}

I know maybe it is not the best practice, but it helped me a lot with images of all sizes that needed to mantain a certain relation with other images, etc.

It's actually pretty simple.

The Image class has a getSize method. [1]

Let's say that you've created a component for your aspectRatioImage and you calculate the appropriate values every time componentWillMount fires.

Then your code would look something like this:

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);
});
}

So now that the image height and width are saved in your component's state, you can just run

 <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

You can use react-native-scalable-image. The following example will do the job:

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>'}} />;

I like bdv's approach and I use this kind of images almost everywhere in my app. That's why I created an own component which is using onLayout to also support device rotation.

import resolveAssetSource from "resolveAssetSource";
import React, { useCallback, useState } from "react";
import { Image, View } from "react-native";


export default function FullWidthImage(props) {
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);


const onLayout = useCallback((event) => {
const containerWidth = event.nativeEvent.layout.width;


if (props.ratio) {
setWidth(containerWidth);
setHeight(containerWidth * props.ratio);
} else if (typeof props.source === "number") {
const source = resolveAssetSource(props.source);


setWidth(containerWidth);
setHeight(containerWidth * source.height / source.width);
} else if (typeof props.source === "object") {
Image.getSize(props.source.uri, (w, h) => {
setWidth(containerWidth);
setHeight(containerWidth * h / w);
});
}
}, [props.ratio, props.source]);


return (
<View onLayout={onLayout}>
<Image
source={props.source}
style=\{\{ width, height }} />
</View>
);
}

You can use it like this:

<FullWidthImage source=\{\{ uri: "http://example.com/image.jpg" }} />
<FullWidthImage source={require("./images/image.jpg")} />

Or if you know the ratio like this:

<FullWidthImage source=\{\{ uri: "http://example.com/image.jpg"}} ratio={0.5} />
<FullWidthImage source={require("./images/image.jpg")} ratio={0.5} />

I tried the Image.getSize approach, but had problems, since we gather all the image links in a config file and then pass the ImageURISource into the source prop of the Image.

My solution for that was to wait for the Image onLayout callback to get it's layout properties and use that to update the dimensions. I created a component for that:

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);
};
}

This will update the dimensions of the image to match the width of the screen.

Use style=\{\{ aspectRatio: 3/2 }} for a horizontal image with width to height ratio of 3:2.

Docs: https://reactnative.dev/docs/layout-props#aspectratio

(Available in RN 0.40+)

<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,
},


});

In my case i also had to set height to 'auto' :

{
width: 200,
height: 'auto',
aspectRatio: 16 / 9,
}

Use resizeMode='contain'

<Image style=\{\{height:'100%', width:'100%'}} resizeMode="contain" source=\{\{uri:this.state.imgSource}} />

This will keep the original aspect ratio, with given width and height as max-height and max-width.

In my case, I am using Styled Components in my React Native (v0.62+) project.

I needed to specify a square aspectRatio for Image components that had a defined width and undefined height.

I found that styling height:0; achieved the "square image" result that I wanted:

// Gallery container styled-component
const Gallery = styled.View`
flexDirection:row;
flexWrap:wrap;
`


// Square half-width image styled-component
const Photo = styled.Image`
width:50%;
height:0;
aspectRatio:1;
`

This method also works for full width image styling - replacing width:50% with width:100% produces the expect result with correct aspect ratio of each image.

const RespImage = ({ offer }) => {


const [height, setHeight] = useState(0);
const [width, setWidth] = useState(0);


let image_url = `YOUR_IMAGE_URI`;


Image.getSize(image_url, (srcWidth, srcHeight) => {


const maxHeight = Dimensions.get('window').height;
const maxWidth = Dimensions.get('window').width;


const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
setHeight(srcHeight * ratio);
setWidth(srcWidth * ratio);
});


return (
<View>
<Image resizeMode={'contain'} style=\{\{ height: height, width: width, marginBottom: 20, resizeMode: "contain" }}
source=\{\{ uri: image_url }}
/>
</View>
)

}

With resizeMode='contain' and flex=1 I get the image in full width while keeping the aspect ratio.

  <Image
source=\{\{ uri: 'URI' }}
resizeMode="contain"
style=\{\{flex:1}} />

The image need to be in a container View with flex or height defined, so the flex of the image can work.

Give aspectRatio and width to the parent view and add width and height 100% to the Image If you want an image with width of 100 and height of 50

<View style=\{\{ width: 100, aspectRatio: 2 }}>
<Image
source=\{\{ uri: '' }}
style=\{\{
width: '100%',
height: '100%'
}}/>
</View>