Giter Club home page Giter Club logo

react-native-pager's Introduction

react-native-pager

Fully controllable, high performance pager component w/ gesture support for React Native

Installation

yarn add @crowdlinker/react-native-pager

If you're using expo, all dependencies are already installed by default. If not, you'll need to install two dependencies along with this library:

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

There are additional steps to setting these up:

Examples

These examples were inspired by the docs of the awesome react-native-snap-carousel library

Basic Pager

<Pager initialIndex={2}>
  <Screen />
  <Screen />
  <Screen />
  <Screen />
  <Screen />
</Pager>

Controlled Pager

From App.js in /example directory

// App.js
import React, {useState} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  Button,
  Alert,
  TouchableOpacity,
} from 'react-native';

console.disableYellowBox = true;

import {Pager} from '../src';

const colors = [
  'coral',
  'aquamarine',
  'gold',
  'cadetblue',
  'crimson',
  'darkorange',
  'darkmagenta',
  'salmon',
];

const screens = Array.from({length: 10}, (c, i) => (
  <View
    key={i}
    style={{
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: colors[i % colors.length],
    }}>
    <Text>{`Screen: ${i}`}</Text>
    <Button title="Hello" onPress={() => Alert.alert('Joe')} />
  </View>
));


const App = () => {
  const [activeIndex, onChange] = useState(0);

  return (
    <SafeAreaView style={{flex: 1}}>
      <Pager
        activeIndex={activeIndex}
        onChange={onChange}
        adjacentChildOffset={2}>
        {screens}
      </Pager>

      <Buttons activeIndex={activeIndex} setActiveIndex={onChange} />
    </SafeAreaView>
  );
};

function Buttons({activeIndex, onChange}) {
  return (
    <View style={{height: 75, width: '100%'}}>
      <Text
        style={{
          fontSize: 16,
          height: 25,
          textAlign: 'center',
        }}>{`activeIndex: ${activeIndex}`}</Text>

      <View style={{flex: 1, flexDirection: 'row'}}>
        <TouchableOpacity
          title="Dec"
          style={{
            flex: 1,
            borderWidth: StyleSheet.hairlineWidth,
            borderRadius: 4,
            alignItems: 'center',
            justifyContent: 'center',
          }}
          onPress={() => onChange(activeIndex - 1)}>
          <Text>{`<`}</Text>
        </TouchableOpacity>

        <TouchableOpacity
          style={{
            flex: 1,
            borderWidth: StyleSheet.hairlineWidth,
            borderRadius: 4,
            alignItems: 'center',
            justifyContent: 'center',
          }}
          onPress={() => onChange(activeIndex + 1)}>
          <Text>{`>`}</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

API Reference

Pager

import { Pager } from 'react-native-pager-component'

Props
--------
activeIndex?: number; - active screen
onChange?: (nextIndex: number) => void; - active screen changed
initialIndex?: number; - initial active screen
children: React.ReactNode[];
springConfig?: Partial<SpringConfig> - configuration for spring transitions on swipe / snap
pageInterpolation?: ViewStyle - see below - configuration for individual page transforms
panProps?: Partial<GestureHandlerProperties> - configuration for <PanGestureHandler />
pageSize?: number; - percentage (0 - 1), how far should it page on index change
threshold?: number; - percentage (0 - 1), how far should the user drag before snapping to next / prev
minIndex?: number; - minimum index to swipe to (default 0)
maxIndex?: number; - maximum index to swipe to (default children.length - 1)
adjacentChildOffset?: number; - the number of children adjacent to the activeIndex to render
style?: ViewStyle; - container style for the pager
animatedValue?: Animated.Value<number>; - total translation value of the pager
type?: 'horizontal' | 'vertical'; - target horizontal swipes or vertical swipes
clamp?: {
  prev?: number; - percentage (0 - 1) - clamp children to the left of the active screen
  next?: number; - percentage (0 - 1) - clamp children to the right of the active screen
};
clampDrag?: {
  prev?: number; - percentage (0 - 1) - maximum drag distance for previous screens
  next?: number; - percentage (0 - 1) - maximum drag distance for next screens
};

Tabs and Stack

Tab and Stack configurations are pretty straightforward to get setup:

function Stack({children}) {
  const [activeIndex, setActiveIndex] = useState(0);

  return (
    <View style={{flex: 1, borderWidth: StyleSheet.hairlineWidth}}>
      <Pager
        activeIndex={activeIndex}
        onChange={setActiveIndex}
        clamp={{prev: 0.3}}
        clampDrag={{prev: 0}}
        style={{flex: 1, overflow: 'hidden', paddingVertical: 5}}>
        {children}
      </Pager>

      <View style={{height: 50, flexDirection: 'row'}}>
        <TouchableOpacity
          onPress={() =>
            setActiveIndex(Math.min(activeIndex + 1, children.length - 1))
          }
          style={{
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            borderWidth: 1,
            borderColor: colors[activeIndex],
          }}>
          <Text style={{color: colors[activeIndex]}}>Push</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

function Tabs({children}) {
  const [activeIndex, setActiveIndex] = useState(0);

  return (
    <View style={{flex: 1, borderWidth: StyleSheet.hairlineWidth}}>
      <Pager
        activeIndex={activeIndex}
        onChange={setActiveIndex}
        style={{flex: 1, overflow: 'hidden', paddingVertical: 5}}>
        {children}
      </Pager>

      <View style={{height: 50, flexDirection: 'row'}}>
        {React.Children.map(children, (c, i) => (
          <TouchableOpacity
            onPress={() => setActiveIndex(i)}
            style={{
              flex: 1,
              justifyContent: 'center',
              alignItems: 'center',
              borderWidth: 1,
              borderColor: activeIndex === i ? colors[i] : 'black',
            }}>
            <Text style={{color: activeIndex === i ? colors[i] : 'black'}}>
              {i + 1}
            </Text>
          </TouchableOpacity>
        ))}
      </View>
    </View>
  );
}

Customization

The default settings for the pager component will be a full screen page that handles horizontal swipes.

You can customize the behaviour of individual cards using the pageInterpolation prop. It accepts an object of interpolation configurations for the different properties you want to transform. The interpolation configs can be found in the react-native-reanimated docs.

There's some pretty neat stuff you can do with these -- here are some examples for the configs above:

// the numbers we are interpolating are relative to the active card
// e.g an inputRange value of -1 means it is 1 page to the left of whatever is active.

const kilterCards = {
  transform: [
    {
      scale: {
        inputRange: [-1, 0, 1],
        outputRange: [0.95, 1, 0.95],
      },
    },

    {
      translateY: {
        inputRange: [-1, 0, 1, 2],
        outputRange: [0, 0, 10, -15],
      },
    },

    {
      rotate: {
        unit: 'deg',
        inputRange: [-1, 0, 1, 2],
        outputRange: [-20, 0, -7.5, 5],
      },
    },
  ],

  opacity: {
    inputRange: [-1, 0, 1, 2, 3],
    outputRange: [0, 1, 1, 1, 0],
  },
};


<Pager clamp={{ next: 0 }} pageInterpolation={kilterCards}>...</Pager>

const swipeCards = {
  transform: [
    {
      scale: {
        inputRange: [-1, 0, 1],
        outputRange: [0.95, 1, 0.95],
        clamp: Extrapolate.EXTEND,
      },
    },
    {
      translateX: {
        inputRange: [-1, 0, 1],
        outputRange: [-150, 0, 0],
      },
    },
    {
      translateY: {
        inputRange: [-1, 0, 1],
        outputRange: [0, 0, 10],
        clamp: Extrapolate.EXTEND,
      },
    },

    {
      rotate: {
        unit: 'deg',
        inputRange: [-1, 0, 1],
        outputRange: [-20, 0, 0],
        clamp: Extrapolate.EXTEND,
      },
    },
  ],
};

<Pager clamp={{ next: 0 }} pageInterpolation={swipeCards}>...</Pager>

react-native-pager's People

Watchers

 avatar

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.