Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android][Flatlist][Horizontal] Last item delete in horizontal flatlist does not adjust scroll position. #27504

Closed
jayshah123 opened this issue Dec 13, 2019 · 26 comments

Comments

@jayshah123
Copy link
Contributor

React Native version: 0.59.10

output

Steps To Reproduce

export default class App extends Component<Props> {

  constructor(props) {
    super(props);
    this.dataItems = [{
      id: 1,
      text: 'one'
    },{
      id: 2,
      text: 'two'
    },{
      id: 3,
      text: 'three'
    }, {
      id: 4,
      text: 'four',
    }, {
      id: 5,
      text: 'five'
    }];
  }

  removeItem = (id) => {
    this.dataItems = this.dataItems.filter((item) => item.id !== id);
    this.setState({});
  };

  renderItem = ({item}) => {
    return (
      <View style={{ width: 140, height: 140, backgroundColor: 'yellow', margin: 10}}>
        <Text>{item.text}</Text>
        <TouchableOpacity onPress={() => {
          this.removeItem(item.id);
        }}>
          <Text>{'Remove me'}</Text>
        </TouchableOpacity>
      </View>
    )
  };

  render() {
    return (
      <View style={styles.container}>
        <View style={{height: 140, width: '100%'}}>
          <FlatList
            horizontal
            data={this.dataItems}
            renderItem={this.renderItem}
            keyExtractor={item => `${item.id}`}
          />
        </View>
      </View>
    );
  }
}

Describe what you expected to happen:
After removing last item, scroll position should be adjusted.

Snack, code example, screenshot, or link to a repository:

@jayshah123 jayshah123 added the Bug label Dec 13, 2019
@jayshah123 jayshah123 changed the title [Android][Flatlist][Horizontal] Last item delete in horizontal flatlist does not adjust position. [Android][Flatlist][Horizontal] Last item delete in horizontal flatlist does not adjust scroll position. Dec 13, 2019
@jayshah123
Copy link
Contributor Author

This problem will most likely also be present on the latest version from the code it seems.

@jayshah123
Copy link
Contributor Author

The fix can be simple: add a hierarchy change + layout change listener, which does a scrollTo whenever we have scrolled beyond capacity post an item removal. This is already present in ReactScrollView.

@stale
Copy link

stale bot commented Mar 12, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Mar 12, 2020
@Peeeep
Copy link

Peeeep commented Mar 12, 2020

Thank you, kind little bot, but this still needs a fix :/

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Mar 12, 2020
@alexeyvax
Copy link

I would suggest to use scrollToEnd(), but anyway you need to know screen width and each item width. In case you have two or only one item in your list, you will need to use scrollToIndex({ index: 0 }) instead

@jayshah123
Copy link
Contributor Author

The PR (#27514) has the exact fix for Horizontal Scroll View which is already present in vertical scrollview in production/master since a long time.

@jayshah123
Copy link
Contributor Author

latest pr is #28977

@bboure
Copy link

bboure commented Aug 3, 2020

I am facing this issue too. Any workaround while waiting for the fix?

@Klescouar
Copy link

Up ! Same problem on my side...

@sanduluca
Copy link

I have the same problem with react-native 0.64.2 😕

@victoralmeidadev
Copy link

Same problem here.

A workaround while waiting fix: use scrollToEnd when removing the last item.

Example:

import React, { useState, useRef, useCallback } from "react";
import { FlatList } from "react-native";

function ExampleComponent() {
  const [items, setItems] = useState<[]>([]);
  const flatListRef = useRef<FlatList>();

  const handleRemoveFlatListItem = useCallback(
    (index: number) => {
      const canScrollToEnd = index === items.length - 1;
      const newItems = [...items] as [];
      newItems.splice(index, 1);
      setItems([...newItems]);
      if (flatListRef?.current && canScrollToEnd)
        flatListRef.current.scrollToEnd();
    },
    [items, flatListRef]
  );

  const renderItem = ...

  return (
    <FlatList
      horizontal
      data={items}
      renderItem={renderItem}
      keyExtractor={(item) => `${item.id}`}
    />
  );
}

@Michaeliaaa
Copy link

Same problem here, hope it get fixed soon.

@stale
Copy link

stale bot commented Jan 9, 2022

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jan 9, 2022
@wangliang1124
Copy link

Same problem on 0.63.4

@Lisergishnu
Copy link

Same problem on 0.67.4

@cortinico cortinico removed the Stale There has been a lack of activity on this issue and it may be closed soon. label May 6, 2022
@xhirazi
Copy link

xhirazi commented May 20, 2022

+1

@mbezard
Copy link

mbezard commented May 20, 2022

I have this issue on 0.67.4, but with a scrollview (horizontal) like:

<ScrollView>
    {array.map((item) => (
        <Item onPress={() => removeItem(item.id)} key={item.id} />
    )}
</ScrollView>

@fabOnReact
Copy link
Contributor

fabOnReact commented Jul 8, 2022

Branch - Last item delete in horizontal flatlist does not adjust scroll position.

Test case documents PR #34141

sourcecode example

import React from "react";
import {
  SafeAreaView,
  View,
  FlatList,
  StyleSheet,
  Text,
  StatusBar,
  Button,
} from "react-native";

const DATA = [
  {
    id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
    title: "First Item",
  },
  {
    id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
    title: "Second Item",
  },
  {
    id: "58694a0f-3da1-471f-bd96-145571e29d72",
    title: "Third Item",
  },
  {
    id: "bd7acbea-c1b1-46c2-aed5-3ad53abb8bbb",
    title: "Fourth Item",
  },
  {
    id: "3ac68afc-c605-48d3-a4f8-fbd91aa97676",
    title: "Fifth Item",
  },
  {
    id: "58694a0f-3da1-471f-bd96-145571e27234",
    title: "Sixth Item",
  },
  {
    id: "58694a0f-3da1-471f-bd96-145571e29234",
    title: "Seven Item",
  },
  {
    id: "58694a0f-3da1-471f-bd96-145571429234",
    title: "Eight Item",
  },
  {
    id: "58694a0f-3da1-471f-bd96-115571429234",
    title: "Nine Item",
  },
  {
    id: "58694a0f-3da1-471f-bd96-1155h1429234",
    title: "Ten Item",
  },
];

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

const renderItem = ({ item }) => <Item title={item.title} />;
const ITEM_HEIGHT = 50;

const renderFlatList = ({ item }) => (
  <NestedFlatList item={item} />
);

function NestedFlatList(props) {
  const [items, setItems] = React.useState(DATA);
  return (
    <View>
      <Button
      title="add an item"
      onPress={() => setItems([...items, {title: 'new item'}])}
      />
      <Button
        title="remove an item"
        onPress={() => {
          const newItems = [...items];
          newItems.splice(items.length - 1, 1)
          setItems(newItems);
        }}
      />
      <Text>Flatlist</Text>
      <FlatList
        horizontal={true}
        style={{height: 400}}
        inverted={true}
        renderItem={renderItem} data={items} />
    </View>
  )
}

const FlatList_nested = () => {
  let flatlist = React.useRef(0);
  return (
    <FlatList
      ref={(ref) => flatlist = ref}
      data={[1,2,3]}
      renderItem={renderFlatList}
      keyExtractor={(item) => item.toString()}
    />
  );
};

const styles = StyleSheet.create({
  item: {
    backgroundColor: "#f9c2ff",
    padding: 20,
    marginVertical: 8,
    marginHorizontal: 16,
  },
  title: {
    fontSize: 16,
  },
});

export default ({
  title: 'Nested',
  name: 'nested',
  description: 'nested FlatList',
  render: () => <FlatList_nested />,
}: RNTesterModuleExample);

Screen.Recording.2022-07-08.at.14.38.53.mov

@fabOnReact
Copy link
Contributor

Main - Last item added/deleted in vertical flatlist does not adjust scroll position.

Screen.Recording.2022-07-11.at.22.06.54.mov

@kneza23
Copy link

kneza23 commented Mar 6, 2023

same problem on Android on 0.71.3

@jayshah123
Copy link
Contributor Author

Will re raise the fix after taking a look at source once again.

@jayshah123 jayshah123 closed this as not planned Won't fix, can't repro, duplicate, stale Mar 9, 2023
@stuckj
Copy link

stuckj commented Mar 23, 2023

So...I see this is closed, but it's still broken. Is there another thread where it's not closed?

@stuckj
Copy link

stuckj commented Mar 23, 2023

Given this is unfixed after 3 years I just went with a workaround. :-P

In my case I'm not explicitly removing an item from a list, but rather getting updated data from an API call which could change the data in a horizontal list. If viewing the last item when this happens it will exhibit this behavior. And since I don't explicitly know that the last item was removed (or any item to make the list shorter I guess) I just went with a more brute force approach.

I store the current content offset by observing onScrollEndDrag and onMomentumScrollEnd. And I added an onContentSizeChange callback to check for when the width changes (i.e., and item was removed). I also know the width of the items by measuring them when the items layout (if your item widths vary this would be more complicated). Finally, in a useEffect, if contentOffset + itemWidth > contentWidth then I know I've hit a case where this bug has happened and I'm showing past the end of the scrollview. If that is true, then call scrollToEnd (without animation in my case) on a reference to the list.

Bit of a pain, but not too bad and works for me.

@sergeyzhukov
Copy link

still broken

@usmansbk
Copy link

usmansbk commented Jul 8, 2023

sigh!

@ashwinmridul
Copy link

ashwinmridul commented Feb 23, 2024

call flatListRef.current.scrollToEnd() inside onEndReached callback of FlatList to scroll to end whenever you reach to the end because of dynamically remove any item.

Can do more optimisations to restrict calling scrollToEnd forcefully everytime the scroll position reaches end of list.

<FlatList
    ref={flatListRef}
    onEndReached={() => {
        if (Platform.OS === 'android') flatListRef.current.scrollToEnd();
    }}
/>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment