skip to Main Content

I’m trying to use the signature canvas from react-native-signature-canvas. I’ve imported it as stated in the npm docs and placed it in my code perfectly. I can’t figure out why it doesn’t show up on my screen. Here’s my code:

    import React, { useRef, useState } from "react";
    import {
        Text,
        StyleSheet,
        Pressable,
        TextInput,
        View,
        SafeAreaView,
        Image,
    } from "react-native";
    import SignatureScreen from "react-native-signature-canvas";

    export default function SignatureNav() {
    const [colorText, setPenColor] = useState("");
    const ref = useRef();

    const [signature, setSign] = useState(null);

    //onOk Function  update
    const handleOK = (signature) => {
        setSign(signature);
  };

    const handleColorChange = () => {
        ref.current.changePenColor(colorText);
  };

    // Function to handle Undo
    const handleUndo = () => {
        ref.current.undo();
    };

    const handleEmpty = () => {
        console.log("Empty");
    };

    // Function to handle Redo
    const handleRedo = () => {
        ref.current.redo();
    };

    const handleClear = () => {
        console.log("clear success!");
    };

    return (
        <View style={styles.container}>
          <Text style={styles.textSign}>Sign Below</Text>
          <View style={styles.row}>
              <Pressable
                   style={[
                   styles.setButton,
                   { marginRight: 30, backgroundColor: "red" },
                   ]}
                   onPress={handleUndo}
              >
                  <Text style={styles.text}>Undo</Text>
              </Pressable>
              <TextInput
                  placeholder="Specify Pen Color"
                  style={styles.textInput}
                  autoCapitalize="none"
                  value={colorText}
                  onChangeText={setPenColor}
              />
            <Pressable style={styles.setButton} onPress={handleColorChange}>
                <Text style={styles.text}>Set</Text>
            </Pressable>
            <Pressable
                style={[styles.setButton, { marginLeft: 30, backgroundColor: "red" }]}
                onPress={handleRedo}
            >
                <Text style={styles.text}>Redo</Text>
            </Pressable>
         </View>

        <SignatureScreen
            ref={ref}
            onOK={(signature) => handleOK(signature)}
            onEmpty={handleEmpty}
            penColor={colorText}
            onClear={handleClear}
            confirmText="Preview"
        />
        <Text style={styles.textSign}>Preview Signature</Text>
        <Image
            resizeMode={"cover"}
            style={{ width: 300, height: 180, paddingBottom: 20 }}
            source={{ uri: signature }}
        />
      </View>
  );
}

    const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: "center",
        justifyContent: "center",
        height: 250,
        padding: 10,
    },
    row: {
        flexDirection: "row",
        marginTop: 10,
        borderBottomWidth: 1,
        borderBottomColor: "#f2f2f2",
        paddingBottom: 5,
    },
    textSign: {
        color: "deepskyblue",
        fontWeight: "bold",
        paddingVertical: 5,
    },
    text: {
        color: "#fff",
        fontWeight: "900",
    },
    textInput: {
        paddingVertical: 10,
        textAlign: "center",
    },
    setButton: {
        backgroundColor: "deepskyblue",
        textAlign: "center",
        fontWeight: "900",
        color: "#fff",
        marginHorizontal: 10,
        paddingVertical: 15,
        paddingHorizontal: 10,
        borderRadius: 5,
    },
    preview: {
        width: 335,
        height: 114,
        backgroundColor: "#F8F8F8",
        justifyContent: "center",
        alignItems: "center",
        marginTop: 15,
    },
});

and here’s my package.json

    {
    "name": "data-sign-mobile-app",
    "version": "1.0.0",
    "main": "node_modules/expo/AppEntry.js",
    "scripts": {
        "start": "expo start",
        "android": "expo start --android",
        "ios": "expo start --ios",
        "web": "expo start --web"
    },
    "dependencies": {
        "@emotion/react": "^11.11.4",
        "@emotion/styled": "^11.11.0",
        "@expo/metro-runtime": "~3.1.3",
        "@expo/ngrok": "^2.5.0",
        "@expo/vector-icons": "^14.0.0",
        "@gluestack-style/react": "^1.0.49",
        "@gluestack-ui/themed": "^1.1.9",
        "@mui/icons-material": "^5.15.11",
        "@mui/material": "^5.15.11",
        "@react-native-async-storage/async-storage": "1.21.0",
        "@react-navigation/drawer": "^6.6.9",
        "@react-navigation/native": "^6.1.12",
        "@react-navigation/stack": "^6.3.23",
        "@reduxjs/toolkit": "^2.2.1",
        "@rneui/themed": "^4.0.0-rc.8",
        "@types/react-native": "^0.73.0",
        "base-64": "^1.0.0",
        "expo": "~50.0.8",
        "expo-image-picker": "~14.7.1",
        "expo-status-bar": "~1.11.1",
        "react": "18.2.0",
        "react-native": "0.73.4",
        "react-native-canvas": "^0.1.39",
        "react-native-dropdown-select-list": "^2.0.5",
        "react-native-gesture-handler": "~2.14.0",
        "react-native-keyboard-aware-scroll-view": "^0.9.5",
        "react-native-reanimated": "~3.6.2",
        "react-native-screens": "~3.29.0",
        "react-native-signature-canvas": "^4.7.2",
        "react-native-signature-capture": "^0.4.12",
        "react-native-svg": "13.4.0",
        "react-native-web": "~0.19.6",
        "react-native-webview": "13.6.4",
        "react-redux": "^9.1.0",
        "@shopify/react-native-skia": "0.1.221"
    },
    "devDependencies": {
        "@babel/core": "^7.20.0",
        "@expo/ngrok": "^4.1.0"
    },
    "private": true
    }

and here’s my App.js

    import "react-native-gesture-handler";
    import React, { useEffect, useState } from "react";
    import {
          ActivityIndicator,
          View,
          Image,
          Text,
          SafeAreaView,
    } from "react-native";
    import { NavigationContainer } from "@react-navigation/native";
    import { createStackNavigator } from "@react-navigation/stack";
    import {
          DrawerItemList,
          createDrawerNavigator,
    } from "@react-navigation/drawer";
    import {
          LoginScreen,
          HomeScreen,
          RegistrationScreen,
          EditProfileScreen,
          SignatureScreen,
    } from "./src/screens";
    import {
          SimpleLineIcons,
          MaterialIcons,
          MaterialCommunityIcons,
          FontAwesome,
    } from "@expo/vector-icons";
    import { decode, encode } from "base-64";
    import { store } from "./src/features/common/store";
    import { Provider } from "react-redux";


    if (!global.btoa) {
          global.btoa = encode;
    }
    if (!global.atob) {
          global.atob = decode;
    }

    const Stack = createStackNavigator();
    const Drawer = createDrawerNavigator();

    export default function App() {
          const [user, setUser] = useState({
                username: "",
                password: "",
                hasPaid: true,
          }); //change code for when backend stores if user has paid
          const [waitingForUser, setWaitingForUser] = useState(false);

      return (
            <Provider store={store}>
                  <NavigationContainer>
                  {waitingForUser ? (
                      <ActivityIndicator
                      style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
                      size="large"
                      />
                      ) : (
                      <>
                     {user ? (
                     <Drawer.Navigator
                          drawerContent={(props) => {
                                  return (
                                      <SafeAreaView>
                                          <View
                                          style={{
                                          height: 200,
                                          width: "100%",
                                          justifyContent: "center",
                                          alignItems: "center",
                                          borderBottomColor: "#f4f4f4",
                                          borderBottomWidth: 1,
                                          }}
                                          >
                                              <Image
                                               source={require("./assets/profile_logo.png")}
                                               style={{
                                               height: 130,
                                               width: 130,
                                               borderRadius: 65,
                                               }}
                                               />
                                               <Text
                                               style={{
                                               fontSize: 22,
                                               marginVertical: 6,
                                               fontWeight: "bold",
                                               color: "#111",
                                               }}
                                               >
                                                   John Doe
                                               </Text>
                                               <Text
                                               style={{
                                               fontSize: 16,
                                               color: "#111",
                                               }}
                                               >
                                                   Introduction
                                               </Text>
                                          </View>
                                          <DrawerItemList {...props} />
                                      </SafeAreaView>
                                  );
                          }}
                          screenOptions={{
                          drawerStyle: {
                          backgroundColor: "#fff",
                          width: 250,
                          },
                          headerStyle: {
                          backgroundColor: "#788eec",
                          },
                          headerTintColor: "#fff",
                          headerTitleStyle: {
                          fontWeight: "bold",
                          },
                          drawerActiveTintColor: "#788eec", // use blue if it doesn't look good
                          drawerLabelStyle: {
                          color: "#111",
                          },
                          }}
                      >
                          {user.hasPaid ? (
                              <>
                                  <Drawer.Screen
                                   name="Signature"
                                   options={{
                                   drawerLabel: "Signature",
                                   title: "Signature",
                                   drawerIcon: () => (
                                       <MaterialCommunityIcons
                                        name="signature"
                                        size={20}
                                        color="#808080"
                                        />
                                  ),
                                  }}
                                  component={SignatureScreen}
                                  />
                              </>
                          ) : (
                              <>
                                  <Drawer.Screen
                                   name="Home"
                                   options={{
                                   drawerLabel: "Home",
                                   title: "Home",
                                   drawerIcon: () => (
                                       <SimpleLineIcons
                                        name="home"
                                        size={20}
                                        color="#808080"
                                        />
                                  ),
                                  }}
                                  >
                                      {(props) => <HomeScreen {...props} extraData={user} />}
                                  </Drawer.Screen>
                              </>
                          )}
                          <Drawer.Screen
                          name="Edit Profile"
                          options={{
                          drawerLabel: "Edit Profile",
                          title: "Edit Profile",
                          drawerIcon: () => (
                              <FontAwesome name="edit" size={20} color="#808080" />
                          ),
                          }}
                          component={EditProfileScreen}
                          />
                     </Drawer.Navigator>
                     ) : (
                     <Stack.Navigator>
                         <Stack.Screen name="Login" component={LoginScreen} />
                         <Stack.Screen
                          name="Registration"
                          component={RegistrationScreen}
                          />
                     </Stack.Navigator>
                     )}
                     </>
                  )}
                  </NavigationContainer>
            </Provider>
      );
      }

and here’s related files (SignatureNav is called in Signature, which is called in SignatureScreen)
SignatureScreen:

    import React from 'react'
    import Signature from "../../features/signature"
    import { ScrollView } from "react-native-gesture-handler";


    export default function SignatureScreen() {
        return (
            <ScrollView>
                <Signature />
            </ScrollView>
        )
    }

Signature:

    import React, { useEffect, useState } from "react";
    import { useAppDispatch } from "../common/exports";
    import { setPageTitle } from "../common/headerSlice";
    import SignatureContent from "./SignatureContent";
    import SignatureNav from "./SignatureNav";
    import { Pressable, View, Text, StyleSheet } from "react-native";


    export default function Signature() {
        const [activeTab, setActiveTab] = useState("tab1");
 
        const handleTabClick = (tab) => {
            setActiveTab(tab);
        };

        return (
            <View
                style={{ display: "flex", flexDirection: "column", backgroundColor: "#fff" }}
            >
            {/* Sidebar */}
                <View style={{ backgroundColor: "#bbdefb", padding: "2rem" }}>
                    <Pressable
                    style={styles.button}
                    onPress={() => handleTabClick("tab1")}
                    >
                        <Text style={styles.buttonTitle}>Generate Signature</Text>
                    </Pressable>

                    <Pressable
                    style={styles.button}
                    onPress={() => handleTabClick("tab2")}
                    >
                        <Text style={styles.buttonTitle}>Draw Signature</Text>
                    </Pressable>
                </View>

                {/* Main Content */}
                <View style={{
                flexGrow: 1,
                overflow: 'hidden',
                borderRadius: 8
                }}
                >
                    <View style={{
                    paddingTop: 32,
                    }}
                    >
                        {activeTab === 'tab1' && <SignatureContent />}
                        {activeTab === 'tab2' && <SignatureNav />}
                    </View>
                </View>
            </View>
        );
    }

    const styles = StyleSheet.create({
        button: {
            backgroundColor: "#3f51b5",
            marginLeft: 30,
            marginRight: 30,
            marginVertical: 20,
            height: 48,
            borderRadius: 5,
            alignItems: "center",
            justifyContent: "center",
            paddingLeft: 20,
            paddingRight: 20,
        },
        buttonTitle: {
            color: "white",
            fontSize: 16,
            fontWeight: "bold",
        },
    });

I tried adding webStyles thinking that the problem was that there was no height, reinstalling the module, and using curly brackets {} to import the module. Can’t think of anything else. I’m new to React Native!

2

Answers


  1. You are on Expo v50.0.8 which came out 16 days ago, yet you are trying to use react-native-signature-canvas v4.7.2 which came out 13 days ago.

    I recommend you try v4.7.1 to see if that changes the behaviour.

    Login or Signup to reply.
  2. The code you provided is incomplete. I can’t see where you are importing the ‘react-native-signature-canvas’ module. Anyways, this is working for me:

    import Signature from "react-native-signature-canvas";
    
    <View style={styles.signature}>
            <Signature
              ref={ref}
              webStyle={`.m-signature-pad {
                border: none;
                background-color: #A8A29E;
                box-shadow: none;
              }
              .m-signature-pad--body {
                border: none
              }
              `}
              onEmpty={handleEmpty}
              onOK={handleOK}
              trimWhitespace={true}
            />
          </View>
    

    Container Style:

     signature: {
        height: <predefined height>,
        borderWidth: 2,
        borderRadius: 8,
        borderColor: <optional>,
        padding: 2,
        backgroundColor: <same as bg color in webstyle>,
      },
    

    Although this works in Expo-Go, I have had issues in the development build using eas – it crashes on launch in iOS.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search