osdnk / react-native-reanimated-bottom-sheet

Highly configurable bottom sheet component made with react-native-reanimated and react-native-gesture-handler
MIT License
3.32k stars 328 forks source link

Mask background with dark overlay #138

Open oferRounds opened 4 years ago

oferRounds commented 4 years ago

Hi!

Thanks for this awesome library!

Quick question please: How can I mask the background? if I just add a mask view, it darken also the bottom sheet... Any idea?

oferRounds commented 4 years ago

I’m not using expo by the way... So can’t use the example with the blur

zmnv commented 4 years ago

https://github.com/osdnk/react-native-reanimated-bottom-sheet/blob/master/Example/src/screen/AppleMusic.tsx#L202

didn't help?

oferRounds commented 4 years ago

@zmnv Thank you very much, missed this! Will look into it!

oferRounds commented 4 years ago

Thank you, works perfect!

oferRounds commented 4 years ago

There is one problem actually which I notice – the shadow does not cover the navigation bar nor the tab bar (using react native navigation), any idea how workaround this issue?

zmnv commented 4 years ago

The same as https://github.com/osdnk/react-native-reanimated-bottom-sheet/issues/60

stelmakhivan commented 3 years ago

@oferRounds, I used BottomSheet on the top level of my app

hungdev commented 3 years ago

Thank @zmnv , it worked for me. This is my example for anyone who comes late

import React from 'react'
import {
  Image,
  StyleSheet,
  Text,
  TouchableWithoutFeedback,
  View,
  TextInput,
  SafeAreaView,
  TouchableOpacity
} from 'react-native';
import BottomSheet from 'reanimated-bottom-sheet'
import Animated from 'react-native-reanimated'
const AnimatedView = Animated.View

let fall = new Animated.Value(1)

export default class Example extends React.Component {
  renderInner = () => (
    <View style={styles.panel}>
      <TextInput
        style={styles.search}
        onFocus={() => {
          this.bs.current.snapTo(1)
        }}
        placeholder="search"
      />
      <Text style={styles.panelTitle}>San Francisco Airport</Text>
      <Text style={styles.panelSubtitle}>
        International Airport - 40 miles away
      </Text>
      <View style={styles.panelButton}>
        <Text style={styles.panelButtonTitle}>Directions</Text>
      </View>
      <View style={styles.panelButton}>
        <Text style={styles.panelButtonTitle}>Search Nearby</Text>
      </View>
      {/* <Image
        style={styles.photo}
        source={require('./assets/airport-photo.jpg')}
      /> */}
    </View>
  )

  renderHeader = () => (
    <View style={styles.header}>
      <View style={styles.panelHeader}>
        <View style={styles.panelHandle} />
      </View>
    </View>
  )

  bs = React.createRef()

  renderShadow = () => {
    const animatedShadowOpacity = Animated.interpolate(fall, {
      inputRange: [0, 1],
      outputRange: [0.5, 0],
    })

    return (
      <AnimatedView
        pointerEvents="none"
        style={[
          styles.shadowContainer,
          {
            opacity: animatedShadowOpacity,
          },
        ]}
      />
    )
  }

  render() {
    return (
      <SafeAreaView style={{ flex: 1 }}>
        <View style={styles.container}>
          {this.renderShadow()}
          <BottomSheet
            ref={this.bs}
            snapPoints={[500, 250, 0]}
            renderContent={this.renderInner}
            renderHeader={this.renderHeader}
            initialSnap={1}
            callbackNode={fall}
          />
          <TouchableOpacity style={{ marginTop: 100, borderWidth: 1, borderColor: 'red' }}
            onPress={() => this.bs.current.snapTo(0)}>
            <Text>aaa</Text>
            {/* <Image style={styles.map} source={require('./assets/map-bg.jpg')} /> */}
          </TouchableOpacity>
        </View>
      </SafeAreaView>
    )
  }
}

const IMAGE_SIZE = 200

const styles = StyleSheet.create({
  search: {
    borderColor: 'gray',
    borderWidth: StyleSheet.hairlineWidth,
    height: 40,
    borderRadius: 10,
    paddingHorizontal: 15,
  },
  container: {
    flex: 1,
    backgroundColor: '#F5FCFF',
  },
  box: {
    width: IMAGE_SIZE,
    height: IMAGE_SIZE,
  },
  panelContainer: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
  },
  panel: {
    height: 600,
    padding: 20,
    backgroundColor: '#fff',
  },
  header: {
    backgroundColor: '#fff',
    shadowColor: '#000000',
    paddingTop: 20,
    borderTopLeftRadius: 20,
    borderTopRightRadius: 20,
  },
  panelHeader: {
    alignItems: 'center',
  },
  panelHandle: {
    width: 40,
    height: 8,
    borderRadius: 4,
    backgroundColor: '#00000040',
    marginBottom: 10,
  },
  panelTitle: {
    fontSize: 27,
    height: 35,
  },
  panelSubtitle: {
    fontSize: 14,
    color: 'gray',
    height: 30,
    marginBottom: 10,
  },
  panelButton: {
    padding: 20,
    borderRadius: 10,
    backgroundColor: '#318bfb',
    alignItems: 'center',
    marginVertical: 10,
  },
  panelButtonTitle: {
    fontSize: 17,
    fontWeight: 'bold',
    color: 'white',
  },
  photo: {
    width: '100%',
    height: 225,
    marginTop: 30,
  },
  map: {
    height: '100%',
    width: '100%',
  },
  // Shadow
  shadowContainer: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: '#000',
  },
})
hungdev commented 3 years ago

@zmnv but i still can press some items under mask overlay layout. How to prevent it? thank you

ghost commented 3 years ago

@zmnv but i still can press some items under mask overlay layout. How to prevent it? thank you

hey, i have same problem did you solve it?

greifmatthias commented 3 years ago

I prevent that with:

renderShadow = () => {
    const animatedShadowOpacity = Animated.interpolate(fall, {
      inputRange: [0, 1],
      outputRange: [0.5, 0],
    });

    const clickthrough = Animated.cond(greaterThan(fall, 0), 'none', 'auto');

    return (
      <AnimatedView
        pointerEvents={clickthrough}
        style={[
          styles.shadowContainer,
          {
            opacity: animatedShadowOpacity,
          },
        ]}
      />
    );
  };

Still new to this library so dunno if this is the recommended way

anhquan291 commented 3 years ago

I prevent that with:

renderShadow = () => {
    const animatedShadowOpacity = Animated.interpolate(fall, {
      inputRange: [0, 1],
      outputRange: [0.5, 0],
    });

    const clickthrough = Animated.cond(greaterThan(fall, 0), 'none', 'auto');

    return (
      <AnimatedView
        pointerEvents={clickthrough}
        style={[
          styles.shadowContainer,
          {
            opacity: animatedShadowOpacity,
          },
        ]}
      />
    );
  };

Still new to this library to dunno if this is the recommended way

Hi, thanks for your solution. It works but it also disables click even when the bottom sheet and shadow not open. Please help? thank you

greifmatthias commented 3 years ago

Hi @anhquan291; Some while ago now but if I remember correctly I fixed that with the BottomSheet props:

...
enabledGestureInteraction={true}
enabledContentGestureInteraction={false} />
anhquan291 commented 3 years ago

Hi @anhquan291; Some while ago now but if I remember correctly I fixed that with the BottomSheet props:


...

enabledGestureInteraction={true}

enabledContentGestureInteraction={false} />

Thank you. I'll try it

allberto commented 3 years ago

You only need to set a zIndex to the shadowContainer to keep over the back content to avoid interaction

shadowContainer: { ...StyleSheet.absoluteFillObject, backgroundColor: '#292C36', zIndex:10, }

DibyajyotiMishra commented 3 years ago

I get this near Animated.interpolate(fall,{....});

TypeError: undefined is not a function

Any suggestions ??

Here is the full snippet:

const renderShadow = () => {
    const animatedShadowOpacity = Animated.interpolate(fall, {
      inputRange: [0, 1],
      outputRange: [0.5, 0],
    });

    return (
      <AnimatedView
        pointerEvents="none"
        style={[
          styles.shadowContainer,
          {
            opacity: animatedShadowOpacity,
          },
        ]}
      />
    );
  };
DibyajyotiMishra commented 3 years ago

I get this near Animated.interpolate(fall,{....});

TypeError: undefined is not a function

Any suggestions ??

Here is the full snippet:

const renderShadow = () => {
    const animatedShadowOpacity = Animated.interpolate(fall, {
      inputRange: [0, 1],
      outputRange: [0.5, 0],
    });

    return (
      <AnimatedView
        pointerEvents="none"
        style={[
          styles.shadowContainer,
          {
            opacity: animatedShadowOpacity,
          },
        ]}
      />
    );
  };

Downgrading react-native-reanimated package to 1.7.0 helped.

greifmatthias commented 3 years ago

The api for reanimated is changed in v2, try interpolateNode: https://docs.swmansion.com/react-native-reanimated/docs/migration

patlux commented 2 years ago
const fall = React.useRef(new Animated.Value(1)).current;

const animatedShadowOpacity = Animated.interpolateNode(fall, {
  inputRange: [0, 1],
  outputRange: [0.5, 0],
});

return (
  <>
    <BottomSheet .../>
    <Animated.View
      pointerEvents="none"
      style={[
        styles.shadowContainer,
        {
          opacity: animatedShadowOpacity,
        },
      ]}
    />
  </>
);

const styles = StyleSheet.create({
  shadowContainer: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: '#000',
  },
});