All Projects → rgommezz → React Native Scroll Bottom Sheet

rgommezz / React Native Scroll Bottom Sheet

Licence: mit
Cross platform scrollable bottom sheet with virtualisation support, native animations at 60 FPS and fully implemented in JS land 🔥

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to React Native Scroll Bottom Sheet

Bottomify Navigation View
A nice looking Spotify like bottom navigation view
Stars: ✭ 97 (-92.09%)
Mutual labels:  bottomsheet, bottom-sheet
React Native Bottomsheet Reanimated
React Native bottom sheet with fully native 60 FPS animations and awesome user experience
Stars: ✭ 80 (-93.47%)
Mutual labels:  bottomsheet, bottom-sheet
BottomSheetBehavior
BottomSheetBehavior is an android library extracted from the Google I/O 2018 application source code.
Stars: ✭ 12 (-99.02%)
Mutual labels:  bottom-sheet, bottomsheet
Stickytabbarviewcontroller
Sticky and Collapsible View on top of tab bar
Stars: ✭ 82 (-93.31%)
Mutual labels:  bottomsheet, bottom-sheet
React Native Bottom Sheet
A performant interactive bottom sheet with fully configurable options 🚀
Stars: ✭ 2,695 (+119.82%)
Mutual labels:  bottomsheet, bottom-sheet
react-spring-bottom-sheet
Accessible ♿️, Delightful ✨, & Fast 🚀
Stars: ✭ 604 (-50.73%)
Mutual labels:  bottom-sheet, bottomsheet
Ubottomsheet
iPhone Maps App bottom sheet - A Protocol Oriented Approach
Stars: ✭ 259 (-78.87%)
Mutual labels:  bottomsheet, bottom-sheet
Xena
Lightweight, lighting-fast Java Based Cross-Platform CSGO Cheat
Stars: ✭ 69 (-94.37%)
Mutual labels:  cross-platform
Google Play Music Desktop Player Unofficial
A beautiful cross platform Desktop Player for Google Play Music
Stars: ✭ 8,459 (+589.97%)
Mutual labels:  cross-platform
Openatdeluxe
The open source remake of Airline Tycoon Deluxe
Stars: ✭ 69 (-94.37%)
Mutual labels:  cross-platform
Flutter Ui Showcase
FLUTTER UI Showcase
Stars: ✭ 68 (-94.45%)
Mutual labels:  cross-platform
Cross Platform Node Guide
📗 How to write cross-platform Node.js code
Stars: ✭ 1,161 (-5.3%)
Mutual labels:  cross-platform
Waveboxapp
Wavebox Classic has been updated to Wavebox 10. Learn more Wavebox.io
Stars: ✭ 1,198 (-2.28%)
Mutual labels:  cross-platform
Electron
This is the repository for my course, Electron: Building Cross Platform Desktop Apps on LinkedIn Learning and Lynda.com.
Stars: ✭ 69 (-94.37%)
Mutual labels:  cross-platform
Aws Sdk Cpp
AWS SDK for C++
Stars: ✭ 1,204 (-1.79%)
Mutual labels:  cross-platform
Nitroshare Desktop
Network file transfer application for Windows, OS X, & Linux
Stars: ✭ 1,150 (-6.2%)
Mutual labels:  cross-platform
Arcgis Appstudio Samples
Collection of samples available in AppStudio for ArcGIS desktop to learn and help build your next app.
Stars: ✭ 78 (-93.64%)
Mutual labels:  cross-platform
Awesome Hpp
A curated list of awesome header-only C++ libraries
Stars: ✭ 1,198 (-2.28%)
Mutual labels:  cross-platform
Tvtower
A tribute to Mad TV. Written in BlitzMax, Lua and a bit of C.
Stars: ✭ 73 (-94.05%)
Mutual labels:  cross-platform
Traffic Shm
traffic-shm (Anna) is a Java based lock free IPC library.
Stars: ✭ 72 (-94.13%)
Mutual labels:  cross-platform

Scroll Bottom Sheet

npm npm bundle size platforms: ios, android, web license MIT

Cross platform scrollable bottom sheet with virtualisation support and fully native animations, that integrates with all core scrollable components from React Native: FlatList, ScrollView and SectionList. Also, it's 100% compatible with Expo.



Features

  • :electron: Virtualisation support: FlatList and SectionList components are 1st class citizens, as well as ScrollView
  • 🔥 Performant: runs at 60 FPS even on low grade Android devices
  • ✅ Horizontal mode: allows for nice implementation of Google or Apple Maps bottom sheets types, where you have several horizontal lists embedded
  • ⚙️ Minimalistic: exposes a set of fundamental props to easily control its behaviour, supporting both Timing and Spring animations
  • 👇 Support for interruptions: animations can be interrupted anytime smoothly without sudden jumps
  • 😎 Imperative snapping: for cases where you need to close the bottom sheet by pressing an external touchable
  • 🚀 Animate all the things: you can animate other elements on the screen based on the bottom sheet position
  • 💪 No native dependencies: fully implemented in JS land, thanks to the powerful Gesture Handler and Reanimated libraries
  • 📱 Expo compatible: no need to eject to enjoy this component!
  • 🛠 TS definitions: For those of you like me who can't look back to start a project in plain JS

Installation

npm

npm i react-native-scroll-bottom-sheet

yarn

yarn add react-native-scroll-bottom-sheet

If you don't use Expo, you also need to install react-native-gesture-handler and react-native-reanimated libraries along with this one.

It's recommended you install a version of gesture handler equal or higher than 1.6.0, and for reanimated, equal or higher than 1.7.0. Otherwise you may run into unexpected errors. This library is also compatible with reanimated 2.x, starting with react-native-reanimated: 2.0.0-alpha.4.

Usage

The below is an example using the core FlatList from React Native as the scrollable component.

import React from 'react';
import { Dimensions, StyleSheet, Text, View } from 'react-native';
import ScrollBottomSheet from 'react-native-scroll-bottom-sheet';

const windowHeight = Dimensions.get('window').height;

function Example() {
  return (
    <View style={styles.container}>
      <ScrollBottomSheet<string> // If you are using TS, that'll infer the renderItem `item` type
        componentType="FlatList"
        snapPoints={[128, '50%', windowHeight - 200]}
        initialSnapIndex={2}
        renderHandle={() => (
          <View style={styles.header}>
            <View style={styles.panelHandle} />
          </View>
        )}
        data={Array.from({ length: 200 }).map((_, i) => String(i))}
        keyExtractor={i => i}
        renderItem={({ item }) => (
          <View style={styles.item}>
            <Text>{`Item ${item}`}</Text>
          </View>
        )}
        contentContainerStyle={styles.contentContainerStyle}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  contentContainerStyle: {
    padding: 16,
    backgroundColor: '#F3F4F9',
  },
  header: {
    alignItems: 'center',
    backgroundColor: 'white',
    paddingVertical: 20,
    borderTopLeftRadius: 20,
    borderTopRightRadius: 20
  },
  panelHandle: {
    width: 40,
    height: 2,
    backgroundColor: 'rgba(0,0,0,0.3)',
    borderRadius: 4
  },
  item: {
    padding: 20,
    justifyContent: 'center',
    backgroundColor: 'white',
    alignItems: 'center',
    marginVertical: 10,
  },
});

Props

There are 2 types of props this component receives: explicit and inherited.

Explicit

This is the list of exclusive props that are meant to be used to customise the bottom sheet behaviour.

Name Required Type Description
componentType yes string 'FlatList', 'ScrollView', or 'SectionList'
snapPoints yes Array<string | number> Array of numbers and/or percentages that indicate the different resting positions of the bottom sheet (in dp or %), starting from the top. If a percentage is used, that would translate to the relative amount of the total window height. If you want that percentage to be calculated based on the parent available space instead, for example to account for safe areas or navigation bars, use it in combination with topInset prop
initialSnapIndex yes number Index that references the initial resting position of the drawer, starting from the top
renderHandle yes () => React.ReactNode Render prop for the handle, should return a React Element
onSettle no (index: number) => void Callback that is executed right after the bottom sheet settles in one of the snapping points. The new index is provided on the callback
animationType no string timing (default) or spring
animationConfig no TimingConfig or SpringConfig Timing or Spring configuration for the animation. If animationType is timing, it uses by default a timing configuration with a duration of 250ms and easing fn Easing.inOut(Easing.linear). If animationType is spring, it uses this default spring configuration. You can partially override any parameter from the animation config as per your needs
animatedPosition no Animated.Value<number> Animated value that tracks the position of the drawer, being: 0 => closed, 1 => fully opened
topInset no number This value is useful to provide an offset (in dp) when applying percentages for snapping points
innerRef no RefObject Ref to the inner scrollable component (ScrollView, FlatList or SectionList), so that you can call its imperative methods. For instance, calling scrollTo on a ScrollView. In order to so, you have to use getNode as well, since it's wrapped into an animated component: ref.current.getNode().scrollTo({y: 0, animated: true})
containerStyle no StyleProp<ViewStyle> Style to be applied to the container (Handle and Content)
friction no number Factor of resistance when the gesture is released. A value of 0 offers maximum * acceleration, whereas 1 acts as the opposite. Defaults to 0.95
enableOverScroll no boolean Allow drawer to be dragged beyond lowest snap point

Inherited

Depending on the value of componentType chosen, the bottom sheet component will inherit its underlying props, being one of FlatListProps, ScrollViewProps or SectionListProps, so that you can tailor the scrollable content behaviour as per your needs.

Methods

snapTo(index)

Imperative method to snap to a specific index, i.e.

bottomSheetRef.current.snapTo(0)

bottomSheetRef refers to the ref passed to the ScrollBottomSheet component.

Compatibility table

You may add some touchable components inside the bottom sheet or several FlatList widgets for horizontal mode. Unfortunately, not all interactable React Native components are compatible with this library. This is due to some limitations on react-native-gesture-handler, which this library uses behind the scenes. For that, please follow this compatibility table:

Import Touchable Flatlist
react-native iOS 🚫
react-native-gesture-handler Android Android, iOS

Touchables

As you can see on the table, for any touchable component (TouchableOpacity, TouchableHighlight, ...) you need to have different imports depending on the platform. The below is a snippet you may find useful to abstract that into a component.

import React from "react";
import { Platform, TouchableOpacity } from "react-native";
import { TouchableOpacity as RNGHTouchableOpacity } from "react-native-gesture-handler";

const BottomSheetTouchable = (props) => {
  if (Platform.OS === "android") {
    return (
      <RNGHTouchableOpacity {...props} />
    );
  }

  return <TouchableOpacity {...props} />
};

export default BottomSheetTouchable;

Horizontal Mode

For this mode to work properly, you have to import FlatList from react-native-gesture-handler instead of react-native.

import { FlatList } from 'react-native-gesture-handler';

...

Limitations

At the moment, the component does not support updating snap points via state, something you may want to achieve when changing device orientation for instance. A temporary workaround is to leverage React keys to force a re-mount of the component. This is some illustrative code to give you an idea how you could handle an orientation change with keys:

import { useDimensions } from '@react-native-community/hooks'

const useOrientation = () => {
  const { width, height } = useDimensions().window;

  if (height > width) {
    return 'portrait'
  }

  return 'landscape'
}

const OrientationAwareBS = () => {
	const orientation = useOrientation();
	const snapPoints = {
		portrait: [...],
		landscape: [...]
	}

	return (
      <ScrollBottomSheet
 		key={orientation}
        componentType="FlatList"
        snapPoints={snapPoints[orientation]}
        initialSnapIndex={2}
        ...
      />
	);
}

Example

There is an Expo example application that you can play with to get a good grasp on the different customisation options. In case of Android, you can directly open the project here. For iOS, head to the example folder and run the project locally:

$ npm install

$ npm start

Typescript

The library has been written in Typescript, so you'll get type checking and autocompletion if you use it as well.

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].