webentwicklung-frage-antwort-db.com.de

Überlagerungstaste über Image in React Native

Ich versuche in React Native den folgenden Effekt zu erzielen:

 image with an icon in the corner

Das Bild hat eine Schaltfläche in der Ecke. Die Schaltfläche befindet sich immer in der Ecke des Bildes, unabhängig von der Bildgröße oder dem Seitenverhältnis. Das Bild wird nicht beschnitten (es wird immer so skaliert, dass es vollständig in eine Box passt).

Das Problem, das ich in React Native habe, ist, dass die Größe der Image-Komponente nicht immer mit der verkleinerten Größe des Image übereinstimmt. Wenn ich die Höhe des Bildes auf 300 festlege, stelle ich Flex 1 ein, um die Breite des Bildes zu vergrößern und den Inhalt zu füllen. Das Bild ist Hochformat. Die Bildkomponente entspricht der gesamten Breite des Containers Breite von viel weniger. Daher funktioniert der typische Ansatz, eine Ansicht mit einer anderen Ansicht zu überlagern, nicht wie gewünscht - meine Überlagerung deckt auch die Auffüllung um das Bild ab, und die Schaltfläche (an der Ecke verankert) wird außerhalb des Bildes angezeigt.

So sieht es in React Native aus:

 portrait image with button overlay in React Native

Das X ist ein Platzhalter für die Schaltfläche. Es wird so festgelegt, dass es links oben in einer Ansicht verankert ist, die ein Kind derselben Ansicht ist, von der das Bild ein Kind ist. Die backgroundColor des Bildes ist auf grün gesetzt, um zu zeigen, wie sich die Breite der Image-Komponente von der Breite des Bildes in der Komponente unterscheidet.

Das Ziel ist, dass sich das X unabhängig vom Seitenverhältnis im Bild befindet. Ich denke, ich könnte etwas tun, indem ich die Bildgröße erhalte und die Höhe und Breite der Bildkomponente skaliere, aber das klingt kompliziert und fragil. Ist das mit dem Styling responsiv möglich?

Demonstrationscode:

<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>

5
Keith Kurak

Ab react-native v0.50.0 wird <Image> mit verschachteltem Inhalt nicht mehr unterstützt. Verwenden Sie stattdessen <ImageBackground>.

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

Wir können <Image/> Anzeigebilder verwenden und wir können es als background-image-Hack verwenden.

versuche dies

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

dieser Gist ist eine vollständige Demo für Ihre Bedürfnisse.

oder Sie können es live auf der Expo sehen:

<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>

1
Oboo Chin

Wie @ObooChin dies erwähnt, verwenden Sie Image.getSize (), um die tatsächliche Größe des Bildes zu ermitteln und dann eine Höhe und Breite zu generieren, basierend auf a) dem maximalen Platz, den das Bild beanspruchen soll. und b) das Seitenverhältnis der tatsächlichen Bildabmessungen.

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 />
        )
    }
}

Der Versuch ist immer noch etwas grob, aber ich arbeite daran, daraus eine Bibliothek zu machen, in der Sie die maximale Höhe, Breite und das Overlay angeben können, das Sie verwenden möchten, und den Rest erledigt: https: // github. com/nudgeyourself/reag-native-flexible-thumbnail .

0
Keith Kurak

So habe ich das geschafft:

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"
  }
});

So sieht es aus:

 enter image description here

0
Ozesh