J'essaie d'obtenir l'effet suivant dans React Native:
L'image a un bouton dans le coin. Le bouton se trouve toujours dans le coin de l'image, quels que soient sa taille ou son rapport de format, et aucune partie de l'image n'est coupée (il est toujours réduit pour s'ajuster parfaitement à un cadre).
Le problème que j'ai dans React Native, c'est que la taille du composant Image ne correspond pas toujours à la taille réduite de l'image. Si je fixe la hauteur de l’image à 300, définissez flex 1 pour que la largeur de l’image s’agrandisse de manière à remplir tout son contenu et que l’image est en mode portrait, le composant Image ayant la largeur totale du conteneur, mais l’image dans le composant aura un largeur de beaucoup moins. Par conséquent, l'approche habituelle consistant à superposer une vue à une autre ne fonctionne pas car je souhaiterais qu'elle me recouvre également le remplissage autour de l'image et le bouton (ancré dans le coin) apparaît à l'extérieur de l'image.
Voici à quoi cela ressemble dans React Native:
Le X est un espace réservé pour le bouton. Il est défini pour s'ancrer dans le coin supérieur gauche d'une vue qui est un enfant de la même vue que l'image est un enfant de. La couleur d'arrière-plan de l'image est définie sur vert pour montrer en quoi la largeur du composant Image est différente de la largeur de l'image à l'intérieur du composant.
L'objectif est que le X se trouve à l'intérieur de l'image, quel que soit son rapport de format. Je pense que je pourrais faire quelque chose en prenant la dimension de l'image et en mettant à l'échelle la hauteur et la largeur du composant Image, mais cela semble complexe et fragile. Est-ce possible d'une manière réactive avec le style?
Code de démonstration:
<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>
De React-native v0.50.0 <Image>
avec le contenu imbriqué n'est plus pris en charge. Utilisez <ImageBackground>
à la place.
<ImageBackground
source={imageSource}
>
<View>
<Text>×</Text>
</View>
</ImageBackground>
Nous pouvons utiliser des images d'affichage <Image/>
, et nous pouvons l'utiliser comme un hack background-image
.
essaye ça
<Image
source={imageSource}
>
<View>
<Text>×</Text>
</View>
</Image>
this Gist est une démonstration complète pour vos besoins.
ou vous pouvez le voir en direct à l'expo:
<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>
Ainsi, comme @ObooChin l’a mentionné, vous devez utiliser Image.getSize () pour obtenir la taille réelle de l’image, puis générer une hauteur et une largeur basées sur a) l’espace maximal que vous souhaitez que l’image prenne, et b) les proportions des dimensions réelles de l'image.
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 />
)
}
}
La tentative est toujours un peu rude, mais je travaille à transformer cela en une bibliothèque où vous pouvez spécifier la hauteur maximale, la largeur et la superposition que vous souhaitez utiliser, et elle gère le reste: https: // github. com/nudgeyourself/react-native-flexible-thumbnail .
Voici comment j'ai accompli cela:
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"
}
});
Voici à quoi ça ressemble: