Comment définir la couleur d'arrière-plan de la vue transparente dans React Native

139

C'est le style de vue que j'ai utilisé

backCover: {
  position: 'absolute',
  marginTop: 20,
  top: 0,
  bottom: 0,
  left: 0,
  right: 0,
}

Actuellement, il a un fond blanc. Je peux changer le backgroundColor comme je veux, '#343434'mais il n'accepte que la valeur hexadécimale maximale de 6 pour la couleur, donc je ne peux pas donner d'opacité à ce sujet '#00ffffff'. J'ai essayé d'utiliser l'opacité comme celle-ci

backCover: {
  position: 'absolute',
  marginTop: 20,
  top: 0,
  bottom: 0,
  left: 0,
  right: 0,
  opacity: 0.5,
}

mais cela réduit la visibilité du contenu de la vue. Alors des réponses?

JEROM JOY
la source

Réponses:

288

Utilisez la rgbavaleur pour le backgroundColor.

Par exemple,

backgroundColor: 'rgba(52, 52, 52, 0.8)'

Celui - ci définit une couleur grise avec une opacité de 80%, qui est dérivée de la virgule d'opacité, 0.8. Cette valeur peut être n'importe quoi de 0.0à 1.0.

dieuvn3b
la source
pourquoi diable les valeurs de couleur sont-elles 8 bits et les valeurs alpha flottent?
duhaime
@duhaime, je ne sais pas pourquoi spécifiquement, mais 8 bits a du sens du point de vue de la mémoire (surtout historiquement). Les valeurs alpha ont plus de sens d'avoir 0 et 1 comme min et max pour totalement transparent ou totalement opaque. Par exemple, si vous voulez que quelque chose soit transparent à 25%, vous ne voulez pas savoir ce qu'est 1 / 4e de 255.
kojow7 le
104

Ce qui suit fonctionne très bien:

backgroundColor: 'rgba(52, 52, 52, alpha)'

Vous pouvez également essayer:

backgroundColor: 'transparent'
JEROM JOY
la source
2
backgroundColor: «transparent» est de loin la solution la plus simple.
NathanL
27

Essayez ceci, backgroundColor: '#00000000' il définira la couleur d'arrière-plan sur transparent, il suit les codes hexadécimaux #rrggbbaa

Tharzeez
la source
Pour une raison quelconque, cette variante affiche la couleur du résultat avec une opacité incorrecte. Si je ne me trompe pas, c'est un bug dans RN. Il vaut donc mieux utiliser le rgbachemin.
Shyngys Kassymov
1
@ShyngysKassymov gist.github.com/lopspower/03fb1cc0ac9f32ef38f4 vérifier ceci
Oo
@Oo intéressant, c'est logique. Merci de l'avoir signalé! Mais l'OMI, c'est plus facile d'utiliser la rgbamanière :)
Shyngys Kassymov
cela signifie-t-il que le format devrait être #aarrggbb à la place?
Shyngys Kassymov le
Je voulais dire que vous pouvez utiliser l'hexavalue rrggbbaa.
Oo
3

Vous devez être conscient des conflits actuels qui existent avec les arrière-plans iOS et RGBA.

Résumé: public React Native expose actuellement les propriétés d'ombre de la couche iOS plus ou moins directement, mais cela pose un certain nombre de problèmes:

1) Les performances lors de l'utilisation de ces propriétés sont médiocres par défaut. En effet, iOS calcule l'ombre en obtenant le masque de pixel exact de la vue, y compris tout contenu transparent, et toutes ses sous-vues, ce qui est très gourmand en CPU et en GPU. 2) Les propriétés d'ombre d'iOS ne correspondent pas à la syntaxe ou à la sémantique de la norme CSS box-shadow, et il est peu probable qu'elles soient implémentées sur Android. 3) Nous n'exposons pas la layer.shadowPathpropriété, ce qui est crucial pour obtenir de bonnes performances des ombres de calque.

Cette différence résout le problème numéro 1) en implémentant une valeur par défaut shadowPathqui correspond à la bordure de la vue pour les vues avec un arrière-plan opaque. Cela améliore les performances des ombres en optimisant le cas d'utilisation courant. J'ai également rétabli la propagation de la couleur d'arrière-plan pour les vues qui ont des accessoires d'ombre - cela devrait aider à garantir que ce meilleur scénario se produise plus souvent.

Pour les vues avec un arrière-plan transparent explicite, l'ombre continuera à fonctionner comme avant (elle ne shadowPathsera pas définie et l'ombre sera dérivée exactement des pixels de la vue et de ses sous-vues). Cependant, il s'agit du pire des cas pour les performances, vous devez donc l'éviter à moins que cela ne soit absolument nécessaire. La prise en charge de cela peut être désactivée par défaut à l'avenir, ou supprimée complètement.

Pour les images translucides, il est suggéré de cuire l'ombre dans l'image elle-même ou d'utiliser un autre mécanisme pour pré-générer l'ombre. Pour les ombres de texte, vous devez utiliser les propriétés textShadow, qui fonctionnent sur plusieurs plates-formes et offrent de bien meilleures performances.

Le problème numéro 2) sera résolu dans un futur différentiel, éventuellement en renommant les propriétés iOS shadowXXX en boxShadowXXX, et en modifiant la syntaxe et la sémantique pour correspondre aux normes CSS.

Le problème numéro 3) est maintenant presque sans objet, puisque nous générons automatiquement le shadowPath. À l'avenir, nous pourrions fournir un accessoire spécifique à iOS pour définir explicitement le chemin s'il y a une demande pour un contrôle plus précis de l'ombre.

Revu par: weicool

Commit: https://github.com/facebook/react-native/commit/e4c53c28aea7e067e48f5c8c0100c7cafc031b06

Fourchette Matías
la source
2

Étonnamment, personne n'en a parlé, ce qui apporte une certaine clarté:

style={{
backgroundColor: 'white',
opacity: 0.7
}}
Antonin GAVREL
la source
6
Cette solution définit l'opacité de la vue entière, pas seulement son arrière-plan, ce qui fait que tous ses enfants deviennent également semi-opaques (ce qui est en fait souligné dans la question originale)
Cool Soft
-1

Voici ma solution à un modal qui peut être rendu sur n'importe quel écran et initialisé dans App.tsx

ModalComponent.tsx

import React, { Component } from 'react';
import { Modal, Text, TouchableHighlight, View, StyleSheet, Platform } from 'react-native';
import EventEmitter from 'events';
// I keep localization files for strings and device metrics like height and width which are used for styling 
import strings from '../../config/strings';
import metrics from '../../config/metrics';

const emitter = new EventEmitter();
export const _modalEmitter = emitter

export class ModalView extends Component {
    state: {
        modalVisible: boolean,
        text: string, 
        callbackSubmit: any, 
        callbackCancel: any,
        animation: any
    }

    constructor(props) {
        super(props)
        this.state = {
            modalVisible: false,
            text: "", 
            callbackSubmit: (() => {}), 
            callbackCancel: (() => {}),
            animation: new Animated.Value(0)
        } 
    }

    componentDidMount() {
        _modalEmitter.addListener(strings.modalOpen, (event) => {
            var state = {
                modalVisible: true,
                text: event.text, 
                callbackSubmit: event.onSubmit, 
                callbackCancel: event.onClose,
                animation: new Animated.Value(0)
            } 
            this.setState(state)
        })
        _modalEmitter.addListener(strings.modalClose, (event) => {
            var state = {
                modalVisible: false,
                text: "", 
                callbackSubmit: (() => {}), 
                callbackCancel: (() => {}),
                animation: new Animated.Value(0)
            } 
            this.setState(state)
        })
    }

    componentWillUnmount() {
        var state = {
            modalVisible: false,
            text: "", 
            callbackSubmit: (() => {}), 
            callbackCancel: (() => {})
        } 
        this.setState(state)
    }

    closeModal = () => {
        _modalEmitter.emit(strings.modalClose)
    }

    startAnimation=()=>{
        Animated.timing(this.state.animation, {
            toValue : 0.5,
            duration : 500
        }).start()
    }

    body = () => {
        const animatedOpacity ={
            opacity : this.state.animation
        }
        this.startAnimation()
        return (
            <View style={{ height: 0 }}>
                <Modal
                    animationType="fade"
                    transparent={true}
                    visible={this.state.modalVisible}>

                    // render a transparent gray background over the whole screen and animate it to fade in, touchable opacity to close modal on click out

                    <Animated.View style={[styles.modalBackground, animatedOpacity]} > 
                        <TouchableOpacity onPress={() => this.closeModal()} activeOpacity={1} style={[styles.modalBackground, {opacity: 1} ]} > 
                        </TouchableOpacity>
                    </Animated.View>

                    // render an absolutely positioned modal component over that background
                    <View style={styles.modalContent}>

                        <View key="text_container">
                            <Text>{this.state.text}?</Text>
                        </View>
                        <View key="options_container">
                            // keep in mind the content styling is very minimal for this example, you can put in your own component here or style and make it behave as you wish
                            <TouchableOpacity
                                onPress={() => {
                                    this.state.callbackSubmit();
                                }}>
                                <Text>Confirm</Text>
                            </TouchableOpacity>

                            <TouchableOpacity
                                onPress={() => {
                                    this.state.callbackCancel();
                                }}>
                                <Text>Cancel</Text>
                            </TouchableOpacity>

                        </View>
                    </View>
                </Modal>
            </View> 
        );
    }

    render() {
        return this.body()
    }
}

// to center the modal on your screen 
// top: metrics.DEVICE_HEIGHT/2 positions the top of the modal at the center of your screen
// however you wanna consider your modal's height and subtract half of that so that the 
// center of the modal is centered not the top, additionally for 'ios' taking into consideration
// the 20px top bunny ears offset hence - (Platform.OS == 'ios'? 120 : 100)
// where 100 is half of the modal's height of 200
const styles = StyleSheet.create({
    modalBackground: {
        height: '100%', 
        width: '100%', 
        backgroundColor: 'gray', 
        zIndex: -1 
    },
    modalContent: { 
        position: 'absolute', 
        alignSelf: 'center', 
        zIndex: 1, 
        top: metrics.DEVICE_HEIGHT/2 - (Platform.OS == 'ios'? 120 : 100), 
        justifyContent: 'center', 
        alignItems: 'center', 
        display: 'flex', 
        height: 200, 
        width: '80%', 
        borderRadius: 27,
        backgroundColor: 'white', 
        opacity: 1 
    },
})

Rendu et importation App.tsx

import { ModalView } from './{your_path}/ModalComponent';

render() {
    return (
        <React.Fragment>
            <StatusBar barStyle={'dark-content'} />
            <AppRouter />
            <ModalView />
        </React.Fragment>
    )
}

et de l'utiliser à partir de n'importe quel composant

SomeComponent.tsx

import { _modalEmitter } from './{your_path}/ModalComponent'

// Some functions within your component

showModal(modalText, callbackOnSubmit, callbackOnClose) {
    _modalEmitter.emit(strings.modalOpen, { text: modalText, onSubmit: callbackOnSubmit.bind(this), onClose: callbackOnClose.bind(this) })
}

closeModal() {
    _modalEmitter.emit(strings.modalClose)
}

J'espère avoir pu aider certains d'entre vous, j'ai utilisé une structure très similaire pour les notifications dans l'application

Bon codage

Nikola G. Tachev
la source