Skip to content

UdaySravanK/RNSwipeButton

Repository files navigation

React Native Swipe Button Component

star this repo fork this repo NPM Version npm total downloads Npm Downloads Socke Score Contribuutions Welcome


Installation

npm install rn-swipe-button --save

# OR

yarn add rn-swipe-button

react-native compatibility

rn-swipe-button react-native react
<= v1.3.8 >= 0.60.5 >= 16.8.6
>= v2.0.0 >= 0.70.0 >= 18.1.0

Usage

import SwipeButton from 'rn-swipe-button'; 

<SwipeButton/>


Screenshots

iOS Android iOS GIF Android RTL

These screenshots are from the demo app.


Component properties

    containerStyles: PropTypes.object,
    disabled: PropTypes.bool,
    disableResetOnTap: PropTypes.bool,
    disabledRailBackgroundColor: PropTypes.string,
    disabledThumbIconBackgroundColor: PropTypes.string,
    disabledThumbIconBorderColor: PropTypes.string,
    enableReverseSwipe: PropTypes.bool,
    forceReset: PropTypes.func,  // RNSwipeButton will call this function by passing a "reset" function as argument. Calling "reset" will reset the swipe thumb.
    height: PropTypes.oneOfType([
       PropTypes.string,
       PropTypes.number,
    ]),
    onSwipeFail: PropTypes.func,
    onSwipeStart: PropTypes.func,
    onSwipeSuccess: PropTypes.func,
    railBackgroundColor: PropTypes.string,
    railBorderColor: PropTypes.string,
    railFillBackgroundColor: PropTypes.string,
    railFillBorderColor: PropTypes.string,
    railStyles: PropTypes.object,
    resetAfterSuccessAnimDelay: PropTypes.number, // This is delay before resetting the button after successful swipe When shouldResetAfterSuccess = true 
    screenReaderEnabled: PropTypes.bool,
    shouldResetAfterSuccess: PropTypes.bool, // If set to true, buttun resets automatically after swipe success with default delay of 1000ms
    swipeSuccessThreshold: PropTypes.number, // Ex: 70. Swipping 70% will be considered as successful swipe
    thumbIconBackgroundColor: PropTypes.string,
    thumbIconBorderColor: PropTypes.string,
    thumbIconComponent: PropTypes.node, Pass any react component to replace swipable thumb icon
    thumbIconImageSource: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),
    thumbIconStyles: PropTypes.object,
    thumbIconWidth: PropTypes.number,
    title: PropTypes.string,
    titleColor: PropTypes.string,
    titleFontSize: PropTypes.number,
    titleMaxFontScale: PropTypes.number, // Ex: 2. will limit font size increasing to 200% when user increases font size in device properties
    titleMaxLines: PropTypes.number, // Use other title related props for additional UI customization
    titleStyles: PropTypes.object,
    width: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),

Code for above screenshots

import React, {useState} from 'react';
import {SafeAreaView, View, Text, StatusBar, Button} from 'react-native';

import Icon from 'react-native-vector-icons/FontAwesome';

import thumbIcon from './assets/thumbIcon.png';
import arrowRight from './assets/arrow-right.png';
import styles from './styles';

import SwipeButton from 'rn-swipe-button';


const App: () => React$Node = () => {
  const [disableCBButton, setDisableCBButton] = useState(false)
  const defaultStatusMessage = 'swipe status appears here';
  const [swipeStatusMessage, setSwipeStatusMessage] = useState(
    defaultStatusMessage,
  );

  setInterval(() => setSwipeStatusMessage(defaultStatusMessage), 5000);
  const updateSwipeStatusMessage = (message) => setSwipeStatusMessage(message);
  const renderSubHeading = (heading) => (
    <Text style={styles.subHeading}>{heading}</Text>
  );
  let forceResetLastButton = null;

  const CheckoutButton = () => {
    return(
        <View style={{width: 100, height: 30, backgroundColor: '#C70039', borderRadius: 5, justifyContent: 'center', alignItems: 'center'}}>
            <Text style={{color: '#ffffff'}}>Checkout</Text>
        </View>
    );
  } 


  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <View style={styles.container}>
          <Text style={styles.title}>React Native Swipe Button</Text>
          <Text style={styles.swipeStatus}>{swipeStatusMessage}</Text>
          {renderSubHeading('Disabled')}
          <SwipeButton thumbIconImageSource={arrowRight} disabled />
          {renderSubHeading('Swipe status callbacks')}
          <SwipeButton
            containerStyles={{borderRadius: 5}}
            height={30}
            onSwipeFail={() => updateSwipeStatusMessage('Incomplete swipe!')}
            onSwipeStart={() => updateSwipeStatusMessage('Swipe started!')}
            onSwipeSuccess={() =>
              updateSwipeStatusMessage('Submitted successfully!')
            }
            railBackgroundColor="#31a57c"
            railStyles={{borderRadius: 5}}
            thumbIconComponent={CheckoutButton}
            thumbIconImageSource={arrowRight}
            thumbIconStyles={{borderRadius: 5}}
            thumbIconWidth={100} 
            title="Submit order"
          />
          {renderSubHeading('Reverse swipe enabled')}
          <SwipeButton
            enableReverseSwipe
            onSwipeSuccess={() => updateSwipeStatusMessage('Slide success!')}
            railBackgroundColor="#a493d6"
            thumbIconBackgroundColor="#FFFFFF"
            title="Slide to unlock"
          />
          {renderSubHeading('Set a component as thumb icon & use forceReset')}
          <SwipeButton
            disableResetOnTap
            forceReset={ reset => {
              forceResetLastButton = reset
            }}
            railBackgroundColor="#9fc7e8"  
            railStyles={{
              backgroundColor: '#44000088',
              borderColor: '#880000FF',
            }}
            thumbIconBackgroundColor="#FFFFFF"
            title="Slide to unlock"
          />
          <View style={{ alignItems: 'center', marginBottom: 5 }}>
            <Button onPress={() => forceResetLastButton && forceResetLastButton()} title="Force reset" />
          </View>  
          {renderSubHeading('Set .png image as thumb icon')}
          <SwipeButton thumbIconImageSource={thumbIcon} railBackgroundColor="#cfb0dd"/>
          {renderSubHeading('Set height & reset after successful swipe')}
          <SwipeButton height={25} shouldResetAfterSuccess={true} resetAfterSuccessAnimDelay={1000} />
          {renderSubHeading('Set height and width')}
          <View style={{ flexDirection: 'row', alignItems: 'center' }}>
            <SwipeButton height={35} width={200} title="Swipe" disabled={disableCBButton} />
            <View style={{ marginLeft: 15, width: 150, height: 32 }}><Button onPress={() => setDisableCBButton(!disableCBButton)} title="Toggle disable" /></View>
          </View>  
        </View>
      </SafeAreaView>
    </>
  );
};

Note

  • In accessibility mode this component works like a regular button (double tap to activate)
  • We are supporting RTL out of the box. For RTL layouts, swipe button works by default as right to left swipe.

Tech Stack

  • Node
  • Yarn/NPM
  • JavaScript
  • TypeScript
  • ReactNative

Running the demo app

  1. git clone https://github.com/UdaySravanK/RNSwipeButtonDemo.git
  2. cd RNSwipeButtonDemo
  3. yarn
  4. To run on an android emulator

    yarn android
    Make sure of
    • Android Studio is configured
    • Global paths set correctly for Android SDK i.e ANDROID_HOME, tools, platform-tools
    • Java8 is installed
    • At least one emulator is ready
  5. To run on an ios simulator

    yarn ios
    Make sure of
    • xcode is configured
    • cocoapods installed
    • If seeing issues then run pod deintegrate & pod install
    • If seeing issues with fonts
      1. Open ios workspace project in xcode
      2. Select RNSwipeButtonDemo
      3. Go to Build phases
      4. Open 'Copy Bundle Resources' and delete all .ttf files

Making changes and seeing them in the demo app

Mapping the local npm package using `npm link` is not working for me but you can give a try and update this readme to help others.

Workaroud is simply copy the `src` folder from the `RNSwipeButton` and paste it in `RNSwipeButtonDemo` app. In the demo app, you see `App.tsx`. When you open it, you will see a commented import and a note. Simply use the copied source code. I understand it is not the ideal way to work but this is a simple component and won't take more than 10seconds to do this.