Jak ustawić przezroczysty kolor tła widoku w React Native

139

To jest styl widoku, którego użyłem

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

Obecnie ma białe tło. Mogę zmienić backgroundColor tak, jak chcę, '#343434'ale akceptuje on tylko maksymalnie 6 wartości szesnastkowych dla koloru, więc nie mogę nadać temu krycia '#00ffffff'. Próbowałem użyć takiego krycia

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

ale zmniejsza widoczność treści widoku. Więc jakieś odpowiedzi?

JEROM JOY
źródło

Odpowiedzi:

288

Użyj rgbawartości dla backgroundColor.

Na przykład,

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

Spowoduje to ustawienie go na szarym kolorze przezroczystości 80%, co pochodzi z przecinku nieprzezroczystości 0.8. Ta wartość może mieć dowolną wartość od 0.0do 1.0.

dieuvn3b
źródło
dlaczego u licha wartości kolorów są 8-bitowe, a wartości alfa pływają?
duhaime
@duhaime, nie wiem dlaczego konkretnie, ale 8-bitowe ma sens z punktu widzenia pamięci (szczególnie historycznie). Wartości alfa są bardziej sensowne, aby mieć 0 i 1 jako min i max dla w pełni przezroczystego lub całkowicie nieprzezroczystego. Na przykład, jeśli chcesz, aby coś było przezroczyste w 25%, nie chcesz dowiedzieć się, co to jest 1/4 z 255.
kojow7
104

Następujące działa dobrze:

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

Możesz też spróbować:

backgroundColor: 'transparent'
JEROM JOY
źródło
2
backgroundColor: „transparent” to zdecydowanie najłatwiejsze rozwiązanie.
NathanL
27

Spróbuj tego backgroundColor: '#00000000' , ustawi kolor tła na przezroczysty, będzie zgodny z kodami szesnastkowymi #rrggbbaa

Tharzeez
źródło
Z jakiegoś powodu ten wariant wyświetla kolor wynikowy z kryciem niepoprawnie. Jeśli się nie mylę, to błąd w RN. Dlatego lepiej skorzystać z rgbadrogi.
Shyngys Kassymov
1
@ShyngysKassymov gist.github.com/lopspower/03fb1cc0ac9f32ef38f4 sprawdź to
Oo
@Oo interesujące, to ma sens. Dzięki za wskazanie! Ale IMO łatwiej jest skorzystać z rgbadrogi :)
Shyngys Kassymov
czy to oznacza, że ​​zamiast tego format powinien być #aarrggbb?
Shyngys Kassymov
Miałem na myśli, że możesz użyć wartości sześciokątnej w rrggbbaa.
Oo
3

Powinieneś zdawać sobie sprawę z obecnych konfliktów, które istnieją w środowiskach iOS i RGBA.

Podsumowanie: public React Native obecnie bardziej lub mniej bezpośrednio ujawnia właściwości cienia warstwy iOS, jednak jest z tym kilka problemów:

1) Wydajność podczas korzystania z tych właściwości jest domyślnie niska. Dzieje się tak, ponieważ iOS oblicza cień, uzyskując dokładną maskę pikseli widoku, w tym wszelkie przezroczyste treści i wszystkie jej podglądy, które są bardzo obciążające procesor i GPU. 2) Właściwości cienia w systemie iOS nie są zgodne ze składnią lub semantyką standardu CSS box-shadow i jest mało prawdopodobne, aby można je było zaimplementować w systemie Android. 3) Nie ujawniamy layer.shadowPathwłaściwości, co jest kluczowe dla uzyskania dobrej wydajności z cieni warstw.

Ta różnica rozwiązuje problem nr 1) poprzez implementację wartości domyślnej, shadowPathktóra pasuje do krawędzi widoku dla widoków z nieprzezroczystym tłem. Poprawia to działanie cieni poprzez optymalizację pod kątem typowego przypadku użycia. Przywróciłem również propagację kolorów tła dla widoków, które mają rekwizyty cienia - powinno to zapewnić, że ten najlepszy scenariusz będzie występował częściej.

W przypadku widoków z wyraźnym przezroczystym tłem cień będzie nadal działał tak, jak wcześniej ( shadowPathpozostanie nieskonfigurowany, a cień zostanie wyprowadzony dokładnie z pikseli widoku i jego widoków podrzędnych). Jest to jednak najgorsza ścieżka wydajności, więc należy jej unikać, chyba że jest to absolutnie konieczne. Obsługa tego może być domyślnie wyłączona w przyszłości lub całkowicie wycofana.

W przypadku obrazów półprzezroczystych sugeruje się wypalenie cienia w samym obrazie lub użycie innego mechanizmu do wstępnego wygenerowania cienia. W przypadku cieni tekstu należy używać właściwości textShadow, które działają na wielu platformach i mają znacznie lepszą wydajność.

Problem nr 2) zostanie rozwiązany w przyszłym diff, prawdopodobnie poprzez zmianę nazwy właściwości systemu iOS shadowXXX na boxShadowXXX oraz zmianę składni i semantyki, aby pasowały do ​​standardów CSS.

Problem nr 3) jest teraz w większości dyskusyjny, ponieważ automatycznie generujemy shadowPath. W przyszłości możemy udostępnić właściwość specyficzną dla iOS, aby jawnie ustawić ścieżkę, jeśli istnieje zapotrzebowanie na bardziej precyzyjną kontrolę cienia.

Recenzja: weicool

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

Matías Fork
źródło
2

Zaskakująco nikt o tym nie powiedział, co zapewnia pewną jasność:

style={{
backgroundColor: 'white',
opacity: 0.7
}}
Antonin GAVREL
źródło
6
To rozwiązanie definiuje krycie całego widoku, a nie tylko jego tła, w wyniku czego wszystkie jego elementy podrzędne również stają się półprzezroczyste (co jest faktycznie wskazane w oryginalnym pytaniu)
Cool Soft
-1

Oto moje rozwiązanie modalne, które można renderować na dowolnym ekranie i zainicjować w 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 
    },
})

Renderowanie i importowanie App.tsx

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

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

i używać go z dowolnego komponentu

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

Mam nadzieję, że niektórym z was mogłem pomóc, użyłem bardzo podobnej struktury dla powiadomień w aplikacji

Miłego kodowania

Nikola G. Tachev
źródło