facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
117.23k stars 24.1k forks source link

zIndex in FlatList #28751

Open ShaMan123 opened 4 years ago

ShaMan123 commented 4 years ago

Description

Related? #23614 #23615 Setting zIndex on items of a FlatList yields no result across different rows. However, it does work in the same row across it's columns if existing. I have tried using CellRenderComponent without success. This is crucial for dragging items in a list etc. I can confirm it is cross platform. See the snack below.

React Native version:

React Native version ```bash System: OS: Windows 10 10.0.18362 CPU: (4) x64 Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz Memory: 2.84 GB / 7.87 GB Binaries: Node: 12.14.0 - C:\Users\DELL\AppData\Local\Temp\yarn--1587809387421-0.6934667812958264\node.CMD Yarn: 1.22.0 - C:\Users\DELL\AppData\Local\Temp\yarn--1587809387421-0.6934667812958264\yarn.CMD npm: 6.13.4 - C:\Program Files (x86)\nodejs\npm.CMD Watchman: Not Found SDKs: Android SDK: API Levels: 22, 23, 25, 26, 27, 28, 29 Build Tools: 23.0.1, 23.0.3, 24.0.1, 26.0.2, 27.0.1, 27.0.3, 28.0.0, 28.0.3, 29.0.3, 30.0.0 System Images: android-22 | Google APIs Intel x86 Atom, android-22 | Google APIs Intel x86 Atom_64, android-23 | Intel x86 Atom_64, android-23 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom_64, android-25 | Google APIs Intel x86 Atom, android-26 | Google APIs Intel x86 Atom_64, android-26 | Google Play Intel x86 Atom, android-27 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom_64, android-28 | Google Play Intel x86 Atom, android-28 | Google Play Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom, android-R | Google APIs Intel x86 Atom, android-R | Google Play Intel x86 Atom_64 Android NDK: 17.2.4988734 IDEs: Android Studio: Version 3.5.0.0 AI-191.8026.42.35.5791312 Languages: Java: 1.8.0_172 - C:\Program Files\Java\jdk1.8.0_172\bin\javac.EXE Python: 3.6.5 - C:\Users\DELL\AppData\Local\Programs\Python\Python36-32\python.EXE npmPackages: @react-native-community/cli: Not Found react: ^16.13.0 => 16.13.1 react-native: ^0.62.2 => 0.62.2 npmGlobalPackages: *react-native*: Not Found Done in 13.98s. ```

Steps To Reproduce

  1. Render a list of items with FlatList.
  2. Change items' position and zIndex so an item should render above other items placed after it in the list (descending zIndex).

Expected Results

zIndex should behave the same in FlatList items as it does in other view hierarchies. Meaning a greater value should result in rendering above other views.

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

https://snack.expo.io/VHjFLB_Dz

ShaMan123 commented 4 years ago

Check out how it behaves across rows/columns. zIndex works in the row but not across rows.

zindex

seunghyun-woo commented 4 years ago

I got exact same issue. Any updates?

seunghyun-woo commented 4 years ago

Description

Related? #23614 #23615 Setting zIndex on items of a FlatList yields no result across different rows. However, it does work in the same row across it's columns if existing. I have tried using CellRenderComponent without success. This is crucial for dragging items in a list etc. I can confirm it is cross platform. See the snack below.

React Native version:

React Native version

Steps To Reproduce

  1. Render a list of items with FlatList.
  2. Change items' position and zIndex so an item should render above other items placed after it in the list (descending zIndex).

Expected Results

zIndex should behave the same in FlatList items as it does in other view hierarchies. Meaning a greater value should result in rendering above other views.

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

https://snack.expo.io/VHjFLB_Dz

BTW it's CellRendererComponent, not CellRenderComponent. This may solve your problem?

jcargilo commented 4 years ago

https://github.com/facebook/react-native/issues/23392 Seems to be related (issue template is just a link).

In my case, I have an AutoComplete component within each rendered item that displays a list of items which should overlap the next list item below it. The issue appears to be that z-indexing is somehow backwards (each subsequent item is layered above the one before it) within the FlatList component and there's no way to override it because the rendered item isn't the row component.

You can see this visually by setting inverse={true} which was a bandaid for me to workaround this issue temporarily, at the cost of my list items now being shown backwards. By listing them backwards, the backwards z-index was effectively corrected.

Using React Native 0.61.4 (in case that helps)

bboure commented 3 years ago

Hi,

I am having the same issue. (I am trying to implement a drag-and-drop sort FastList) Setting zIndex inside the renderItem function does not work.

I also tried to use CellRendererComponent and set the zIndex in the Wrapping component, but that would block my animations for some reason.

I finally made it work by making sure that CellRendererComponentis always the exact same instance of the function across re-renders.

Here is a simplified version of my code

  // make sure to use `.bind(this)` in the constructor or use auto binding. 
  renderCell = ({ index, style, ...props }) => {
    const { currentDragIndex } = this.state;
    const zIndex = {
      zIndex: index === currentDragIndex ? 2 : 0,
    };

    return <View style={[style, zIndex]} {...props} />;
  };

  render() {
    const {
      data,
    } = this.props;

    return (
      <FlatList
        data={data}
        // renderCell is always the same instance.
        CellRendererComponent={this.renderCell}
        // ...
      />
    );
  }

In a functional component, you would probably want to use useCallback.

Hope that helps

safaiyeh commented 3 years ago

Thanks for the issue @ShaMan123!

Have you tried @bboure's solution? Does it solve your case?

ShaMan123 commented 3 years ago

Strangely enough on iOS the solution suggested by @bboure works. On android it has no effect. See updated snack with CellRendererComponent fix (thanks @seunghyun-woo) and useCallback.

Twelvefat commented 3 years ago

Hi,

I am having the same issue. (I am trying to implement a drag-and-drop sort FastList) Setting zIndex inside the renderItem function does not work.

I also tried to use CellRendererComponent and set the zIndex in the Wrapping component, but that would block my animations for some reason.

I finally made it work by making sure that CellRendererComponentis always the exact same instance of the function across re-renders.

Here is a simplified version of my code

  // make sure to use `.bind(this)` in the constructor or use auto binding. 
  renderCell = ({ index, style, ...props }) => {
  const { currentDragIndex } = this.state;
  const zIndex = {
      zIndex: index === currentDragIndex ? 2 : 0,
    };

    return <View style={[style, zIndex]} {...props} />;
  };

  render() {
    const {
      data,
    } = this.props;

    return (
      <FlatList
        data={data}
        // renderCell is always the same instance.
        CellRendererComponent={this.renderCell}
        // ...
      />
    );
  }

In a functional component, you would probably want to use useCallback.

Hope that helps

when i was using this way to change my zIndex cause crash on android ? why ? please help, thank you The error say 'java.lang.ArrayIndexOutOfBoundsException: length=2; index=2'

bboure commented 3 years ago

@Twelvefat A quick follow up on this. I too experienced crashing on Android with that solution. I ended up using a ScrollView instead 😞 It least a a temporary workaround.

AndreiBacescu commented 3 years ago

Hi guys. Maybe this will help someone: https://github.com/facebook/react-native/issues/18616#issuecomment-389444165

mmilvydas112 commented 3 years ago

Having same issue. Can we expect a new workaround or a fix this year? it's been about 2 years now.

ChiragMDave commented 3 years ago

Just move ransform:[{translateY:200}] from greenBox style to redBox style and the result will be same in both Scroll and FlatList.. More over, there is absolutely no problem of zindex in FlashList within item and items across rows. I also have a line defined in one item stretching across items in rows.

ChiragMDave commented 3 years ago

Description

Related? #23614 #23615 Setting zIndex on items of a FlatList yields no result across different rows. However, it does work in the same row across it's columns if existing. I have tried using CellRenderComponent without success. This is crucial for dragging items in a list etc. I can confirm it is cross platform. See the snack below.

React Native version:

React Native version

Steps To Reproduce

  1. Render a list of items with FlatList.
  2. Change items' position and zIndex so an item should render above other items placed after it in the list (descending zIndex).

Expected Results

zIndex should behave the same in FlatList items as it does in other view hierarchies. Meaning a greater value should result in rendering above other views.

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

https://snack.expo.io/VHjFLB_Dz

BTW it's CellRendererComponent, not CellRenderComponent. This may solve your problem?

Just move ransform:[{translateY:200}] from greenBox style to redBox style and the result will be same in both Scroll and FlatList.. More over, there is absolutely no problem of zindex in FlashList within item and items across rows. I also have a line defined in one item stretching across items in rows.

adamward459 commented 2 years ago

18616 (comment)

it will block the animation because you have to wait for next render

M-i-k-e-l commented 2 years ago

For anyone that had a crash on Android when using CellRendererComponent: This solution seems to be working, I hope performance won't take too big of a hit.

Couldn't make this workaround work on Android without also having removeClippedSubviews={false} explicitly set.

zhangwen9229 commented 2 years ago
            CellRendererComponent={({ children, item, ...props }) => {
                return (
                    <View onLayout={onLayout}>
                        {children}
                    </View>
                )
            }}
            renderItem={renderItem}
enesozturk commented 2 years ago

+1 It looks like this is open for a long time without a proper solution. I am having the exact same issue recorded here. It's even the same when using the ScrollView.

yolpsoftware commented 1 year ago

Guys, when will this be fixed?

bolan9999 commented 1 year ago

How can I set the List Header zIndex on Android?

ListHeaderComponentStyle={{ zIndex: 9999 }} works well on iOS, but not on Andorid.

julianjear commented 1 year ago

Experiencing this issue as well and even though CellRendererComponent does work, it causes my memoized RenderItem component to re-render (which does not happen if I don't use CellRendererComponent).

Would appreciate a proper fix on this!

Bayramito commented 1 year ago

I tried every single suggestion abouve but unfortunately didn't help me. In my case i want to have pinch zoom functionality just like @wcandillon 's video right here https://www.youtube.com/watch?v=MukiK57qwVY&t=1186s but to achieve this, my zIndex value should be conditional. I tried hold my conditional value in component's local state or mobx state but it did not work at all. Seems like CellRendererComponent runs only once for each cell and not affecting when there is a change on the state. i dont know what to do at this point. I wonder how instagram guys achieved this on their feeds page.I am almost sure they created their own custom native component but...

vberezkin commented 1 year ago

Hi,

I am having the same issue. (I am trying to implement a drag-and-drop sort FastList) Setting zIndex inside the renderItem function does not work.

I also tried to use CellRendererComponent and set the zIndex in the Wrapping component, but that would block my animations for some reason.

I finally made it work by making sure that CellRendererComponentis always the exact same instance of the function across re-renders.

Here is a simplified version of my code

  // make sure to use `.bind(this)` in the constructor or use auto binding. 
  renderCell = ({ index, style, ...props }) => {
  const { currentDragIndex } = this.state;
  const zIndex = {
      zIndex: index === currentDragIndex ? 2 : 0,
    };

    return <View style={[style, zIndex]} {...props} />;
  };

  render() {
    const {
      data,
    } = this.props;

    return (
      <FlatList
        data={data}
        // renderCell is always the same instance.
        CellRendererComponent={this.renderCell}
        // ...
      />
    );
  }

In a functional component, you would probably want to use useCallback.

Hope that helps

It is important to notice that it works only with class components, not functional

kapobajza commented 1 year ago

How can I set the List Header zIndex on Android?

ListHeaderComponentStyle={{ zIndex: 9999 }} works well on iOS, but not on Andorid.

In order to get it working on Android, you should also use the elevation property.

ListHeaderComponentStyle={{ zIndex: 9999, elevation: 1 }}

Bayramito commented 1 year ago

I have solved this thanks

Abhishek2250 commented 1 year ago

For me, it's working on iOS but not on Android. Also, set removeClippedSubviews={false} I have a popup view that gets extended to 2nd item of FlatList but it's getting cut out after the separator of FlatList

code:

    const cellRenderer = (props: any) => {
        const { children, index } = props;
        return (
            <View style={{
                elevation: dataIdToRenderList.length - index,
                zIndex: dataIdToRenderList.length - index,
            }}
            >
                {children}
            </View>
        );
    };
Bayramito commented 1 year ago

what do you guys trying to achieve ?

Abhishek2250 commented 1 year ago

@Bayramito

Screenshot 2023-05-29 at 6 18 29 PM

see in the above screenshot, a blue bg popup should not get cut. It should be above the item 2 of flatlist

Bayramito commented 1 year ago

why do you hold the popup in the row item ?

Bayramito commented 1 year ago

Hope this helps to understand methodology correctly...

const Home = () => {
  const [activePopup, setActivePopup] = React.useState(null);
  return (
    <View style={{flex: 1}}>
      <FlashList
        disableAutoLayout={true}
        data={[0, 1, 2, 3, 4]}
        estimatedItemSize={400}
        ItemSeparatorComponent={() => {
          return <View style={{height: 10}} />;
        }}
        CellRendererComponent={props => {
          return (
            <View
              {...props}
              style={{
                zIndex: activePopup === props.index ? 10 : 2,
              }}>
              {props.children}
            </View>
          );
        }}
        renderItem={({item, index}) => {
          return (
            <View
              style={{
                width: '100%',
                height: 400,
                backgroundColor: 'red',
              }}>
              <TouchableOpacity
                onPress={() => {
                  if (activePopup === null) {
                    setActivePopup(index);
                  } else {
                    setActivePopup(null);
                  }
                }}
                style={{
                  position: 'absolute',
                  bottom: 10,
                  left: 10,
                  backgroundColor: 'blue',
                  padding: 10,
                }}>
                <Text>Click me</Text>
              </TouchableOpacity>
              {activePopup === index && (
                <View
                  style={{
                    position: 'absolute',
                    bottom: -130,
                    left: 50,
                    height: 150,
                    width: 150,
                    backgroundColor: 'yellow',
                  }}>
                  <Text>PopUp</Text>
                </View>
              )}
            </View>
          );
        }}
      />
    </View>
  );
};

Simulator Screen Shot - iPhone 14 - 2023-05-29 at 16 11 37

Abhishek2250 commented 1 year ago

@Bayramito thanks for the quick reply

Screenshot 2023-05-29 at 6 51 09 PM

this is working on iOS but not Android. That's the same issue which I'm facing

Bayramito commented 1 year ago

@Bayramito thanks for the quick reply Screenshot 2023-05-29 at 6 51 09 PM

this is working on iOS but not Android. That's the same issue which I'm facing

Seems like there is a issue on react-native FlatList

changed the code a little bit...

use https://shopify.github.io/flash-list/ which is 10x faster than FlatList

carsonkrueger commented 1 year ago

Still having issues with this Summer of 2023. Please fix.

Maxth commented 11 months ago

I just encountered this problem when I was making a diagram using a flatlist. Each item in the flatlist is a diagram bar and when pressing a bar a popup appears displaying the bar-data in text. You see in the pic below that the popup is on top of one of the adjacent bars but underneath the other one.

My SO-question led me here. I also made a snack for this issue.

For my use case I'll work around this issue by increasing the distance between the diagram bars.

My project is running on RN 0.70.8.

Simulator Screenshot - iPhone 14 - 2023-08-01 at 15 32 30

github-actions[bot] commented 5 months ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

willyuanxu commented 5 months ago

any updates on this?

hgezeery commented 3 months ago

I think this is an important issue to fix.

8KillerMuffin8 commented 3 months ago

This worked for me

CellRendererComponent={({ style, ...props }) => (
    <View style={[style, { elevation: -1 }]} {...props} />
)}
guilhermesandi commented 3 months ago

I just added the two properties below and set the zIndex = 1

CellRendererComponent={({ children }) => children}
removeClippedSubviews={false}