Home > Blockchain >  React native: Sectionalist button scroll to up
React native: Sectionalist button scroll to up

Time:11-24

I am learning React native app. I found one demo app from open source app about FlatList where user can click the go down of the screen as well as go up of the screen. I would like implement same logic in SectionList, According to React native documentation, FlatList and SectionList has almost same props. But when I am try implementing the scroll down and up button logic SectionList, it does not work. It throws me error. Here is the snack-bar they used FlatList Scroll down and scroll up logic.

Here is my failed attempt on SectionList and Demo

import React from "react";
import {
  StyleSheet,
  Text,
  View,
  SafeAreaView,
  SectionList,
  StatusBar,
  TouchableOpacity,
  Image,
} from "react-native";

const DATA = [
  {
    title: "Main dishes",
    data: ["Pizza", "Burger", "Risotto"],
  },
  {
    title: "Sides",
    data: ["French Fries", "Onion Rings", "Fried Shrimps"],
  },
  {
    title: "Drinks",
    data: ["Water", "Coke", "Beer"],
  },
  {
    title: "Desserts",
    data: ["Cheese Cake", "Isse Cream"],
  },
];

const Item = ({ title }) => (
  <View style={styles.item}>
    <Text style={styles.title}>{title}</Text>
  </View>
);

const App = () => {
  const listRef = React.useRef(null);
  const [contentVerticalOffset, setContentVerticalOffset] = React.useState(0);

  const CONTENT_OFFSET_THRESHOLD = 300;

  const upButtonHandler = () => {
    //OnCLick of Up button we scrolled the list to top
    listRef.scrollToOffset({ offset: 0, animated: true });
  };

  const downButtonHandler = () => {
    //OnCLick of down button we scrolled the list to bottom
    listRef.scrollToEnd({ animated: true });
  };

  return (
    <SafeAreaView style={styles.container}>
      <SectionList
        sections={DATA}
        keyExtractor={(item, index) => item   index}
        renderItem={({ item }) => <Item title={item} />}
        renderSectionHeader={({ section: { title } }) => (
          <Text style={styles.header}>{title}</Text>
        )}
        onScroll={(event) => {
          setContentVerticalOffset(event.nativeEvent.contentOffset.y);
        }}
        ref={listRef}
      />

      <TouchableOpacity
        activeOpacity={0.5}
        onPress={downButtonHandler}
        style={styles.downButtonStyle}
      >
        <Image
          source={{
            uri: "https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_down.png",
          }}
          style={styles.downButtonImageStyle}
        />
      </TouchableOpacity>
      <TouchableOpacity
        activeOpacity={0.5}
        onPress={upButtonHandler}
        style={styles.upButtonStyle}
      >
        <Image
          source={{
            uri: "https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_up.png",
          }}
          style={styles.upButtonImageStyle}
        />
      </TouchableOpacity>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: StatusBar.currentHeight,
    marginHorizontal: 16,
  },
  item: {
    backgroundColor: "#f9c2ff",
    padding: 20,
    marginVertical: 8,
  },
  header: {
    fontSize: 32,
    backgroundColor: "#fff",
  },
  title: {
    fontSize: 24,
  },
  upButtonStyle: {
    position: "absolute",
    width: 50,
    height: 50,
    alignItems: "center",
    justifyContent: "center",
    right: 30,
    bottom: 70,
  },
  upButtonImageStyle: {
    resizeMode: "contain",
    width: 30,
    height: 30,
  },
  downButtonStyle: {
    position: "absolute",
    width: 50,
    height: 50,
    alignItems: "center",
    justifyContent: "center",
    right: 30,
    top: 70,
  },
  downButtonImageStyle: {
    resizeMode: "contain",
    width: 30,
    height: 30,
  },
});

export default App;

CodePudding user response:

When using refs the ref is an object , where the value you want to access is within the current property. Also, SectionList have the scrollToLoaction method instead of the scrollToEnd because each section have items of their own.

Here's what I've put together. While the the buttons works on android and ios, on the web they wont position absolute nor will the buttons work:

import React from 'react';
import {
  StyleSheet,
  Text,
  View,
  SafeAreaView,
  SectionList,
  StatusBar,
  TouchableOpacity,
  Image,
  useWindowDimensions,
} from 'react-native';

const Item = ({ title }) => (
  <View style={styles.item}>
    <Text style={styles.title}>{title}</Text>
  </View>
);

const TouchableButton = ({ style, onPress, imgSrc }) => {
  return (
    <TouchableOpacity activeOpacity={0.5} onPress={onPress} style={style}>
      <Image
        source={{
          uri: imgSrc,
        }}
        style={styles.downButtonImageStyle}
      />
    </TouchableOpacity>
  );
};

// made list longer
const DATA = [
  {
    title: 'Main dishes',
    data: ['Pizza', 'Burger', 'Risotto', 'Steak', 'Spaghetti'],
  },
  {
    title: 'Sides',
    data: ['French Fries', 'Onion Rings', 'Fried Shrimps', 'Mac and Cheese'],
  },
  {
    title: 'Drinks',
    data: ['Water', 'Coke', 'Beer', 'Lemonade'],
  },
  {
    title: 'Desserts',
    data: ['Cheese Cake', 'Ice Cream', 'Chocolate Cake'],
  },
];
const imgSize = 36;
const App = () => {
  const listRef = React.useRef(null);
  const [contentVerticalOffset, setContentVerticalOffset] = React.useState(0);
  // use view layout to position the buttons absolutely
  const [viewLayout, setViewLayout] = React.useState({});
  const CONTENT_OFFSET_THRESHOLD = 300;

  const upButtonHandler = () => {
    //OnCLick of Up button we scrolled the list to top
    console.log(`Scrolling to section:0 and index:0`);
    if (!listRef.current.scrollToLocation) console.log('no scrollToLocation');
    listRef.current.scrollToLocation?.({
      itemIndex: 0,
      sectionIndex: 0,
      animated: true,
    });
  };

  const downButtonHandler = () => {
    //OnCLick of down button we scrolled the list to bottom
    const sectionIndex = DATA.length - 1;
    const itemIndex = DATA[sectionIndex].data.length - 1;
    console.log(`Scrolling to section:${sectionIndex} and index:${itemIndex}`);
    if (!listRef.current.scrollToLocation) console.log('no scrollToLocation');
    listRef.current.scrollToLocation?.({
      itemIndex,
      sectionIndex,
      animated: true,
    });
  };

  return (
    <SafeAreaView
      style={styles.container}
      onLayout={(e) => setViewLayout(e.nativeEvent.layout)}>
      <TouchableButton
        onPress={downButtonHandler}
        style={{
          position: 'absolute',
          zIndex: 2,
          left: viewLayout.width - viewLayout.x - imgSize,
          top: viewLayout.y   (StatusBar.currentHeight || 40),
        }}
        imgSrc="https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_down.png"
      />
      <TouchableButton
        onPress={upButtonHandler}
        style={{
          position: 'absolute',
          zIndex: 2,
          left: viewLayout.width - viewLayout.x - imgSize,
          top: viewLayout.height - 20 - imgSize,
        }}
        imgSrc="https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_up.png"
      />
      <SectionList
        sections={DATA}
        keyExtractor={(item, index) => item   index}
        renderItem={({ item }) => <Item title={item} />}
        renderSectionHeader={({ section: { title } }) => (
          <Text style={styles.header}>{title}</Text>
        )}
        onScroll={(event) => {
          setContentVerticalOffset(event.nativeEvent.contentOffset.y);
        }}
        ref={listRef}
      />
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: StatusBar.currentHeight,
    marginHorizontal: 16,
  },
  item: {
    backgroundColor: '#f9c2ff',
    padding: 20,
    marginVertical: 8,
  },
  header: {
    fontSize: 32,
    backgroundColor: '#fff',
  },
  title: {
    fontSize: 24,
  },

  downButtonImageStyle: {
    resizeMode: 'contain',
    width: imgSize,
    height: imgSize,
  },
});

export default App;

  • Related