web-dev-qa-db-fra.com

Ajuster automatiquement la hauteur de l'image avec React Native

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???<<<
  }
)
28
plmok61

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.

29
TheJizel

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

3
Nedko Dimitrov

Jetez un oeil à cette bibliothèque react-native-scalable-image . Il fait exactement ce que vous demandez.

2
Ihor Burlachenko

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.

1
Thomas Praxl

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.

1
Haitao Li

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}/>
1
KlimczakM

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
    };
0
josesuero