Como definir a cor de plano de fundo da vista transparente no React Native

139

Este é o estilo da visualização que eu usei

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

Atualmente, possui um fundo branco. Eu posso alterar o backgroundColor como eu quiser, '#343434'mas ele aceita apenas no máximo 6 valores hexadecimais para cores, então não posso dar opacidade a esse gosto '#00ffffff'. Eu tentei usar opacidade como esta

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

mas reduz a visibilidade do conteúdo da visualização. Então, alguma resposta?

JEROM JOY
fonte

Respostas:

288

Use o rgbavalor para backgroundColor.

Por exemplo,

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

Isso define uma cor cinza com 80% de opacidade, derivada do decimal da opacidade 0.8,. Este valor pode ser qualquer coisa de 0.0até 1.0.

dieuvn3b
fonte
por que diabos os valores de cores são 8 bits e os valores alfa flutuam?
Duhaime
@duhaime, não sei por que especificamente, mas 8 bits faz sentido a partir de um sentido de memória (especialmente historicamente). Os valores alfa fazem mais sentido ter 0 e 1 como min e max para totalmente transparente ou totalmente opaco. Por exemplo, se você deseja que algo seja 25% transparente, não quer descobrir o que é 1/4 de 255.
kojow7 14/01
104

O seguinte funciona bem:

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

Você também pode tentar:

backgroundColor: 'transparent'
JEROM JOY
fonte
2
backgroundColor: 'transparente' é de longe a solução mais fácil.
#
27

Tente isso, backgroundColor: '#00000000' ele definirá a cor do plano de fundo como transparente e segue os códigos hexagonais #rrggbbaa

Tharzeez
fonte
Por alguma razão, essa variante exibe a cor do resultado com opacidade incorretamente. Se não me engano, é um bug no RN. Portanto, melhor usar o rgbacaminho.
Shyngys Kassymov 24/07/19
1
@ShyngysKassymov gist.github.com/lopspower/03fb1cc0ac9f32ef38f4 verifique isto
Oo
@Oo interessante, isso faz sentido. Obrigado por apontar! Mas na OMI é mais fácil usar o rgbacaminho :)
Shyngys Kassymov 06/06
significa que o formato deve ser #aarrggbb?
Shyngys Kassymov 06/06
Eu quis dizer que você pode usar o hexavalor em rrggbbaa.
06/06
3

Você deve estar ciente dos conflitos atuais que existem com os fundos iOS e RGBA.

Resumo: public React Native atualmente expõe as propriedades de sombra da camada iOS mais ou menos diretamente, no entanto, existem vários problemas com isso:

1) O desempenho ao usar essas propriedades é ruim por padrão. Isso ocorre porque o iOS calcula a sombra obtendo a máscara de pixel exata da visualização, incluindo qualquer conteúdo tranlucente e todas as suas subvisões, que exigem muita CPU e GPU. 2) As propriedades de sombra do iOS não correspondem à sintaxe ou semântica do padrão CSS box-shadow e é improvável que seja possível implementar no Android. 3) Não expomos olayer.shadowPath propriedade, que é crucial para obter um bom desempenho das sombras da camada.

Esse diff resolve o problema número 1) implementando um padrão shadowPath que corresponde à borda da vista para vistas com um fundo opaco. Isso melhora o desempenho das sombras, otimizando para o caso de uso comum. Também restabeleci a propagação de cores de segundo plano para exibições com adereços de sombra - isso deve ajudar a garantir que esse melhor cenário ocorra com mais frequência.

Para visualizações com um plano de fundo explícito e transparente, a sombra continuará funcionando como antes ( shadowPathserá deixada não definida e a sombra será derivada exatamente dos pixels da visualização e de suas subvisões). Este é o pior caminho para o desempenho, no entanto, você deve evitá-lo, a menos que seja absolutamente necessário. O suporte para isso pode ser desativado por padrão no futuro ou ser descartado por completo.

Para imagens translúcidas, sugere-se que você faça a sombra na própria imagem ou use outro mecanismo para pré-gerar a sombra. Para sombras de texto, você deve usar as propriedades textShadow, que funcionam em várias plataformas e têm desempenho muito melhor.

O problema número 2) será resolvido em uma comparação futura, possivelmente renomeando as propriedades shadowXXX do iOS para boxShadowXXX e alterando a sintaxe e a semântica para corresponder aos padrões CSS.

O problema número 3) agora é discutível, já que geramos o shadowPath automaticamente. No futuro, poderemos fornecer um suporte específico para iOS para definir o caminho explicitamente se houver uma demanda por um controle mais preciso da sombra.

Analisado por: weicool

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

Garfo Matías
fonte
2

Surpreendentemente, ninguém falou sobre isso, o que fornece um pouco de clareza:

style={{
backgroundColor: 'white',
opacity: 0.7
}}
Antonin GAVREL
fonte
6
Essa solução define opacidade para a visualização inteira, não apenas para o plano de fundo, resultando em todos os filhos também semi-opacos (o que é realmente apontado na pergunta original)
Cool Soft
-1

Aqui está minha solução para um modal que pode ser renderizado em qualquer tela e inicializado em 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 
    },
})

App.tsx renderiza e importa

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

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

e usá-lo a partir de qualquer componente

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

Espero poder ajudar alguns de vocês, usei uma estrutura muito semelhante para notificações no aplicativo

Feliz codificação

Nikola G. Tachev
fonte