Coder Social home page Coder Social logo

osdnk / react-native-reanimated-bottom-sheet Goto Github PK

View Code? Open in Web Editor NEW
3.3K 25.0 329.0 43.89 MB

Highly configurable bottom sheet component made with react-native-reanimated and react-native-gesture-handler

License: MIT License

JavaScript 36.48% TypeScript 63.52%

react-native-reanimated-bottom-sheet's Issues

Able to scrollTo() of the content

How to 'scrollToTop' for the scrollable content inside the bottom-sheet? Is it possible to add a scrollTo({}) method for the component?

I've tried couple times but failed. It's too complicated since the 'scrollView' inside the bottom-sheet is controlled by all these math... I don't know where to start.

So, is it basically add another animated.value to signal a manuallySetScroll, inject something inside the this.Y(), if manuallySetScroll is on then, stop the clock, reset manuallySetScroll, and return position 0 for the this.Y().

Thanks a lot

Content is overflowing at the bottom which results in a content leak on Notch phones

First of all, awesome library 👏

I've come across what I think is a bug where the bottomSheet content is leaking into the SafeArea from the bottom (on notch phones like iPhone X). SafeArea is a component from react-navigation that ensures content is not overlapping outside of viewable area in notch phones.

Preview

bottomSheet-bug-short

You can see the bottom sheet content is overflowing at the bottom when it should not be.

Here's my configuration:

<BottomSheet
  snapPoints={[290, 75]}
  initialSnap={1}
  renderContent={renderInner}
  renderHeader={renderHeader}
/>

react-native info

  React Native Environment Info:
    System:
      OS: macOS 10.14.2
      CPU: x64 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
      Memory: 27.74 MB / 16.00 GB
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 8.12.0 - ~/.nvm/versions/node/v8.12.0/bin/node
      Yarn: 1.6.0 - /usr/local/bin/yarn
      npm: 6.4.1 - ~/.nvm/versions/node/v8.12.0/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
      Android SDK:
        Build Tools: 26.0.3, 27.0.3, 28.0.2, 28.0.3
        API Levels: 21, 22, 23, 24, 25, 26, 27
    IDEs:
      Android Studio: 3.1 AI-173.4907809
      Xcode: 10.1/10B61 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.6.3 => 16.6.3
      react-native: 0.57.8 => 0.57.8
    npmGlobalPackages:
      react-native-log-ios: 1.0.1

Things I tried

I tried setting zIndex on the SafeArea view to a high value like 9 but still, the bottom sheet is showing on top.

Any other ideas I can try to work around this?

Thanks 👋

Reference react-native-gesture-handler documentation for android in readme

If you're setting up react-native-gesture-handler for the first time you must override the root view in your MainActivity.java file, for anyone using this library without already having setup react-native-gesture-handler this library appears incorrectly to be broken on android.

We should add in a caveat to follow the gesture handler getting started guide instead of simply saying "install and link" when installing the peer dependencies.

Touch events on the content are not being captured on Android when zIndex is overridden

Preview

bottomsheetandroidbuglow

As you can see, the touch event is going to the map in the background and not the bottom sheet content. I have to use two-finger gesture in order to interact with the bottom sheet content on Android.

What I tried but didn't work

  • I tried using RNGH.SrollView instead of RN ScrollView.
  • I also tried using just a View.
  • I've tried adding the following props to RNGH.ScrollView: enabled={true} and disallowInterruption={true}
  • I've added:
onScroll={event => {
          console.log(event.nativeEvent);
        }}

and confirmed that trying to scroll with a single finger doesn't even call this function but two-finger touch calls it sometimes.

Example Code

<View>
 	<MapView ... />
	<BottomSheet
          enabledInnerScrolling={true}
          enabledGestureInteraction={true}
          overdragResistanceFactor={0}
          snapPoints={[
            Dimensions.get('window').height / 2.275,
            Dimensions.get('window').height / 3,
            83,
          ]}
          initialSnap={1}
          renderContent={() =>
            return <View>... (doesn't matter what I put here)</View>
          }
          renderHeader={() => <View>... (doesn't matter what I put here)</View>}
        />
</View>

Environments

  React Native Environment Info:
    System:
      OS: macOS 10.14.2
      CPU: x64 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
      Memory: 604.60 MB / 16.00 GB
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 8.12.0 - ~/.nvm/versions/node/v8.12.0/bin/node
      Yarn: 1.6.0 - /usr/local/bin/yarn
      npm: 6.4.1 - ~/.nvm/versions/node/v8.12.0/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
      Android SDK:
        Build Tools: 26.0.3, 27.0.3, 28.0.2, 28.0.3
        API Levels: 21, 22, 23, 24, 25, 26, 27
    IDEs:
      Android Studio: 3.1 AI-173.4907809
      Xcode: 10.1/10B61 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.6.3 => 16.6.3 
      react-native: 0.57.8 => 0.57.8 
    npmGlobalPackages:
      react-native-log-ios: 1.0.1

Dependencies

Tested it on multiple Android phones/versions: Android 8.1 and Android 5.1

"react-native-gesture-handler": "^1.1.0",
"react-native-reanimated": "^1.0.0-alpha.12",
"reanimated-bottom-sheet": "^1.0.0-alpha.1",

@osdnk Any workarounds/ideas I can try?

Thanks

TypeError: Cannot read property 'val' of undefined

This error is located at BottomSheetBehavior at Map.js:16

Steps to reproduce:

I have a simple app that has a bottom tab bar navigation. From just trying to get this going, it doesn't show up at all if I remove everything except the snap points, which are listed as required to render. If I include the initialSnap prop in any way, it throws the error in the title. A Map.js file is one of the screens:

import React from 'react';
import { View, StyleSheet } from 'react-native';
import MapView, { PROVIDER_GOOGLE } from 'react-native-maps';
import BottomSheet from 'reanimated-bottom-sheet';
import renderMarker from './Marker';

const Map = () => {
  return (
    <View style={{ ...StyleSheet.absoluteFillObject }}>
      <BottomSheet
        snapPoints={[500, 250]}
        renderContent={() => <View />}
        initialSnap={250} //this line gives the error described
      />
      <MapView
        provider={PROVIDER_GOOGLE}
        showsUserLocation
        showsMyLocationButton
        followUserLocation
        showsCompass
        style={{ ...StyleSheet.absoluteFillObject }}
        initialRegion={initialRegion}
      >
        {renderMarker()}
      </MapView>
    </View >
  );
};

export default Map;

Bounce when snapping sheet

It'd be great to have an option to enable overshooting / bouncing when the sheet snaps into a position. See the first couple of things in this gif 😅

twitter-sheet

Capture Current Index

On reach a specific index of the Bottom Sheet snapPoints, I need to fire an event in my application, how can I do it? Looks like that currently there is no way to control events or the bottom sheet position with the library.

[Suggestion needed] How to pass callbackNode animated value to a parent component

I am trying to achieve some interaction when the bottom sheet is hidden and visible. I am able to follow the example and I have added the animated value to a view within the same component(add opacity & remove).

Now, I would like to animate a component which is not part of this based on the callbackNode value. This could be a basic approach, but I am new to RN and any advise to achieve this experience will be great.

More details:

App.js

<SafeAreaView style={styles.container} forceInset={{ bottom: 0 }}>
        <View style={styles.notifHolder}>
          <NotifPanel /> <----- A notification panel(based on react-native-reanimated example) is always visible(25%). FYI, this is an Interactable.View.
        </View>
        <Nav /> <----- Bottom sheet code is inside a stack navigation page
</SafeAreaView>

Expected output/effect:

I would like to,
a) Slowly hide the notifications panel based on the callbackNode snap position to 1
b) Same way, I would like to bring the notifications panel back when the callbackNode snap position is 0

Thanks for your help!

Invisible bottom sheet gets stuck in the center of the screen on Android

Hello,

The panel sometimes gets stuck in the middle of the screen on first app load. And it's invisible. It prevents me from clicking on the map. Android only. iOS is ok.

I noticed that this happens when initialSnap reference to not maximal value.
In my example: initialSnap = 0 works normally. And the panel is in it's max size.

Map and panel components is on one level and wrapped in one flex container with no other params.
Bug occurs more often on slow Android devices, or in debug mode.

const content = ({ children, height }) => (
  <View style={[styles.panel, { height }]}>
    {children}
  </View>
);

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

const MapPanel = ({ panelRef, children, height }) => (
  <BottomSheet
    ref={panelRef}
    snapPoints={[600, 300, 0]}
    renderContent={() => content({ children, height })}
    renderHeader={renderHeader}
    initialSnap={2}
  />
);

Screenshot_1559676086

Not working properly when used with RNCamera, also with BarcodeScanner from expo on Android

Hi, I was trying to have QRCode scanner in the bottomsheet. I tried using RNCamera (using react-native-qrcode-scanner), also tried BarcodeScanner from expo. But I am having some issues on android.

Here's what happens when used with camera (randomly):

  1. I have to click button (which shows bottomsheet) multiple times to show the bottomsheet.
  2. Sometimes, I can't show the bottomsheet at all.
  3. This is only happening on android.

I have tried to reproduce the issue. Here is the link to the github repo for the example:

https://github.com/nirajniroula/bottomsheet-test

@osdnk @brentvatne

Bottom sheet move too high when keyboard appears

I found a weird behavior when I put text input in the bottom sheet. My snap point is only 0 and device's width but when text input focused and keyboard appears, bottom sheet slide to the top of screen. The problem is; I have a header which floats above all components. So I can not see text input when I type something.

Callback on close

Hey!
I want to get a callback when the user closes the bottom sheet, something like onClosed.
I don't know how to use callbackNode, could you please explain this to me?
Thank you

When a touchable component (inside renderHeader) is pressed, snapTo() method doesn't work on Android.

I was trying to perform snapTo to hide bottomsheet when header is tapped. I wasn't able to do so Android. However, it works on iOS.

It can be reproduced in this snack. (Took one of the snack from earlier issues)
Long press the "Profile" tab to show the bottom sheet.
https://snack.expo.io/@roshangm1/bottom-sheet

I would like to dig in more on this (doing it too). If you have any clue on what could be the possible reason for this behavior, please do let me know.

Callback onClose

I want to implement a close callback that listens to the bottom-sheet. How do I implement this?

[Suggestion Needed] Question regarding implemenation in certain use cases.

How would you implement this library in the following use case ?
I have a bottom tab navigator with 4 tabs. I have to show bottom sheet with different content in different tabs (even 1 tab can have different content).

One approach would be to have the bottom sheet in the root file and calling it from other tab. (Problem here would be rendering dynamic height and dynamic content for bottom sheet for each tab (as height and content are not consistent).

Other approach would be to have bottom sheet for each tab. With this approach, in snapPoints=[0, 400], snapPoints[0] is not going to be true 0 from the bottom of app screen. It's going to be the bottom: 0 from tab navigator instead.

I am not thinking of calculating height of the tab navigator and making snapPoints=[-heightOfTabNavigator, 400] or similar. Suggest me if this is a good idea.

I am using https://www.npmjs.com/package/react-native-tab-navigator [This is a pretty old project 🗡 ] for tab navigator. But I am willing to use react-navigation's bottom navigator if required.

Any kind of suggestions would be helpful. :)

cc @brentvatne @osdnk @Eyesonly88 @satya164 (Sorry to mention you guys here ) 🥂

Drag via header only

Hey!

Awesome component, thanks for sharing!

Is it possible to make only the header draggable?

In my particular use case i would like to render a few ScrollView in the content, so I've turned off enabledGestureInteraction. It works so far, but it would be cool to make the header draggable, to allow the user to close the sheet via dragging.

Any suggestion?

Thanks!

How to implement callback based on the contentPosition prop ?

Thanks a lot for this library. I am trying to work on a pull to refresh UI ( I already have flat list rendered in the bottom sheet content). I know there are three gesture handlers that get passed through the instance, but I am not sure how to go about it.

I am thinking of getting the initial position of the header ref and check if the drag went below a certain level ( say maybe -50) and then trigger it. What I am not able to find is how do I get the initial position of the header ref and how to keep a check on where the header ref current is.

P.S. I couldn't find a StackOverflow tag for this so had to ask here. Let me know if there is anything you aren't clear about. I would try my best to come up with an example.

Edit
After going through the examples I figured out that you need to get the contentPosition from the prop and based on the value you can define a custom callback. What I am not quite sure about is where do I implement the callback. I saw the callbackNode prop but it only accepts an animatedValue which gets updated based on the content position.

[Suggestion] Allow customization of how nearest snap point is calculated

Right now, the calculation simply looks at which snap point is nearest to the release point. It would be nice to be able to bias certain snap points so that the user can move only a short distance away from one snap point and be considered closer to the next snap point.

Use cases for this is when you have a near-fullscreen snap point and don't want your user to have to pull the sheet half a screen height just to get to the next snap point.

Ref is not working when React.createRef() is used in two page at the same stack

I can show up that bottom sheet with touchable highlight's on press even at my first page but not at my second page even i just save as my first page.

this is my first page code:

import React, { Component } from 'react';
import { ScrollView, View, Text, Image, TextInput, TouchableHighlight, StatusBar, Dimensions, FlatList } from 'react-native';
import { StackActions, NavigationActions } from 'react-navigation';
import { Container, Content } from 'native-base';
import { BarPasswordStrengthDisplay } from 'react-native-password-strength-meter';
import BottomSheet from 'reanimated-bottom-sheet';
import Icon from 'react-native-vector-icons/FontAwesome';
import { LOGO } from '../../../assets/img';
import { placeholder, buttonSuccess, mainBlue, mainBackground } from '../../../assets/ColorIndex';

const {width, height} = Dimensions.get('screen')

export default class FirstScreen extends Component {
  constructor(props) {
    super(props);
    this.bottomSheetRegisterCompany = React.createRef();
    this.goRegister = this._goRegister.bind(this);
    this.goLogin = this._goLogin.bind(this);
    this.showBottomSheet = this._showBottomSheet.bind(this);
    this.headerBottomSheet = this._renderHeader.bind(this);
    this.contentBottomSheet = this._renderContent.bind(this);
    this.renderItem = this._renderItem.bind(this);
  }

  _goRegister() {
    this.props.navigation.dispatch(StackActions.reset({ index: 0, actions: [ NavigationActions.navigate({ routeName: 'Register' }) ] }));
  }
  
  _goLogin() {
    this.props.navigation.dispatch(StackActions.reset({ index: 0, actions: [ NavigationActions.navigate({ routeName: 'Login' }) ] }));
  }

  _renderHeader() {
    const { bottomSheetActive } = this.props.registerCompany;

    switch(bottomSheetActive){
      case 'bussiness_entity':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Badan Usaha</Text>
          </View>
        );
      case 'province':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Provinsi</Text>
          </View>
        );
      case 'city':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Kota</Text>
          </View>
        );
      case 'district':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Kecamatan</Text>
          </View>
        );
      case 'bussiness_industry':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Bisnis Industri</Text>
          </View>
        );
      case 'jenis_kelamin':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Jenis Kelamin</Text>
          </View>
        );
      case 'job_position':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Jabatan</Text>
          </View>
        );
    }
  }

  _renderContent(){
    const { bottomSheetActive } = this.props.registerCompany;
    const { bussinessEntities, bussinessIndustries, provinces, cities, districts, jenisKelamin, jobPositions } = this.props.masterData;

    switch(bottomSheetActive){
      case 'bussiness_entity':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(bussinessEntities.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `bussinessEntities-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={bussinessEntities}
              scrollEnabled={false}
            />
          </View>
        );
      case 'bussiness_industry':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(bussinessIndustries.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `bussinessIndustries-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={bussinessIndustries}
              scrollEnabled={false}
            />
          </View>
        );
      case 'province':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(provinces.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `provinces-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={provinces}
              scrollEnabled={false}
            />
          </View>
        );
      case 'city':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(cities.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `cities-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={cities}
              scrollEnabled={false}
            />
          </View>
        );
      case 'district':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(districts.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `districts-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={districts}
              scrollEnabled={false}
            />
          </View>
        );
      case 'jenis_kelamin':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(jenisKelamin.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `jenisKelamin-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={jenisKelamin}
              scrollEnabled={false}
            />
          </View>
        );
      case 'job_position':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(jobPositions.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `jobPositions-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={jobPositions}
              scrollEnabled={false}
            />
          </View>
        );
    }
  }

  _renderItem(item) {
    return (
      <TouchableHighlight style={{ padding: 10 }}>
        <View style={{ justifyContent: 'space-between', alignItems: 'center', flexDirection: 'row' }}>
          <View style={{ justifyContent: 'flex-start', alignItems: 'flex-start', paddingHorizontal: 10 }}>
            <Text style={{ fontWeight: 'bold', fontSize: 18 }}>{item.name}</Text>
          </View>
          <Icon name='circle-o' size={20} color={mainBlue} />
        </View>
      </TouchableHighlight>
    );
  }

  async _showBottomSheet(type, withContent = true) {
    const _type = type.toLowerCase();
    const {provinceValue, cityValue} = this.props.registerCompany

    switch(_type){
      case 'bussiness_entity':
        if(withContent){
          await this.props.getBussinessEntities();
        }
        break;
      case 'bussiness_industry':
        if(withContent){
          await this.props.getBussinessIndustries();
        }
        break;
      case 'province':
        if(withContent){
          await this.props.getProvinces();
        }
        break;
      case 'city':
        if(withContent){
          await this.props.getCitiesByProvince(provinceValue.id);
        }
        break;
      case 'district':
        if(withContent){
          await this.props.getDistrictsByCity(cityValue.id);
        }
        break;
      case 'position':
        if(withContent){
          await this.props.getJobPositions();
        }
        break;
    }
    
    this.props.setBottomSheetLoading(_type, true);
    this.bottomSheetRegisterCompany.current.snapTo(1);
  }

  componentDidMount() {
    this.props.clearProps();
  }

  render() {
    return (
      <Container style={{ backgroundColor: mainBackground, justifyContent: 'center' }}>
				<StatusBar backgroundColor={mainBlue} barStyle={'light-content'} />
        <Content>
          <View style={{ alignItems: 'center', justifyContent: 'center', height: 100 }}>
            <Image source={LOGO} resizeMode='contain' style={{ width: '20%' }} />
          </View>
          <View
            style={{
              alignItems: 'center',
              alignSelf: 'center',
              justifyContent: 'space-around',
              backgroundColor: '#fff',
              padding: 10,
              width: '90%'
            }}
          >
            <View style={{ alignItems: 'center', width: '100%', marginBottom: 20 }}>
              <Text style={{ fontSize: 20, fontWeight: 'bold', alignSelf: 'center', marginVertical: 15, color: '#000' }}>Daftar Sebagai Perusahaan</Text>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('bussiness_entity') }>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Badan Usaha</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nama Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='NPWP Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nomor Telepon Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nomor Fax Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Alamat Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('province')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Provinsi</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('city')} disabled={true}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Kota</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('district')} disabled={true}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Kecamatan</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('bussiness_industry')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Bisnis Industri</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ width: '100%', height: 50, marginVertical: 10, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
                <Text style={{ fontSize: 20, fontWeight: 'bold', paddingHorizontal: 10 }}>Data Akun</Text>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Email'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1, flexDirection: 'row' }}>
                <TextInput
                  style={{ width: '90%' }}
                  placeholderColor={placeholder}
                  placeholder='Kata Sandi'
                  secureTextEntry={!this.props.registerCompany.showPassword}
                  onChangeText={() => {}}
                />
                <TouchableHighlight onPress={ () => this.props.showPassword() } underlayColor={'#fff'} activeOpacity={0.5}>
                  {
                    this.props.registerCompany.showPassword ?
                    <Icon name='eye-slash' size={20} color={mainBlue} />
                    :
                    <Icon name='eye' size={20} color={mainBlue} />
                  }
                </TouchableHighlight>
              </View>
              <BarPasswordStrengthDisplay password={this.props.registerCompany.password} width={width - 65} wrapperStyle={{ marginBottom: 10 }} />
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Konfirmasi Kata Sandi'
                  secureTextEntry={!this.props.registerCompany.showPassword}
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ width: '100%', height: 50, marginVertical: 10, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
                <Text style={{ fontSize: 20, fontWeight: 'bold', paddingHorizontal: 10 }}>Penanggung Jawab</Text>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('jenis_kelamin')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Jenis Kelamin</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nama Lengkap'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('job_position')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Jabatan</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nomor Handphone'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', marginVertical: 10 }}>
                <TouchableHighlight onPress={ () => {} } underlayColor={'#fff'} activeOpacity={0.5} style={{ width: '100%', justifyContent: 'space-around', alignItems: 'center' }}>
                  <View style={{ width: '100%', flexDirection: 'row' }}>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5 }}>
                      <Icon name='square-o' size={20} color={placeholder} />
                    </View>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5 }}>
                      <Text>Daftar Sebagai EMKL</Text>
                    </View>
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', marginVertical: 10 }}>
                <TouchableHighlight onPress={ () => {} } underlayColor={'#fff'} activeOpacity={0.5} style={{ width: '100%' }}>
                  <View style={{ width: '100%', flexDirection: 'row', paddingHorizontal: 10, justifyContent: 'space-between' }}>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5, marginTop: 5 }}>
                      <Icon name='square-o' size={20} color={placeholder} />
                    </View>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5 }}>
                      <Text>Saya telah membaca dan menyetujui Syarat dan Ketentuan, Kebijakan Privasi, dan Persetujuan Pengguna</Text>
                    </View>
                  </View>
                </TouchableHighlight>
              </View>
            </View>
            <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%' }}>
              <TouchableHighlight style={{ width: '90%', backgroundColor: buttonSuccess, alignItems: 'center', justifyContent: 'center', marginBottom: 20 }}>
                <Text style={{ fontSize: 15, color: '#fff', fontWeight: 'bold', padding: 10 }}>Daftar</Text>
              </TouchableHighlight>
            </View>
          </View>
          <View style={{ position: 'relative', bottom: 0 }}>
            <Text style={{ color: '#000', fontSize: 15, marginVertical: 20, alignSelf: 'center' }}>Sudah Punya Akun? <Text style={{ color: mainBlue, fontSize: 15, fontWeight: 'bold' }} onPress={ () => this.goLogin() }>Masuk disini</Text></Text>
          </View>
        </Content>
        <BottomSheet
          ref={this.bottomSheetRegisterCompany}
          snapPoints={[-1000, width, height*0.9 ]}
          initialSnap={0}
          renderHeader={() => this.headerBottomSheet()}
          renderContent={() => this.contentBottomSheet()}
        />
      </Container>
    );
  }
}

and here is my secon page:

import React, { Component } from 'react';
import { ScrollView, View, Text, Image, TextInput, TouchableHighlight, StatusBar, Dimensions, FlatList } from 'react-native';
import { StackActions, NavigationActions } from 'react-navigation';
import { Container, Content } from 'native-base';
import { BarPasswordStrengthDisplay } from 'react-native-password-strength-meter';
import BottomSheet from 'reanimated-bottom-sheet';
import Icon from 'react-native-vector-icons/FontAwesome';
import { LOGO } from '../../../assets/img';
import { placeholder, buttonSuccess, mainBlue, mainBackground } from '../../../assets/ColorIndex';

const {width, height} = Dimensions.get('screen');

export default class RegisterSupplierScreen extends Component {
  constructor(props) {
    super(props);
    this.bottomSheetRegisterSupplier = React.createRef();
    this.goRegister = this._goRegister.bind(this);
    this.goLogin = this._goLogin.bind(this);
    this.showBottomSheet = this._showBottomSheets.bind(this);
    this.headerBottomSheet = this._renderHeader.bind(this);
    this.contentBottomSheet = this._renderContent.bind(this);
    this.renderItem = this._renderItem.bind(this);
  }

  _goRegister() {
    this.props.navigation.dispatch(StackActions.reset({ index: 0, actions: [ NavigationActions.navigate({ routeName: 'Register' }) ] }));
  }
  
  _goLogin() {
    this.props.navigation.dispatch(StackActions.reset({ index: 0, actions: [ NavigationActions.navigate({ routeName: 'Login' }) ] }));
  }

  _renderHeader() {
    const { bottomSheetActive } = this.props.registerSupplier;

    switch(bottomSheetActive){
      case 'bussiness_entity':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Badan Usaha</Text>
          </View>
        );
      case 'province':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Provinsi</Text>
          </View>
        );
      case 'city':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Kota</Text>
          </View>
        );
      case 'district':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Kecamatan</Text>
          </View>
        );
      case 'bussiness_industry':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Bisnis Industri</Text>
          </View>
        );
      case 'jenis_kelamin':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Jenis Kelamin</Text>
          </View>
        );
      case 'job_position':
        return (
          <View style={{ justifyContent: 'space-around', alignItems: 'center', backgroundColor: mainBackground }}>
            <View style={{ height: 5, width: width*0.2, borderRadius: 20, backgroundColor: placeholder, marginVertical: 10 }} />
            <Text style={{ fontWeight: 'bold', fontSize: 18, marginBottom: 5 }}>Pilih Jabatan</Text>
          </View>
        );
    }
  }

  _renderContent(){
    const { bottomSheetActive } = this.props.registerSupplier;
    const { bussinessEntities, bussinessIndustries, provinces, cities, districts, jenisKelamin, jobPositions } = this.props.masterData;

    switch(bottomSheetActive){
      case 'bussiness_entity':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(bussinessEntities.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `bussinessEntities-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={bussinessEntities}
              scrollEnabled={false}
            />
          </View>
        );
      case 'bussiness_industry':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(bussinessIndustries.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `bussinessIndustries-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={bussinessIndustries}
              scrollEnabled={false}
            />
          </View>
        );
      case 'province':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(provinces.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `provinces-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={provinces}
              scrollEnabled={false}
            />
          </View>
        );
      case 'city':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(cities.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `cities-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={cities}
              scrollEnabled={false}
            />
          </View>
        );
      case 'district':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(districts.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `districts-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={districts}
              scrollEnabled={false}
            />
          </View>
        );
      case 'jenis_kelamin':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(jenisKelamin.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `jenisKelamin-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={jenisKelamin}
              scrollEnabled={false}
            />
          </View>
        );
      case 'job_position':
        return (
          <View style={{ backgroundColor: mainBackground, height: Math.max(jobPositions.length*45+15, 40), minHeight: height*0.9 }}>
            <FlatList
              keyExtractor={item => `jobPositions-${item.id}`}
              renderItem={({item}) => this.renderItem(item)}
              data={jobPositions}
              scrollEnabled={false}
            />
          </View>
        );
    }
  }

  _renderItem(item) {
    return (
      <TouchableHighlight style={{ padding: 10 }}>
        <View style={{ justifyContent: 'space-between', alignItems: 'center', flexDirection: 'row' }}>
          <View style={{ justifyContent: 'flex-start', alignItems: 'flex-start', paddingHorizontal: 10 }}>
            <Text style={{ fontWeight: 'bold', fontSize: 18 }}>{item.name}</Text>
          </View>
          <Icon name='circle-o' size={20} color={mainBlue} />
        </View>
      </TouchableHighlight>
    );
  }

  async _showBottomSheets(type, withContent = true) {
    
    const _type = type.toLowerCase();
    // const {provinceValue, cityValue} = this.props.registerSupplier
    
    switch(_type){
      case 'bussiness_entity':
      if(withContent){
          await this.props.getBussinessEntities();
        }
        break;
      case 'bussiness_industry':
        if(withContent){
          await this.props.getBussinessIndustries();
        }
        break;
      case 'province':
        if(withContent){
          await this.props.getProvinces();
        }
        break;
      case 'city':
        if(withContent){
          // await this.props.getCitiesByProvince(provinceValue.id);
        }
        break;
      case 'district':
        if(withContent){
          // await this.props.getDistrictsByCity(cityValue.id);
        }
        break;
      case 'position':
        if(withContent){
          await this.props.getJobPositions();
        }
        break;
    }
    
    await this.props.setBottomSheetLoading(_type, true);
    this.bottomSheetRegisterSupplier.current.snapTo(1);
    console.warn('after '+this.props.registerSupplier.bottomSheetActive);
  }
  
  componentDidMount() {
    this.props.clearProps();
  }

  render() {
    return (
      <Container style={{ backgroundColor: mainBackground, justifyContent: 'center' }}>
				<StatusBar backgroundColor={mainBlue} barStyle={'light-content'} />
        <Content>
          <View style={{ alignItems: 'center', justifyContent: 'center', height: 100 }}>
            <Image source={LOGO} resizeMode='contain' style={{ width: '20%' }} />
          </View>
          <View
            style={{
              alignItems: 'center',
              alignSelf: 'center',
              justifyContent: 'space-around',
              backgroundColor: '#fff',
              padding: 10,
              width: '90%'
            }}
          >
            <View style={{ alignItems: 'center', width: '100%', marginBottom: 20 }}>
              <Text style={{ fontSize: 20, fontWeight: 'bold', alignSelf: 'center', marginVertical: 15, color: '#000' }}>Daftar Sebagai Supplier</Text>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('bussiness_entity') }>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Badan Usaha</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nama Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='NPWP Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Alamat Perusahaan'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('province')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Provinsi</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('city')} disabled={true}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Kota</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('district')} disabled={true}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Kecamatan</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('bussiness_industry')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Bisnis Industri</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ width: '100%', height: 50, marginVertical: 10, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
                <Text style={{ fontSize: 20, fontWeight: 'bold', paddingHorizontal: 10 }}>Data Akun</Text>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Email'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <View style={{ alignItems: 'center', flexDirection: 'row', width: '100%' }}>
                  <TextInput
                    style={{ width: '90%' }}
                    placeholderColor={placeholder}
                    placeholder='Kata Sandi'
                    secureTextEntry={!this.props.registerSupplier.showPassword}
                    onChangeText={() => {}}
                  />
                  <TouchableHighlight onPress={ () => {} } underlayColor={'#fff'} activeOpacity={0.5}>
                    {
                      this.props.registerSupplier.showPassword ?
                      <Icon name='eye-slash' size={20} color={mainBlue} />
                      :
                      <Icon name='eye' size={20} color={mainBlue} />
                    }
                  </TouchableHighlight>
                </View>
                <BarPasswordStrengthDisplay password={this.props.registerSupplier.password} width={width - 65} wrapperStyle={{ marginVertical: 10 }} />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Konfirmasi Kata Sandi'
                  secureTextEntry={!this.props.registerSupplier.showPassword}
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ width: '100%', height: 50, marginVertical: 10, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
                <Text style={{ fontSize: 20, fontWeight: 'bold', paddingHorizontal: 10 }}>Penanggung Jawab</Text>
                <View style={{ borderBottomWidth: 2, borderBottomColor: mainBackground, flexGrow: 1 }} />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('jenis_kelamin')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Jenis Kelamin</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nama Lengkap'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TouchableHighlight onPress={() => this.showBottomSheet('job_position')}>
                  <View style={{ alignItems: 'center', justifyContent: 'space-between', flexDirection: 'row', paddingVertical: 10 }}>
                    <Text style={{ color: placeholder, fontSize: 15, maxWidth: '94%', minWidth: '94%' }}>Pilih Jabatan</Text>
                    <Icon name='sort' size={20} color={'#000'} />
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nomor Handphone'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nomor Telepon'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', borderBottomColor: mainBackground, borderBottomWidth: 1 }}>
                <TextInput
                  style={{ width: '100%' }}
                  placeholderColor={placeholder}
                  placeholder='Nomor Fax'
                  onChangeText={() => {}}
                />
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', marginVertical: 10 }}>
                <TouchableHighlight onPress={ () => {} } underlayColor={'#fff'} activeOpacity={0.5} style={{ width: '100%', justifyContent: 'space-around', alignItems: 'center' }}>
                  <View style={{ width: '100%', flexDirection: 'row' }}>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5 }}>
                      <Icon name='square-o' size={20} color={placeholder} />
                    </View>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5 }}>
                      <Text>PKP ( Perusahaan Kena Pajak )</Text>
                    </View>
                  </View>
                </TouchableHighlight>
              </View>
              <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%', marginVertical: 10 }}>
                <TouchableHighlight onPress={ () => {} } underlayColor={'#fff'} activeOpacity={0.5} style={{ width: '100%', justifyContent: 'space-around', alignItems: 'center' }}>
                  <View style={{ width: '100%', flexDirection: 'row' }}>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5 }}>
                      <Icon name='square-o' size={20} color={placeholder} />
                    </View>
                    <View style={{ justifyContent: 'flex-start', alignItems: 'center', marginHorizontal: 5 }}>
                      <Text>Saya telah membaca dan menyetujui Syarat dan Ketentuan, Kebijakan Privasi, dan Persetujuan Pengguna </Text>
                    </View>
                  </View>
                </TouchableHighlight>
              </View>
            </View>
            <View style={{ alignItems: 'center', justifyContent: 'center', width: '100%' }}>
              <TouchableHighlight style={{ width: '90%', backgroundColor: buttonSuccess, alignItems: 'center', justifyContent: 'center', marginBottom: 20 }}>
                <Text style={{ fontSize: 15, color: '#fff', fontWeight: 'bold', padding: 10 }}>Daftar</Text>
              </TouchableHighlight>
            </View>
          </View>
          <View style={{ position: 'relative', bottom: 0 }}>
            <Text style={{ color: '#000', fontSize: 15, marginVertical: 20, alignSelf: 'center' }}>Sudah Punya Akun? <Text style={{ color: mainBlue, fontSize: 15, fontWeight: 'bold' }} onPress={ () => this.goLogin() }>Masuk disini</Text></Text>
          </View>
          <BottomSheet
            ref={this.bottomSheetRegisterSupplier}
            snapPoints={[0, width, height*0.9 ]}
            renderHeader={() => this.headerBottomSheet()}
            renderContent={() => this.contentBottomSheet()}
          />
        </Content>
      </Container>
    );
  }
}

I hope it can solved/closed ASAP.
cheers

Add unit tests

Hi there,

I'm thinking of setting up some unit tests for this package. I decided to create an issue because I wasn't sure if someone is already working on this or not.

If you would like me to do it, then please upvote.

Otherwise, close it if it's in progress by someone else or not needed.

Unable to set initialSnapPoint after changing snapPoints

I would like the closed sheet to have height of 124. However, I need to fetch data to see how high the content will be, and once I update the state to update the snapPoints, the sheet no longer snaps to 124.

Could you support updating snapPoints by ref?

Inside render:

` var snapPoints = [];
    var closedIndex = 0;
    if (this.state.height != "60%" && this.state.height < 124) {
      snapPoints = [124, this.state.height];
    } else {
      snapPoints = [this.state.height, 124];
      closedIndex = 1;
    }
    return (
      <Container style={{ flex: 1 }}>
        <BottomSheet
          renderContent={this.renderSheetContent.bind(this)}
          renderHeader={this.renderSheetHeader.bind(this)}
          snapPoints={snapPoints}
          initialSnap={closedIndex}
          ref={this._bottomSheet}
        />
      </Container>`

Close sheet when top of FlatList is reached

Hey! Great lib!

Is it possible to add a FlatList to content and use that scroll position when the bottom sheet should expand or not?

Like the apple map, when the list is in the top and you move upwards, the sheat goes up. but when you scroll down the sheet stays until the user scroll to the top of the list within.

Is it possible to hook up using this or should I go custom with reanimates and gesture handler?

Getting issues with TextInput and other touchables on android - A very random behavior

When I use Bottomsheet in a screen, In a very random manner, I am unable to type any thing in a TextInput and also sometimes unable to tap the touchables in that particular screen. This is only happening on Android.

I have to re-open the app to make it work fine again and also sometimes I have to clear the data and open again.

When not using BottomSheet, this error doesn't occur.

I am not sure if this is issue with the bottomsheet, but if you have faced this before with anything, please do let me know.

Updating sheet position after snapPoints change

It doesn't appear that the position of the sheet changes if the snapPoints props are changed. Is there any way to make this work? Or is that not supported?

It would be nice to have the positions be dynamic based on content heights, where the snapPoints are defined from state values set in onLayout callbacks of the sheet elements.

Add a way to read current index

This project is great and shows a lot of promise, but currently, there is no way to read the current index of the sheet and wanted to propose a feature to read this state

Perhaps we can add a function prop onIndexChange(prev, current) that the user would pass in that would get called anytime the current index changes.

Over-drag with resistance

It'd be nice to have an option to allow you to drag past the highest snap point, but gesture translation past that snap point shouldn't result in 1:1 translation of the sheet, so it feels like there is some resistance. On release it should then bounce back to the highest snap point.

If you over-drag and the content is scrollable for as far as you can over-drag, you should see more of the scrollable content appear. (nevermind, it actually should just continue into scroll at the snap point)

If the content is not scrollable, we will need to have some way to style the area that is visible below 'content'. I'm bad at explaining so let's just look at a video. Notice that it's not scrollable, and the sheet style continues when we over-drag.

twitter-sheet

GestureState.CANCELLED breaks snapTo

Here is my problem:

  • Inside bottom sheet content I have a button that pushes new navigation screen to stack (covering bottom sheet)
  • Clicking outside the bottom sheet imperatively closes it using snapTo
  • After I pop back to the screen with bottom sheet, snapTo no longer works
  • This is happening on Android only

I debugged the issue shallowly, and I think the problem is that when the screen gets pushed above bottom sheet, panMasterState is set to CANCELLED and never comes back to END (unless dragged manually).

I was able to hack my way around this by overriding panMasterState. It seems to work, but I need to test it more. I think proper handling of CANCELLED state is required, because it's as valid outcome of gesture handling flow as END

this.translateMaster = block([
      // TODO: this is a HACK
      cond(
        eq(this.panMasterState, GestureState.CANCELLED),
        set(this.panMasterState, GestureState.END),
      ),
      // END OF HACK
      cond(
        eq(this.panMasterState, GestureState.END),
    

Using strings in snapPoints prop throws an exception

Setting snapPoints={['50%', '10%']} causes the component to throw the following exception:

Exception thrown while executing UI block: -[NSNull doubleValue]: unrecognized selector sent to instance 0x10ca14f28

__44-[RCTUIManager flushUIBlocksWithCompletion:]_block_invoke
    RCTUIManager.m:1114
__44-[RCTUIManager flushUIBlocksWithCompletion:]_block_invoke.544
__RCTExecuteOnMainQueue_block_invoke
_dispatch_call_block_and_release
_dispatch_client_callout
_dispatch_main_queue_callback_4CF
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
__CFRunLoopRun
CFRunLoopRunSpecific
GSEventRunModal
UIApplicationMain
main
start

Preview

image

Configuration


  React Native Environment Info:
    System:
      OS: macOS 10.14.2
      CPU: x64 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
      Memory: 27.74 MB / 16.00 GB
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 8.12.0 - ~/.nvm/versions/node/v8.12.0/bin/node
      Yarn: 1.6.0 - /usr/local/bin/yarn
      npm: 6.4.1 - ~/.nvm/versions/node/v8.12.0/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
      Android SDK:
        Build Tools: 26.0.3, 27.0.3, 28.0.2, 28.0.3
        API Levels: 21, 22, 23, 24, 25, 26, 27
    IDEs:
      Android Studio: 3.1 AI-173.4907809
      Xcode: 10.1/10B61 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.6.3 => 16.6.3
      react-native: 0.57.8 => 0.57.8
    npmGlobalPackages:
      react-native-log-ios: 1.0.1

Workaround: use numbers for now.

Unable to call snapTo() when render TextInput in Bottom Sheet Header

First of all, ty for this library ;)
I have issue probably related to #15 . When i try to render TextInput in header (renderHeader) it is means that snapTo() broken

renderBottomSheetHeader = () => (
        <View style={styles.sheetHeaderContainer}>
            <Marker />
            <Search
                onChangeText={() => {}}
            />
        </View>
    );

const Search = () => {
   
        return (
            <View style={style || styles.searchContainer}>
                <TextInput
                    {...inputProps}
                    style={styles.searchInput}
                    placeholder={l10n.searchPlaceholder}
                    placeholderTextColor={constants.defaultIconColor}
                    underlineColorAndroid={'transparent'}
                    onChangeText={(text) => {
                        this.setState({ message: text });
                        this.onChangeTextDelayed(text);
                    }}
                    value={this.state.message}
                    multiline={false}
                />
            </View>
        );

It is also reproduce with TextInput from react-native-gesture-handler

not sliding up

trying to slide up but not working.

          <View style={{flex:1,backgroundColor:'#fff',height:'100%'}}>
            <BottomSheet
              snapPoints = {[450,200]}
              renderContent = {this.renderInner}
              renderHeader = {this.renderHeader}
              initialSnap={1}
            />
            <Animated.View style={{ alignItems: 'center', opacity: Animated.add(0.1, Animated.multiply(this.fall, 0.9)) }}>
              {this.map()}
            </Animated.View>
          </View>

[fixed ]Does not render anything in RN 59.5 for both iOS and Android :(

I'm using the latest version as of today alpha.8 and react-native 59.5 and the exact same code I had before the upgrade now does not render anything anymore on both iOS and Android 😢 😭

I get no errors or warnings 😮

I've tried all released alpha versions 3,4,5,6,7,8.

Has anyone got this library working with the latest react-native 59.5?

I've changed the BottomSheet to just use defaults for everything and still can't get it to render anything. I'm using it just like this:

<BottomSheet
          snapPoints={[
            100,
            200,
          ]}
          initialSnap={1}
          renderContent={() =>
            <View><Text>Hello Header!</Text></View>
          }
          renderHeader={() => <View><Text>Hello Content!</Text></View>}
        />

I can't provide a link because expo doesn't use latest RN 59.5 atm.

React Native Environment Info:
    System:
      OS: macOS 10.14.4
      CPU: x64 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
      Memory: 1018.41 MB / 16.00 GB
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 8.12.0 - ~/.nvm/versions/node/v8.12.0/bin/node
      Yarn: 1.6.0 - /usr/local/bin/yarn
      npm: 6.4.1 - ~/.nvm/versions/node/v8.12.0/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2
      Android SDK:
        Build Tools: 26.0.3, 27.0.3, 28.0.2, 28.0.3
        API Levels: 21, 22, 23, 24, 25, 26, 27, 28
    IDEs:
      Android Studio: 3.1 AI-173.4907809
      Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.3 => 16.8.3
      react-native: 0.59.5 => 0.59.5
    npmGlobalPackages:
      react-native-log-ios: 1.0.1

Send help plz 👍 🙏

[Suggestions Needed] How would you render dynamic components in the bottomsheet ?

I want to render components in bottomsheet dynamically. For example, I have a list of vendors which I can follow or unfollow. A user can follow the vendor by clicking Follow button inside bottomsheet. The button will change to Unfollow now when the user opens bottomsheet.

I know, we can use states to manage the content inside bottomsheet.
How would you perform this behavior also minimizing the number of renders ?

[Suggestion Needed] Dismissing bottom sheet when tapping outside of bottom sheet

Hi. Great component! This is working fantastic so far. One thing I haven't figure out is a way to easily dismiss it when tapping outside of the sheet. I can easily dismiss it programmatically by using snapTo(index) however when the sheet is raised I am not sure how to intercept these taps to prevent it from tapping on content underneath.

Thank you!

snapPoints

I spent all morning debugging - please add to docs that snapPoints array must be descending. If ascending nothing works and you lose hours of your life staring in to the darkness that is despair because 'nothing makes sense.' Ty.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.