如何在React Native中强制图片全宽并保持纵横比?

36

我有一张从URL中获取的图片,但我事先不知道这张图片的尺寸。

如何布局样式,使其为父视图的全宽,并计算高度以保持纵横比例?

我曾经在0.34.0-rc.0版本中尝试使用onLoad,但event.nativeEvent.source中的高度和宽度都是0。

这个图片在一个<ScrollView/>中。我的目标不是全屏显示这张图片。


1
调整大小模式:'cover' 还是 'contain'? - dv3
我无法在没有设置高度的情况下使用“cover”或“contain”。有什么想法吗? - Alex Curtis
啊,关于将它们设置为null并使用flex的奇怪问题...我认为你会在这里找到答案:https://dev59.com/c10b5IYBdhLWcg3wUP4X - dv3
为什么不能在CSS中完成这个操作?https://dev59.com/v2cs5IYBdhLWcg3wRB3h - TylerH
这个回答解决了你的问题吗?在React Native中添加全屏背景图片的最佳方法是什么 - TylerH
显示剩余2条评论
8个回答

37

我的用法非常类似,我需要显示一张图像,使其具有全屏宽度,但同时又要保持其纵横比

基于@JasonGaare的答案,我得出了以下实现:

class PostItem extends React.Component {

  state = {
    imgWidth: 0,
    imgHeight: 0,
  }

  componentDidMount() {

    Image.getSize(this.props.imageUrl, (width, height) => {
      // calculate image width and height 
      const screenWidth = Dimensions.get('window').width
      const scaleFactor = width / screenWidth
      const imageHeight = height / scaleFactor
      this.setState({imgWidth: screenWidth, imgHeight: imageHeight})
    })
  }

  render() {

    const {imgWidth, imgHeight} = this.state

    return (
      <View>
        <Image
          style={{width: imgWidth, height: imgHeight}}
          source={{uri: this.props.imageUrl}}
        />
        <Text style={styles.title}>
          {this.props.description}
        </Text>
      </View>
    )
  }
}

2
感谢提供代码! 我一直在使用react-native-fit-image组件,但是加载图片时遇到了很多问题,有时无法渲染。我对您的代码进行了唯一的修改,就是Image的样式: <Image style={{width: imgWidth, height: imgHeight}} source={{uri: this.props.imageUrl}} /> - Xavier Ojeda Aguilar
我应该在哪里提及图像的实际 URL? - Somename
'Dimensions' is not defined. - Philipp Ludwig
import { Dimensions } from 'react-native'; - oschvr

25

我是react-native的新手,但我发现可以使用简单的样式来解决这个问题:

imageStyle: {
  height: 300,
  flex: 1,
  width: null}

我的第一个应用程序中的全宽图像:
我的第一个应用程序中的全宽图像

对我来说效果很好。


这似乎确实起作用了。附注:我不得不删除我的resizeMode="contain"。 - Eirik H
4
那怎么回答最初的问题呢?你需要事先知道图像的高度... - Michał Kaczanowicz

8

React Native内置了一个函数Image.getSize(),可以返回图片的宽度和高度。具体详情可以查看此处文档


7

这对我来说是有效的。

import React from 'react'
import { View, Text, Image } from 'react-native'

class Test extends React.Component {
  render() {
    return (
      <View>
        <Image
          source={{ uri: "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQL6goeE1IdiDqIUXUzhzeijVV90TDQpigOkiJGhzaJRbdecSEf" }}
          style={{ height: 200, left: 0, right: 0 }}
          resizeMode="contain"
        />
        <Text style={{ textAlign: "center" }}>Papaya</Text>
      </View>
    );
  }
}

export default Test;

另一种方法是在布局事件之后获取父视图的宽度。
<View 
  style={{ flex: 1}} 
  layout={(event) => { this.setState({ width: event.nativeEvent.layout.width }); }}
/>

当您从布局事件中获取父视图的宽度时,您可以将宽度分配给图像标签。
import React from 'react';
import { View, Image } from 'react-native';

class Card extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      height: 300,
      width: 0
    };
  }
  render() {
    return (
      <View style={{
        flex: 1,
        flexDirection: 'row'
      }}>
        <View style={{ width: 50, backgroundColor: '#f00' }} />
        <View
          style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#fafafa' }}
          onLayout={(event) => { this.setState({ width: event.nativeEvent.layout.width }); }}
        >
          {
            this.state.width === 0 ? null : (
              <Image
                source={{ uri: "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQL6goeE1IdiDqIUXUzhzeijVV90TDQpigOkiJGhzaJRbdecSEf" }}
                style={{ width: this.state.width, height: this.state.height }}
                resizeMode="contain"
              />
            )
          }
        </View>
      </View>
    );
  }
}
export default Card;

2

如果你有一张静态图片,可以像这样使用

import React, { Component } from "react";
import { View, Animated, Image, Dimensions } from "react-native";
import splashScreen from "../../../assets/imgs/splash-screen.png";

export default class MasterPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      fadeAnim: new Animated.Value(0),
      imgWidth: 0,
      imgHeight: 0
    };
  }
  checkLogIn = async () => {
    const width = 533; // set your local image with
    const height = 527; // set your local image height 
    // calculate image width and height
    const screenWidth = Dimensions.get("window").width;
    const scaleFactor = width / screenWidth;
    const imageHeight = height / scaleFactor;
    this.setState({ imgWidth: screenWidth, imgHeight: imageHeight });
  };

  async componentDidMount() {
    Animated.timing(
      // Animate over time
      this.state.fadeAnim, // The animated value to drive
      {
        toValue: 1, // Animate to opacity: 1 (opaque)
        duration: 800, // Make it take a while
        useNativeDriver: true
      }
    ).start(this.checkLogIn);
  }

  render() {
    const { imgWidth, imgHeight, fadeAnim } = this.state;
    return (
      <Animated.View
        style={{
          opacity: fadeAnim,
          backgroundColor: "#ebebeb",
          flex: 1,
          justifyContent: "center",
          alignItems: "center"
        }}
      >
        <View>
          <Image
            source={splashScreen}
            style={{ width: imgWidth, height: imgHeight }}
          />
        </View>
      </Animated.View>
    );
  }
}

0
试试这个: 传入图片的uri和父容器宽度(parentWidth),可以使用const { width } = Dimensions.get("window");,然后就可以自动计算高度,基于宽度和纵横比。
import React, {Component} from 'react';
import FastImage from 'react-native-fast-image';

interface Props {
  uri: string;
  parentWidth: number;
}

interface State {
  calcImgHeight: number;
  width: number
  aspectRatio: number
}

export default class CustomFastImage extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      calcImgHeight: 0,
      width: props.parentWidth,
      aspectRatio: 1
    };
  }
  componentDidUpdate(prevProps: Props){
    const { aspectRatio, width }= this.state
    const { parentWidth} = this.props
   
    if( prevProps.parentWidth !== this.props.parentWidth){
        this.setState({
            calcImgHeight: aspectRatio * parentWidth,
            width: parentWidth
          })
    }
  }
  render() {
    const {calcImgHeight, width} = this.state;
    const {uri} = this.props;
    return (
      <FastImage
        style={{width: width, height: calcImgHeight}}
        source={{
          uri,
        }}
        resizeMode={FastImage.resizeMode.contain}
        onLoad={(evt) =>
          {
              this.setState({
            calcImgHeight: (evt.nativeEvent.height / evt.nativeEvent.width) * width, // By this, you keep the image ratio
            aspectRatio:  (evt.nativeEvent.height / evt.nativeEvent.width), 
          })}
        }
      />
    );
  }
}

0
在我的情况下,我通过这样更改图像的宽高比和弹性来使其工作。

flex:1,aspectRatio:1.2, height:null


-5

如果你还没有解决这个问题,React Native v.0.42.0有一个resizeMode属性

<Image style={styles.intro_img} source={require('img.png')} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接