1

I have some Pressable elements that appear on my iPhone in Expo, but are not touchable at all. I cannot even click them in the element inspector. Can anyone guide me towards a solution? I wonder if it's the nesting and it's parent container affecting it's behavior, because when I change the TouchableWithoutFeedback to a View, it instantly "appears" and works as it should. Why is the "TouchableWithoutFeedback" element cancelling out my Pressable elements but not the TouchableOpacity ones? "TouchableWithoutFeedback only supports one child" according to docs, but placing everything inside it inside a single View is also not solving this issue with Pressable. It seems that Pressable cannot exist within this touchable element due to how it works?

Here's the code:

import React from "react";
import { Dimensions, StyleSheet, Text, View, Image, TextInput, Pressable, KeyboardAvoidingView, Keyboard } from "react-native";
import { TouchableOpacity, TouchableWithoutFeedback } from "react-native-gesture-handler";
const { width, height } = Dimensions.get("window");
const color = "#d00000";

const errorMessage = () => {
  console.log("errorMessage triggered");
  Alert.alert("Please enter a name for your character");
};

const Home = (props) => {
  return (
    <KeyboardAvoidingView style={styles.container} behavior='padding'>
      <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>

        <Image style={styles.logo} source={require("../assets/logo.jpg")} />
        <View style={styles.main}>
          <Text style={styles.titulo}>JW's D&D 5e</Text>
          <Text style={styles.subtitulo}>Character Generator</Text>

          <View style={styles.bodyText}>
            <Text style={styles.subtitulo}>Welcome!</Text>
            <Text style={styles.text}>On the following screens you'll choose premade basics for your new character: Race, class, background, plus a photo uploaded from your camera library.</Text>
            <Text style={styles.subtext}>(Your info is stored locally in your device until you 'log out' within the app.)</Text>
          </View>

          {/* DIVIDER */}
          <View
            style={{
              width: "80%",
              marginTop: 10,
              marginBottom: 10,
              borderBottomWidth: StyleSheet.hairlineWidth,
              borderBottomColor: "#000",
              alignSelf: "center",
            }}
          />

          {props.loggedIn === true ? (
            <Pressable
              hitSlop={20}
              pressRetentionOffset={{ top: 20, right: 20, bottom: 20, left: 20 }}
              onPress={() => props.logout()}
              style={({ pressed }) => [
                {
                  backgroundColor: pressed ? "dodgerblue" : color,
                },
                styles.pressable,
              ]}>
              {({ pressed }) => <Text style={styles.btnText}>{pressed ? "Later!" : "Logout"}</Text>}
            </Pressable>
          ) : (
            <View style={styles.nameInput}>
              <Text style={styles.text}>Enter your character's name: </Text>
              <View style={styles.input}>
                <TextInput placeholder='Character name' value={props.name} onChangeText={(text) => props.setName(text)} style={styles.inputText} />
              </View>

              <Pressable
                hitSlop={40}
                pressRetentionOffset={{ top: 20, right: 20, bottom: 20, left: 20 }}
                onPress={() => {
                  props.login();
                  !props.name ? errorMessage() : props.navigation.navigate("Race");
                }}
                style={({ pressed }) => [
                  {
                    backgroundColor: pressed ? "dodgerblue" : color,
                  },
                  styles.pressable,
                ]}>
                {({ pressed }) => <Text style={styles.btnText}>{pressed ? "Let's go!" : "Start your adventure!"}</Text>}
              </Pressable>
            </View>
          )}
        </View>

      </TouchableWithoutFeedback>
    </KeyboardAvoidingView>
  );
};

export default Home;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: "column",
    backgroundColor: "white",
    // alignItems: "center",
    justifyContent: "center",
    width: width,
    height: height,
  },
  bodyText: {
    width: "95%",
    marginTop: 20,
    alignItems: "center",
    justifyContent: "center",
  },
  btnText: {
    color: "white",
    fontSize: 24,
  },
  input: {
    height: 50,
    width: 200,
    borderWidth: 1,
    borderColor: "#ccc",
    alignItems: "center",
    justifyContent: "center",
  },
  inputText: {
    width: "100%",
    height: "100%",
    fontSize: 24,
    textAlign: "center",
  },
  logo: {
    height: 70,
    marginBottom: 10,
    resizeMode: "contain",
    alignSelf: "center",
  },
  main: {
    width: width,
    alignItems: "center",
    justifyContent: "center",
  },
  nameInput: {
    alignItems: "center",
  },
  pressable: {
    marginTop: 20,
    width: width,
    height: 40,
    borderRadius: 5,
    alignItems: "center",
    justifyContent: "center",
    shadowColor: "rgba(0,0,0, .3)", // IOS
    shadowOffset: { height: 3, width: 3 }, // IOS
    shadowOpacity: 1, // IOS
    shadowRadius: 1, //IOS
    elevation: 2, // Android
    zIndex: 3,
  },
  text: {
    color: "#9d0208",
    textAlign: "center",
    lineHeight: 40,
    fontSize: 24,
  },
  titulo: {
    color: color,
    fontSize: 30,
    fontWeight: "bold",
  },
  subtext: {
    textAlign: "center",
    lineHeight: 24,
    fontSize: 16,
    width: "70%",
  },
  subtitulo: {
    marginTop: 10,
    color: color,
    fontSize: 30,
    fontWeight: "bold",
  },
});
PhilosophOtter
  • 183
  • 1
  • 2
  • 12
  • 1
    What's your reason and desired behaviour for nesting touchable / pressable elements like this? Do you want something where the Pressable catches any touch to it and the TouchableWithoutFeedback catches any touch to three background? – user56reinstatemonica8 May 21 '21 at 11:05
  • @user56reinstatemonica8 The purpose is simply to use Pressable because its "future proof" and the Touchble w/o Feedback is to dismiss the keyboard. I COULD just replace the Pressables with TouchableOpacity/Highlight and be done with it... – PhilosophOtter May 21 '21 at 11:33
  • 1
    Right. If you can, I'd recommend instead having the containing ScrollView have `keyboardShouldPersistTaps` as `'never'` to dismiss the keyboard on tap. It's best to avoid nesting interactive elements wherever possible, not just to avoid clashes like this, but also because it's better for accessibility (clearer what is the element that should be selectable by a screen reader). – user56reinstatemonica8 May 22 '21 at 13:57
  • @user56reinstatemonica8 Thank you! I wasn't aware of the accessibility bonus! – PhilosophOtter May 23 '21 at 15:43

0 Answers0