Search code examples
react-hooksreact-nativereact-navigationreact-native-flatlist

Using FlatList to display custom card elements and need to make them touchable


I need to make the list of items touchable in a flatlist, but have no idea how to make the individual components touchable so i can access the id of that flatlist item. I need to handle the onPress so I can use react navigation 5 to send the users to a different screen.

I'm using an array of data to create a card like component that renders in the flatlist.

how do I make the individual list items touchable?

here's what I'm working with:

import * as React from "react";
import { View, StyleSheet, FlatList, SafeAreaView } from "react-native";

import BigButton from "../components/BigButton.js";
import HomeScreenImage from "../components/HomeScreenImage.js";
import HomeCard from "../components/Card";

const homeOptions = [
  {
    name: "Beast shedule",
    body: "Create and manage your workout shedule",
    image: require("../assets/images/DoubleBis.jpg"),
    id: "1",
  },
  {
    name: "Pre-Made Workouts",
    body: "Use one of our pre-made workouts",
    image: require("../assets/images/ChickA.jpg"),
    id: "2",
  },
  {
    name: "Statistics",
    body: "Analyse your personal statistics",
    image: require("../assets/images/WorkoutInProgress.jpg"),
    id: "3",
  },
  {
    name: "History",
    body: "Keep track of your workout history",
    image: require("../assets/images/ChickH.jpg"),
    id: "4",
  },
];

const HomeScreen = (props) => {
  return (
    <View style={Styles.containerTop}>
      <View>
        <HomeScreenImage style={Styles.top} />
        <View style={Styles.top}>
          <BigButton title="Train & Track" />
        </View>
      </View>
      <SafeAreaView style={Styles.flatListContainer}>
        <FlatList
          data={homeOptions}
          renderItem={({ item }) => {
            return <HomeCard info={item} />;
          }}
          keyExtractor={(homeOption) => homeOption.id}
          showsVerticalScrollIndicator={false}
        />
      </SafeAreaView>
    </View>
  );
};

const Styles = StyleSheet.create({
  containerTop: {
    flex: 1,
    backgroundColor: "#3E3636",
  },
  top: {
    flex: 1,
    height: "1%",
    alignItems: "center",
    justifyContent: "center",
  },
  flatListContainer: {
    flex: 1,
  },
});

export default HomeScreen;



import React from "react";
import { View, Text, StyleSheet, Dimensions, Image } from "react-native";

const HomeCard = (props) => {
  return (
    <View style={Styles.container}>
      <View style={Styles.cardContainer}>
        <Image style={Styles.imageStyle} source={props.info.image} />

        <View style={Styles.infoStyle}>
          <Text style={Styles.titleStyle}>{props.info.name}</Text>
          <Text style={Styles.bodyTextStyle}>{props.info.body}</Text>
        </View>
      </View>
    </View>
  );
};

const deviceWidth = Math.round(Dimensions.get("window").width);
const offset = 25;
const radius = 20;
const Styles = StyleSheet.create({
  container: {
    width: deviceWidth - 20,
    marginTop: 20,
  },
  cardContainer: {
    margin: 10,
    width: deviceWidth - offset,
    backgroundColor: "#000",
    height: 200,
    borderRadius: radius,
    shadowColor: "#000",
    shadowOffset: {
      width: 5,
      height: 5,
    },
    shadowOpacity: 0.75,
    shadowRadius: 5,
    elevation: 3,
  },
  imageStyle: {
    height: 130,
    width: deviceWidth - 25,
    borderTopLeftRadius: radius,
    borderTopRightRadius: radius,
    opacity: 0.95,
  },
  titleStyle: {
    color: "#F5EDED",
    textAlign: "center",
    fontSize: 20,
    fontWeight: "800",
  },
  bodyTextStyle: {
    fontWeight: "200",
    color: "#F5EDED",
    textAlign: "center",
  },
  infoStyle: {
    marginHorizontal: 10,
    marginVertical: 1,
  },
});

export default HomeCard;


Solution

  • You can wrap your card with some touchable component, like TouchableOpacity for example, with naviagtion.navigate('routeName', {params}) function on onPress prop.

    const HomeCard = (props) => {
      return (
        <TouchableOpacity onPress={() => navigation.navigate('ReceiverRoute', {image: props.info image, name: props.info.name })}> ///etc any parameters you want
         <View style={Styles.container}>
           <View style={Styles.cardContainer}>
             <Image style={Styles.imageStyle} source={props.info.image} />
    
             <View style={Styles.infoStyle}>
               <Text style={Styles.titleStyle}>{props.info.name}</Text>
               <Text style={Styles.bodyTextStyle}>{props.info.body}</Text>
             </View>
           </View>
         </View>
       </TouchableOpacity>
      );
    };
    

    and then you navigate to a component that can receive some params. For a cleaner example you can look into docs. The main idea is just wrapping your card into some touchable with onpress navigation. For the navigation prop, you can either pass it to your card from parent component, or use useNavigation hook