【问题标题】:Overlay button on top of Image in React NativeReact Native 中图像顶部的叠加按钮
【发布时间】:2018-03-16 13:04:00
【问题描述】:

我正在尝试在 React Native 中实现如下效果:

图片的角落有一个按钮。无论图像的大小或纵横比如何,按钮始终位于图像的一角,并且图像的任何部分都不会被剪裁(始终按比例缩小以完全放入框内)。

我在 React Native 中遇到的问题是 Image 组件的大小并不总是与图像的缩小尺寸相匹配。如果我将图像的高度固定为 300,设置 flex 1 以使图像的宽度扩大以填充其内容,并且图像是肖像,Image 组件具有容器的全宽,但组件内的图像将具有宽度要小得多。因此,让一个视图覆盖另一个视图的典型方法并不像我希望的那样工作 - 我的覆盖还覆盖了图像周围的填充,并且按钮(锚定到角落)出现在图像之外。

这是 React Native 中的样子:

X 是按钮的占位符。它被设置为锚定到 View 的左上角,该 View 是 Image 的子视图的子视图。图片的 backgroundColor 设置为绿色,以演示 Image 组件的宽度与组件内部图片的宽度有何不同。

目标是无论纵横比如何,X 都将位于图像内部。我想我可以基于抓取图像的尺寸并缩放 Image 组件的高度和宽度来做一些事情,但这听起来既复杂又脆弱。这是否可以通过样式响应的方式实现?

演示代码:

   <View
      style={{
        marginLeft: 7,
        marginRight: 7,
        backgroundColor: 'blue',
      }}
    >
      <View
        style={{
          height: 300,
          flex: 1,
        }}
      >
        <Image
          source={imageSource}
          style={{
            flex: 1,
            height: undefined,
            width: undefined,
            backgroundColor: 'green',
          }}
          resizeMode="contain"
        />
      </View>
      <View
        style={{
          position: 'absolute',
          right: 5,
          top: 5,
          backgroundColor: 'transparent',
        }}
      >
        <Text style={{ color: 'white' }}>X</Text>
      </View>
    </View>

【问题讨论】:

    标签: javascript image react-native


    【解决方案1】:

    不再支持带有嵌套内容的 React-native v0.50.0 &lt;Image&gt;。请改用&lt;ImageBackground&gt;

    <ImageBackground
      source={imageSource}
    >
        <View>
            <Text>×</Text>
        </View>
    </ImageBackground>
    

    【讨论】:

      【解决方案2】:

      我是这样实现的:

      import React, { Component } from "react";
      import { View, Image, StyleSheet } from "react-native";
      import { Ionicons } from "@expo/vector-icons";
      
      class MyCard extends Component {
        render() {
          return (
            <View style={styles.container}>
              <Image
                resizeMode="cover"
                style={styles.cover}
                source={{ uri: "https://picsum.photos/700" }}
              />
              <Ionicons style={styles.close} name="ios-close-circle" size={25} />
            </View>
          );
        }
      }
      
      export default MyCard;
      
      const styles = StyleSheet.create({
        container: {
          margin: 5,
          width: 160,
          height: 200
        },
        cover: {
          flex: 1,
          borderRadius: 5
        },
        close: {
          margin: 5,
          position: "absolute",
          top: 0,
          left: 0,
          width: 25,
          height: 25,
          color: "tomato"
        }
      });
      

      这是它的样子:

      【讨论】:

        【解决方案3】:

        2019 年 6 月 29 日更新

        现在(react-native@0.60-RC)有一个特定的组件可以将元素包装为图像背景,ImageBackground。去官方文档吧。

        以下要点已更改。


        原答案

        我们可以使用&lt;Image/&gt; 显示图像,也可以将其用作background-image hack。

        试试这个

        <Image
          source={imageSource}
        >
          <View>
            <Text>×</Text>
          </View>
        </Image>
        

        this gist 是满足您需求的完整演示。

        或者你可以在展会现场看到它:

        <div data-snack-id="B1SsJ7m2b" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.16);border-radius:4px;height:505px;width:100%"></div>
        <script async src="https://snack.expo.io/embed.js"></script>

        【讨论】:

        • 谢谢;我很欣赏这个详尽的例子。不幸的是,这将图像限制为固定的纵横比。如果图像是 3x2 肖像,它看起来很完美,但如果它是 2x3 或 4x3 或其他图像,则图像会被截断。我真的很想找到可以调整图像纵横比的东西,而不必确定图像尺寸并根据它们计算自定义宽度和高度(或者至少找出如果不这样做是不可能的) .
        • 你好,你的意思是你想要这样的布局并根据图像缩放宽度和高度?没问题。Image组件有一个名为Image.getSize的静态方法,你可以得到图像的宽度和高度,然后你可以设置一个固定的宽度,然后计算组件的高度,然后你可以像Pinterest一样做一个流动的图像布局。如果你需要一个详细的例子,请随时回复。谈论调整大小而不重新计算,有没办法做这种事。
        • 异常:错误: 组件不能包含子组件。如果要在图像顶部渲染内容,请考虑使用绝对定位。在本机反应”:“0.51.0”
        • @StanislauBuzunko 是的,团队在发布 0.50 时更改了这一点,发布说明 here,改用 ImageBackground 组件。Reference here
        • @ObooChin 你在 Image.getSize() 上是对的。将发布一个更深入的示例。感谢您的提示!
        【解决方案4】:

        因此,正如@ObooChin 提到的那样,您执行此操作的方式是使用 Image.getSize() 获取图像的实际大小,然后根据 a) 您希望图像的最大空间生成高度和宽度占用,以及 b) 实际图像尺寸的纵横比。

        import React, { Component } from 'react';
        import {
          StyleSheet,
          Image,
          View,
          Dimensions,
        } from 'react-native';
        
        export default class FlexibleThumbnail extends Component {
        
            constructor(props) {
                super(props)
        
                this.state = {
                    imageWidth: 0,
                    imageHeight: 0,
                    source: null,
                }
            }
        
            componentWillMount() {
                this._updateState(this.props)
            }
        
            componentWillReceiveProps(nextProps) {
                this._updateState(nextProps)
            }
        
            _updateState(props) {
                const {source} = props;
                const height = props.maxHeight;
                const width = props.maxWidth || Dimensions.get('window').width;
        
                const imageUri = source.uri;
        
                Image.getSize(imageUri, (iw, ih) => {
                    const {imageWidth, imageHeight} = /* some function that takes max height, width and image height, width and outputs actual dimensions image should be */
        
                    this.setState({
                        imageWidth,
                        imageHeight,
                        source,
                    });
                });
            }
        
            render() {
                const {source, height, width, imageWidth, imageHeight} = this.state;
        
                const overlay = (/* JSX for your overlay here */);
        
                // only display once the source is set in response to getSize() finishing
                if (source) {
                    return (
                        <View style={{width: imageWidth, height: imageHeight}} >
                            <Image
                                style={[ imageStyle, {width: imageWidth, height: imageHeight} ]}
                                resizeMode="contain"
                                source={source}
                            />
                                <View style={{
                                    position: 'absolute',
                                    top: 0,
                                    bottom: 0,
                                    left: 0,
                                    right: 0,
                                    backgroundColor: 'transparent',
                                }}>
                                    {overlay}
                                </View>
                        </View>
                    );
                }
        
                return (
                    <View />
                )
            }
        }
        

        尝试仍然有点粗糙,但我正在努力将其变成一个库,您可以在其中指定最大高度、宽度和要使用的叠加层,其余部分由它处理:https://github.com/nudgeyourself/react-native-flexible-thumbnail

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-06-21
          • 2011-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-16
          • 2021-07-22
          • 2016-07-04
          相关资源
          最近更新 更多