Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How would you implement an overlay to the content below the BottomSheet? #27

Open
ferrannp opened this issue Jul 10, 2017 · 6 comments
Open

Comments

@ferrannp
Copy link

Just like explained here https://material.io/guidelines/components/bottom-sheets.html#bottom-sheets-usage. Is there an easy way?

I think about having an overlay view that use some animation opacity based on the current position of the BottomSheet (full color when is expanded and starting fading color when collapsing). The overlay should also be clickable to close the bottom sheet. Maybe you have an example of it? Thanks :)

@cesardeazevedo
Copy link
Owner

I would do something like that, there it is.

import React, { Component, PropTypes } from 'react'
import {
  Text,
  View,
  Animated,
  StatusBar,
  Dimensions,
  StyleSheet,
} from 'react-native'

import Icon from 'react-native-vector-icons/Ionicons'

import {
  BottomSheetBehavior,
  CoordinatorLayout,
} from 'react-native-bottom-sheet-behavior'

const { width } = Dimensions.get('window')

class SimpleView extends Component {
  static contextTypes = {
    openDrawer: PropTypes.func,
  };

  state = {
    scrollY: new Animated.Value(0),
  };

  handleSlide = (e) => {
    Animated.event(
      [{ nativeEvent: { offset: this.state.scrollY }}, { useNativeDriver: true }]
    )(e, this.state)
  }

  render() {
    const opacity = this.state.scrollY.interpolate({
      inputRange:  [0, 1],
      outputRange: [0, 0.65],
    })
    return (
      <CoordinatorLayout style={styles.container}>
        <StatusBar translucent backgroundColor="rgba(0, 0, 0, 0.2)" />
        <View style={styles.content}>
          <View style={styles.toolbarWrapper}>
            <Icon.ToolbarAndroid
              navIconName={'md-menu'}
              style={styles.toolbar}
              titleColor="white"
              title="Simple Bottom Sheet"
              onIconClicked={() => this.context.openDrawer()}
            />
          </View>
        </View>
        <Animated.View style={[styles.overlay, {opacity}]} />
        <BottomSheetBehavior
          peekHeight={80}
          hideable={false}
          onSlide={this.handleSlide}>
          <View style={styles.bottomSheet}>
            <View style={styles.bottomSheetHeader}>
              <Text style={styles.label}>BottomSheetBehavior !</Text>
            </View>
            <View style={styles.bottomSheetContent}>
            </View>
          </View>
        </BottomSheetBehavior>
      </CoordinatorLayout>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  content: {
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#fff',
  },
  overlay: {
    position: 'absolute',
    top: -24,
    left: 0,
    right: 0,
    bottom: 0,
    opacity: 0,
    backgroundColor: 'black',
  },
  toolbarWrapper: {
    paddingTop: 24,
    marginBottom: 24,
    backgroundColor: '#4389f2',
  },
  toolbar: {
    width,
    height: 56,
  },
  bottomSheet: {
    backgroundColor: '#4389f2',
  },
  bottomSheetHeader: {
    padding: 28,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  bottomSheetContent: {
    height: 200,
    padding: 2,
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  label: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#fff',
  },
})

export default SimpleView

opacity

@ferrannp
Copy link
Author

Nice! Thank you! I was doing something similar, I added a touchable so I can collapse the BottomSheet when clicking the overlay, it might be useful to someone:

<TouchableWithoutFeedback onPress={this._setBottomSheetState}>
  <Animated.View style={[styles.overlay, {
    opacity: this.state.scrollY.interpolate({
      inputRange: [0, 1],
      outputRange: [0, 0.4],
    })
  }]}
    pointerEvents={!this._isOpen() ? "none" : "auto"}
  />
</TouchableWithoutFeedback>

Pity we don't have this in JS so can work on iOS too, but for now, it's good in Android thanks to this lib :)

@ferrannp
Copy link
Author

@cesardeazevedo Thanks to Flow and checking API, I think we were not using useNativeDriver correctly, should be:

  _handleSlide = (e) => {
    Animated.event(
      [{ nativeEvent: { offset: this.state.scrollY }}],
      { useNativeDriver: true }
    )(e, this.state);
  };

The thing is, like that it crashes, with false it works. Any ideas?

@cesardeazevedo
Copy link
Owner

Oh, so sorry about that, completely my fault, i definitely was using wrong the useNativeDriver API.

One the things to work around would be to wrap the BottomSheetBehavior together with the createAnimatedComponent (the FlastList Example does it), that wouldn't cause any crashes, but the transition itself doesn't seems to take any effect with useNativeDrive: true, but i can be wrong about this approach, I will definitely investigate it, sorry about that.

@ferrannp
Copy link
Author

@cesardeazevedo I think that for useNativeDrive to work, your library need to handle that in the native side (because with that set to true, it returns an object not a callback).

@cesardeazevedo
Copy link
Owner

You are right, i am also thinking in something on this direction, i am trying to getting in deep on the ScrollView implementation, and i think it could be more related on the way that we handle the Animated API together with createAnimatedComponent than the native itself, or something in between, i'm not sure, i'm still investigating it, i will reopen this issue for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants