How to implement automatic scrolling `FlatList` when pressing components that are nested in the `renderItem`?

12 Views Asked by At

I'm developing a React Native mobile app. My HomeScreen.tsx renders a FlatList of Unit.tsx which renders an array of Block.tsx using .map. Each Block is a pressable item (just a circle with a height of 100 px) that shows a simple custom popover below that circle after pressing on it. I want to automatically scroll the whole FlatList when the user presses a Block which position is too close to the bottom of the screen and therefore renders the popover outside the screen. Here's the components:

// Home.tsx
import React from "react";
import { View, Text, FlatList } from "react-native";

import styles from "./styles";
import Unit from "../../components/Unit";
import { useAppSelector } from "../../hooks";

const Home = () => {
  const currentSection = useAppSelector((state) => state.path.selectedSection);

  return (
    <View style={styles.container}>
      <FlatList
        data={currentSection.units}
        renderItem={({ item }) => <Unit unit={item} />}
        showsVerticalScrollIndicator={false}
      />
    </View>
  );
};

export default Home;
// Unit.tsx
import React from "react";
import { View, Text } from "react-native";

import styles from "./styles";
import { IUnit } from "../../types/models";
import Block from "../Block";

type Props = {
  unit: IUnit;
};

const Unit = ({ unit }: Props) => {
  return (
    <View style={styles.container}>
      <View style={styles.titleBox}>
        <Text style={styles.title}>{unit.unitName}</Text>
      </View>
      <View style={styles.blocksContainer}>
        {unit.blocks.map((block) => (
          <Block key={block.blockId} block={block} />
        ))}
      </View>
    </View>
  );
};

export default Unit;
// Block.tsx
import { useNavigation } from "@react-navigation/native";
import React, { useState } from "react";
import { View, Text, Pressable } from "react-native";
import { AnimatedCircularProgress } from "react-native-circular-progress";

import styles from "./styles";
import colors from "../../theme/colors";
import { IBlock } from "../../types/models";
import { HomeNavigationProp } from "../../types/navigation";

type Props = {
  block: IBlock;
};

const Block = ({ block }: Props) => {
  const [popoverVisible, setPopoverVisible] = useState(false);

  const navigation = useNavigation<HomeNavigationProp>();

  const handlePressOutside = () => {
    setPopoverVisible(false);
    console.warn("press");
  };

  const onPopoverButtonPress = () => {
    setPopoverVisible(false);
    navigation.navigate("Lesson"); 
  };

  return (
    <>
      <Pressable onPress={() => setPopoverVisible(true)} style={styles.blockBox}>
        <AnimatedCircularProgress
          size={130}
          width={10}
          fill={(block.completedLessons / block.totalLessons) * 100}
          lineCap="round"
          rotation={0}
          tintColor={colors.green50}
          backgroundColor={colors.ghost}
        >
          {() => (
            <View style={styles.innerBlockBox}>
              <Text style={styles.boxText}>{block.blockName}</Text>
              <Text style={styles.boxText}>
                {block.completedLessons} / {block.totalLessons}
              </Text>
            </View>
          )}
        </AnimatedCircularProgress>
      </Pressable>

      {popoverVisible && (
        <View style={styles.popoverBox}>
          <Text style={styles.popoverTitle}>{block.blockName}</Text>
          <Text style={styles.popoverText}>
            Lesson {block.completedLessons} of {block.totalLessons}
          </Text>
          <Pressable onPress={onPopoverButtonPress} style={styles.popoverButton}>
            <Text style={styles.buttonText}>START</Text>
          </Pressable>
        </View>
      )}
    </>
  );
};

export default Block;

Could someone please provide insights or suggestions on how to implement this?

0

There are 0 best solutions below