Giter Club home page Giter Club logo

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

Reanimated Bottom Sheet

Highly configurable component imitating native bottom sheet behavior, with fully native 60 FPS animations!

Built from scratch with react-native-gesture-handler and react-native-reanimated.

Usable with Expo with no extra native dependencies!

Installation

Open a Terminal in the project root and run:

yarn add reanimated-bottom-sheet

Or if you use npm:

npm install reanimated-bottom-sheet

Now we need to install react-native-gesture-handler and react-native-reanimated.

If you are using Expo, to ensure that you get the compatible versions of the libraries, run:

expo install react-native-gesture-handler react-native-reanimated

If you are not using Expo, run the following:

yarn add react-native-reanimated react-native-gesture-handler

Or if you use npm:

npm install react-native-reanimated react-native-gesture-handler

We're done! Now you can build and run the app on your device/simulator.

Usage

import * as React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import Animated from 'react-native-reanimated';
import BottomSheet from 'reanimated-bottom-sheet';

export default function App() {
  const renderContent = () => (
    <View
      style={{
        backgroundColor: 'white',
        padding: 16,
        height: 450,
      }}
    >
      <Text>Swipe down to close</Text>
    </View>
  );

  const sheetRef = React.useRef(null);

  return (
    <>
      <View
        style={{
          flex: 1,
          backgroundColor: 'papayawhip',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        <Button
          title="Open Bottom Sheet"
          onPress={() => sheetRef.current.snapTo(0)}
        />
      </View>
      <BottomSheet
        ref={sheetRef}
        snapPoints={[450, 300, 0]}
        borderRadius={10}
        renderContent={renderContent}
      />
    </>
  );
}

Props

name required default description
snapPoints yes E.g. [300, 200, 0]. Points for snapping of bottom sheet coomponent. They define distance from bottom of the screen. Might be number or percent (as string e.g. '20%') for points or percents of screen height from bottom. Note: Array values must be in descending order.
initialSnap no 0 Determines initial snap point of bottom sheet. The value is the index from snapPoints.
renderContent no Method for rendering scrollable content of bottom sheet.
renderHeader no Method for rendering non-scrollable header of bottom sheet.
enabledGestureInteraction no true Defines if bottom sheet could be scrollable by gesture.
enabledHeaderGestureInteraction no true Defines if bottom sheet header could be scrollable by gesture.
enabledContentGestureInteraction no true Defines if bottom sheet content could be scrollable by gesture.
enabledContentTapInteraction no true Defines whether bottom sheet content could be tapped. Note: If you use Touchable* components inside your renderContent, you'll have to switch this to false to make handlers like onPress work. (See this comment.)
enabledManualSnapping no true If false blocks snapping using snapTo method.
enabledBottomClamp no false If true block movement is clamped from bottom to minimal snapPoint.
enabledBottomInitialAnimation no false If true sheet will grows up from bottom to initial snapPoint.
enabledInnerScrolling no true Defines whether it's possible to scroll inner content of bottom sheet.
callbackNode no reanimated node which holds position of bottom sheet, where 0 it the highest snap point and 1 is the lowest.
contentPosition no reanimated node which holds position of bottom sheet's content (in dp)
headerPosition no reanimated node which holds position of bottom sheet's header (in dp)
overdragResistanceFactor no 0 `Defines how violently sheet has to stopped while overdragging. 0 means no overdrag
springConfig no { } Overrides config for spring animation
innerGestureHandlerRefs no Refs for gesture handlers used for building bottom sheet. The array consists fo three refs. The first for PanGH used for inner content scrolling. The second for PanGH used for header. The third for TapGH used for stopping scrolling the content.
simultaneousHandlers no Accepts a react ref object or an array of refs to handler components.
onOpenStart no Accepts a function to be called when the bottom sheet starts to open.
onOpenEnd no Accepts a function to be called when the bottom sheet is almost fully openned.
onCloseStart no Accepts a function to be called when the bottom sheet starts to close.
onCloseEnd no Accepts a function to be called when the bottom sheet is almost closing.
callbackThreshold no 0.01 Accepts a float value from 0 to 1 indicating the percentage (of the gesture movement) when the callbacks are gonna be called.
borderRadius no Border radius of content wrapper (excluding header)

Methods

snapTo(index)

Imperative method on for snapping to snap point in given index. E.g.

// Snap to the snap point at index 0 (e.g. 450 in [450, 300, 0])
this.bottomSheetRef.current.snapTo(0)

Here this.bottomSheetRef refers to the ref passed to the BottomSheet component.

Example

More complex examples can be found in the Example folder. To view the examples in the Expo app, open a Terminal and run:

yarn
yarn prepare
cd Example
yarn
expo start

The example app is also available on Expo.

Todo

It's not finished and some work has to be done yet.

  1. Play with magic config values
  2. Horizontal mode
  3. Deal with GH in inner scrollView
  4. Cleanup code (e.g. measuring of components)

Contributing

Publishing a release

We use release-it to automate our release. If you have publish access to the NPM package, run the following from the master branch to publish a new release:

yarn release

NOTE: You must have a GITHUB_TOKEN environment variable available. You can create a GitHub access token with the "repo" access here.

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

Contributors

0duaht avatar ahmaddehnavi avatar annihil avatar brentvatne avatar brtqkr avatar codebutler avatar davidgovea avatar dependabot[bot] avatar eyesonly88 avatar franjorub avatar gorhom avatar hanford avatar hosseinmd avatar iamolegga avatar itsyogesh avatar jayu avatar jmacindoe avatar jtomaszewski avatar lluchkaa avatar lucasklimek avatar osdnk avatar rgoldiez avatar rodolfovilaca avatar roshangm1 avatar russ666 avatar satya164 avatar sebqq avatar timothystewart6 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

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

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

[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!

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!

[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!

[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 ?

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;

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.

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.

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

[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.

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

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.

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

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 ๐Ÿ‘‹

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>

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.

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.

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

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.

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.

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>`

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.

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

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

Callback onClose

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

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.

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.

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

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?

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.

[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 ๐Ÿ‘ ๐Ÿ™

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

[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 ) ๐Ÿฅ‚

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

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.