Dans mon application native React, je récupère les images d'une API aux dimensions inconnues. Comment puis-je redimensionner automatiquement la hauteur si je connais la largeur souhaitée?
Exemple:
Je règle la largeur sur Dimensions.get('window').width
. Comment définir la hauteur et conserver le même rapport?
export default class MyComponent extends Component {
constructor(props) {
super(props)
this.state = {
imgUrl: 'http://someimg.com/coolstuff.jpg'
}
}
componentDidMount() {
// sets the image url to state
this.props.getImageFromAPi()
}
render() {
return (
<View>
<Image
source={uri: this.state.imgUrl}
style={styles.myImg}
/>
<Text>Some description</Text>
</View>
)
}
}
const styles = StyleSheet.create(
myImg: {
width: Dimensions.get('window').width,
height: >>>???what goes here???<<<
}
)
Essaye ça:
import React, { Component, PropTypes } from "react";
import { Image } from "react-native";
export default class ScaledImage extends Component {
constructor(props) {
super(props);
this.state = { source: { uri: this.props.uri } };
}
componentWillMount() {
Image.getSize(this.props.uri, (width, height) => {
if (this.props.width && !this.props.height) {
this.setState({
width: this.props.width,
height: height * (this.props.width / width)
});
} else if (!this.props.width && this.props.height) {
this.setState({
width: width * (this.props.height / height),
height: this.props.height
});
} else {
this.setState({ width: width, height: height });
}
});
}
render() {
return (
<Image
source={this.state.source}
style={{ height: this.state.height, width: this.state.width }}
/>
);
}
}
ScaledImage.propTypes = {
uri: PropTypes.string.isRequired,
width: PropTypes.number,
height: PropTypes.number
};
Je passe l'URL comme un accessoire appelé uri
. Vous pouvez spécifier votre prop width
comme Dimensions.get('window').width
et cela devrait le couvrir.
Notez que cela fonctionnera également si vous savez en quoi vous souhaitez définir la hauteur et si vous devez redimensionner la largeur pour conserver le rapport. Dans ce cas, vous spécifieriez la propriété height
au lieu de celle width
.
Il y a une propriété resizeMode définie sur 'contenir'
Exemple:
<Image
source={require('./local_path_to/your_image.png')}
style={{ width: 30 }}
resizeMode="contain"
/>
Source: https://facebook.github.io/react-native/docs/image#resizemode
Jetez un oeil à cette bibliothèque react-native-scalable-image . Il fait exactement ce que vous demandez.
Voici un résumé d'une solution assez simple qui exploite la proposition de -Haitao Li d'utiliser aspectRatio:
https://Gist.github.com/tpraxl/02dc4bfcfa301340d26a0bf2140cd8b9
Pas de magie et pas de calculs nécessaires. Pure "CSS" si vous connaissez les dimensions de l'image d'origine.
Essayez d’abord et voyez si cela fonctionne pour vous: https://github.com/facebook/react-native/commit/5850165795c54b8d5de7bef9f69f6fe6b1b4763d
Si ce n'est pas le cas, vous pouvez alors implémenter votre propre composant image. Mais au lieu de prendre la largeur comme accessoire, vous substituez la méthode onLayout
qui vous donne la largeur souhaitée afin que vous puissiez calculer la hauteur. Cela fonctionne mieux si vous ne connaissez pas la largeur et souhaitez que RN réalise la mise en page à votre place. L'inconvénient est que onLayout
est appelé après un passage de mise en page et de rendu. Donc, vous remarquerez peut-être que vos composants bougent un peu.
TypeScript version de @TheJizel answer avec propriété style
facultative et rappel failure
dans Image.getSize
:
import * as React from 'react'
import {Image} from 'react-native'
interface Props {
uri: string
width?: number
height?: number
style?
}
interface State {
source: {}
width: number
height: number
}
export default class ScaledImage extends React.Component<Props, State> {
constructor(props) {
super(props)
this.state = {
source: {uri: this.props.uri},
width: 0,
height: 0,
}
}
componentWillMount() {
Image.getSize(this.props.uri, (width, height) => {
if (this.props.width && !this.props.height) {
this.setState({width: this.props.width, height: height * (this.props.width / width)})
} else if (!this.props.width && this.props.height) {
this.setState({width: width * (this.props.height / height), height: this.props.height})
} else {
this.setState({width: width, height: height})
}
}, (error) => {
console.log("ScaledImage:componentWillMount:Image.getSize failed with error: ", error)
})
}
render() {
return <Image source={this.state.source} style={[this.props.style, {height: this.state.height, width: this.state.width}]}/>
}
}
Exemple d'utilisation:
<ScaledImage style={styles.scaledImage} uri={this.props.article.coverImageUrl} width={Dimensions.get('window').width}/>
La solution proposée fonctionne, mais vous devez télécharger l'image deux fois, une fois pour déterminer la taille et une autre pour afficher l'image. Il s'agit d'une approche différente, l'image est d'abord chargée au carré et redimensionnée.
import React, { Component, } from "react";
import { Image } from "react-native";
import PropTypes from 'prop-types'
export default class ScaledImage extends Component {
state = {}
componentWillMount() {
const { uri, width, height } = this.props;
this.setState({ source: { uri }, width: width || height, height: height || width });
}
render() {
return (
<Image
source={this.state.source}
onLoad={(value) => {
const { height, width } = value.nativeEvent.source;
if (this.props.width && !this.props.height) {
this.setState({
width: this.props.width,
height: height * (this.props.width / width)
});
} else if (!this.props.width && this.props.height) {
this.setState({
width: width * (this.props.height / height),
height: this.props.height
});
} else {
this.setState({ width: width, height: height });
}
}}
style={{ height: this.state.height, width: this.state.width }}
/>
);
}
}
ScaledImage.propTypes = {
uri: PropTypes.string.isRequired,
width: PropTypes.number,
height: PropTypes.number
};