代码之家  ›  专栏  ›  技术社区  ›  kojow7

在React Native中按比例缩放图像并添加边框

  •  0
  • kojow7  · 技术社区  · 5 年前

    我试图创建一个有边框的图像。它本身工作得很好,但是,我想通过使用 resizeMode='contain' 选项。这样做的问题是,边框填充了它所包含的父元素的整个宽度,而不仅仅是图片周围。我的代码如下:

    const styles = {
         image: {
              borderColor: 'black',
              borderStyle: 'solid',
              borderWidth: 5,
              width: '100%',
              height: '100%' 
         }
    }
    

    还有。。。

    <View style={{height: 200}}>
        <Image resizeMode='contain' style={styles.image} source={require('myimage.jpg')} />
    </View>
    

    我假设边框使用原始的“100%”填充容器大小。我该怎么做才能使图像按比例调整到200的高度,并在其周围设置边框?

    0 回复  |  直到 5 年前
        1
  •  1
  •   Farhan Tanvir    5 年前
    <View style={{height: 200 , borderWidth : 5 , borderColor: 'black',borderStyle: 'solid'}}>
       <Image resizeMode='contain' style={{width: 195 , height : 195 }} source={require('myimage.jpg')} />
    </View>
    

    在视图样式中指定borderWidth,然后从图像的高度和宽度中减去borderWidth。希望这能有所帮助。

        2
  •  0
  •   Christos Lytras    5 年前

    不可能对图像应用比例边框 resizeMode: 'contain' 。您可以使用 Dimensions Image.resolveAssetSource ( 用于捆绑图像 )计算纵横比并精确调整图像宽度和高度:

    In componentDidMount 或在 useEffect :

    const [width, setWidth] = useState(0);
    const [height, setHeight] = useState(0);
    
    useEffect(() => {
      const { width, height } = Image.resolveAssetSource(require('./assets/lambo.jpg'));
      const winSize = Dimensions.get('window');
    
      setWidth(winSize.width);
      setHeight((winSize.width / width) * height);
    }, []);
    

    然后渲染它:

    return (
      <View style={styles.container}>
        <Image source={require('./assets/lambo.jpg')} style={[styles.image, { width, height }]}/>
      </View>
    );
    

    样式:

    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        borderWidth: 5,
        borderColor: 'red'
      },
      image: {
        borderWidth: 5,
        borderColor: 'green',
      }
    });
    

    将得到以下结果:

    RN image proportionally border

        3
  •  0
  •   Max    5 年前

    有一种方法可以使用远程图像,而不依赖于全屏宽度测量。首先,您需要确定调整大小的图像不应跨越的图像组件的边界。它本质上是定义 width height 其中将包含图像。我把这些当作 宽度 高度 道具 ImageWithBorders (屏幕截图上的绿色边框)

    之后,您可以通过以下方式获取远程图像尺寸 Image.getSize ,计算比率并进行一些数学运算,以确定视图的适当视图尺寸

    class ImageWithBorders extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          // image wrapper dimensions
          iWidth: null,
          iHeight: null,
          // image dimensions
          iiWidth: null,
          iiHeight: null,
          // outer wrapper dimensions
          vWidth: null,
          vHeight: null
        }
      }
    
      componentDidMount() {
        Image.getSize(this.props.source,
          (iWidth, iHeight) => {
            this.setState({ iWidth, iHeight })
          }
        )
      }
    
      // using onLayout in case non-numeric dimensions were passed
      _onLayout = ({ nativeEvent: { layout: { height, width } } }) => {
        this.setState({ vWidth: width, vHeight: height })
      };
    
      componentDidUpdate(prevProps, prevState) {
        const {
          iWidth: oldiWidth,
          iHeight: oldiHeight,
          vWidth: oldvWidth,
          vHeight: oldvHeight
        } = prevState
        const {
          iWidth,
          iHeight,
          vWidth,
          vHeight
        } = this.state
        if (oldiWidth === null || oldiHeight === null || oldvWidth === null || oldvHeight === null) {
          if (iWidth && iHeight && vWidth && vHeight) {
            // at this moment both view and remote image were measured
            // now use some math to calculate proper sizes for all views
            const { borderWidth } = this.props
            const border2 = borderWidth * 2
            if (vWidth - border2 < vHeight - border2) {
              const newImageWidth = vWidth - border2
              const imageRatio = iHeight / iWidth
              const newImageHeight = newImageWidth * imageRatio
              this.setState({
                iHeight: newImageHeight + border2,
                iWidth: vWidth,
                iiHeight: newImageHeight,
                iiWidth: newImageWidth,
                measured: true
              })
            } else {
              const newImageHeight = vHeight - border2
              const imageRatio = iHeight / iWidth
              const newImageWidth = newImageHeight / imageRatio
              this.setState({
                iHeight: vHeight,
                iWidth: newImageWidth + border2,
                iiHeight: newImageHeight,
                iiWidth: newImageWidth,
                measured: true
              })
            }
          }
        }
      }
    
      render() {
        const { source, height = 0, width = 0, resizeContainer = false } = this.props
        const outerWidth = resizeContainer ? this.state.measured ? this.state.iWidth : width : width
        const outerHeight = resizeContainer ? this.state.measured ? this.state.iHeight : height : height
        return (
          <View
            style={{
              width: outerWidth,
              height: outerHeight,
              borderWidth: 1,
              borderColor: 'green',
              alignItems: 'center',
              justifyContent: 'center'
            }}
            onLayout={this._onLayout}
          >
            <View
              style={{
                width: this.state.iWidth || 0,
                height: this.state.iHeight || 0,
    
                backgroundColor: 'red',
                alignItems: 'center',
                justifyContent: 'center'
              }}
            >
              <Image
                source={source}
                style={{
                  width: this.state.iiWidth,
                  height: this.state.iiHeight,
                }}
                resizeMode={'contain'}
              />
            </View>
          </View>
        )
      }
    }
    

    这样使用它

    const App = () => {
      return (
        <View
          style={{
            alignItems: 'center',
            justifyContent: 'center',
            ...StyleSheet.absoluteFillObject
          }}
        >
          <ImageWithBorders
            source={{ uri: 'https://i.imgur.com/BWrNPE4.png' }}
            borderWidth={13}
            height={400}
            width={260}
            resizeContainer={false} // or true
          />
          <ImageWithBorders
            source={{ uri: 'https://i.imgur.com/BWrNPE4.png' }}
            borderWidth={5}
            height={100}
            width={260}
            resizeContainer={false} // or true
          />
        </View>
      )
    }
    

    resizeContainer 道具会将图像调整到最终的宽度和高度,而不是在关闭时保持原始的宽度和高

    树脂容器 设置为false:

    with resizeContainer set to false

    树脂容器 设置为true:

    with resizeContainer set to true

    当然,这只是一个最小的工作示例。您可能希望添加其他功能,例如在样式中传递宽度和高度、更改边框颜色,以及在道具动态更改时重新运行计算(现在它只会调整一次大小,如果您在运行时更改borderWidth等,它将不会再次调整大小)