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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animated.View doesn't respect zIndex #23836

Open
haddow777 opened this issue Mar 10, 2019 · 7 comments
Open

Animated.View doesn't respect zIndex #23836

haddow777 opened this issue Mar 10, 2019 · 7 comments

Comments

@haddow777
Copy link

@haddow777 haddow777 commented Mar 10, 2019

馃悰 Bug Report

I am trying to follow a tutorial on building a simple stack swiping app similar to how apps like Tinder works. Basically you stack cards and you swipe the top most one to the left or right. Doing so shifts the deck up so the next card is the new top most card.
In our tutorial, this is done by using position absolute on a number of View components and an Animated View component. The order in which they are rendered is so the Animated.View is rendered last.
The problem is that, at least when I render it on my Android device, the Animated.View is always on the bottom. I have tried changing the zIndex of the Animated View, but it has no effect. No matter what I do, the Animated.View is always behind all the others.

To Reproduce

Generate an array of Views, the last of which is an Animated.View, and style them so they are all position: absolute. Render on an Android devices.

Expected Behavior

When rendered last, the Animated.View should be rendered on top of all the other Views. Also, when the zIndex is changed to a very high number, the Animated.View should be rendered on top of all other components.

Code Example

Full code can be found at https://github.com/haddow777/swipe

bascially, the code that generates the Views is this

renderCards() {
    if (this.state.index >= this.props.data.length) {
      return this.props.renderNoMoreCards();
    }
    return this.props.data
      .map((item, i) => {
        if (i < this.state.index) return null; //
        if (i === this.state.index) {
          return (
            <Animated.View
              key={item.id}
              {...this.state.panResponder.panHandlers}
              style={[
                this.getCardStyle(),
                styles.cardStyle,
                { zIndex: this.props.data.length + 1000 }
              ]}
            >
              {this.props.renderCard(item)}
            </Animated.View>
          );
        }

        return (
          <View key={item.id} style={styles.cardStyle}>
            {this.props.renderCard(item)}
          </View>
        );
      })
      .reverse();
  }

  render() {
    return <View>{this.renderCards()}</View>;
  }
}

const styles = {
  cardStyle: {
    position: "absolute",
    width: SCREEN_WIDTH
  }
};

Environment

 React Native Environment Info:
    System:
      OS: Windows 10
      CPU: (4) x64 Intel(R) Core(TM) i5-4300U CPU @ 1.90GHz
      Memory: 2.72 GB / 7.91 GB
    Binaries:
      Yarn: 1.13.0 - C:\Users\SURFACE\AppData\Roaming\npm\yarn.CMD
      npm: 6.8.0 - C:\Program Files\nodejs\npm.CMD
    IDEs:
      Android Studio: Version  3.2.0.0 AI-181.5540.7.32.5056338
Expo CLI 2.11.6 environment info:
   System:
     OS: Windows 10
   Binaries:
     Yarn: 1.13.0 - C:\Users\SURFACE\AppData\Roaming\npm\yarn.CMD
     npm: 6.8.0 - C:\Program Files\nodejs\npm.CMD
   IDEs:
     Android Studio: Version  3.2.0.0 AI-181.5540.7.32.5056338

Android version 8.0.0 on Samsung Galaxy Note 8

@haddow777

This comment has been minimized.

Copy link
Author

@haddow777 haddow777 commented Mar 10, 2019

Also, it should be noted, that in the tutorial, which is a video, when they added the reverse() to the array map that outputs all the components, the Animated.View was on top. In the view, they used an Iphone simulator though. Other searches I have done have shown other people having zIndex issues with Animated.View on Android while not on Iphones.

@haddow777

This comment has been minimized.

Copy link
Author

@haddow777 haddow777 commented Mar 10, 2019

Additional note. I changed the code so each view being output is an Animated View. It did not change anything. Still the on that is being animated is under the rest. So it doesn't have anything to do with the type of View, it has more to do with the fact that one has the PanResponder attached to it.

@JKCooper2

This comment has been minimized.

Copy link

@JKCooper2 JKCooper2 commented Mar 10, 2019

zIndex on Android is known to have issues (or at least require different code to get the solution than ios)
#8968
#18344
#698

Details on zIndex stacking context: https://philipwalton.com/articles/what-no-one-told-you-about-z-index/

@cpojer cpojer mentioned this issue Mar 19, 2019
59 of 161 tasks complete
@react-native-bot react-native-bot added the Bug label May 3, 2019
@hramos hramos removed the Type: Bug Report label May 6, 2019
@stale

This comment has been minimized.

Copy link

@stale stale bot commented Aug 4, 2019

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 label Aug 4, 2019
@ksegla

This comment has been minimized.

Copy link

@ksegla ksegla commented Aug 9, 2019

elevation helped in my case. Component is rendered on top but there are still all kinds of weird things. When the Animated View is on top of something clickable, that something takes precedence. Also, anything that was ever below the Animated View can't be clicked anymore. A mess.

@stale stale bot removed the Stale label Aug 9, 2019
@codypearce

This comment has been minimized.

Copy link

@codypearce codypearce commented Sep 8, 2019

This has come up as an issue on my library with the <AppbarBottom />component when I started wrapping components in an <Animated.View /> to scale them on load. It works fine on iOS and the Web as can be seen in the docs and storybook. However, on android you cannot click the fab .

The Fab component

The <Fab />'s <Animated.View /> is positioned absolute and has a zindex higher than the other components. Here's a simplified version

 <Animated.View
        style={[
          {
            transform: [{ scale: scale }],
            elevation: 100,
            zIndex: 100,
            position: 'absolute', 
          }
        ]}
>
        <Ripple
         style={[
           {
               position: 'absolute',
               zIndex: 100,
            },
          ]}
    >
          {children}
        </Ripple>
      </Animated.View>

The Problem

animatedview

1. Half Touchable
If I remove the transform I can click on the <Fab /> but only the part that is contained within the <AppbarBottom />, not the overflowed part at the top.

bottomripple

2. Full Touchable
If I refactor the <AppbarBottom /> to render the <Fab /> completely outside of the rest of components then the whole <Fab /> is touchable again:

success

Further testing:
3. Adding the transform back again to the <Animated.View />, with the refactored structure above, again makes the <Fab /> untouchable.
4. Removing the <Animated.View /> completely or replacing with a <View /> with the refactored structured also allows for full touchable again.
5. Removing the <Animated.View /> completely or replacing with a <View />, but not using the refactored structure, so the <Fab /> is back inside the <AppbarBottom />, makes the <Fab /> only touchable on the bottom part again.
6. Removing position: absolute on both the <Animated.View /> and the <Fab /> so that appear above the <AppbarBottom /> means that it is fully touchable. But then the <Fab /> does not match Material docs because it's above the <AppbarBottom />.

7. Success
Removing absolute from the <Fab /> and keeping position: absolute on the <Animated.View /> with the transform and the refactored structure finally produced the result I wanted:
success2

Takeways:

  1. Through all of this testing both iOS and the Web (using RNW) were able to fully touch the <Fab />, which mean the problem is specifically with Android.
  2. Adding position: absolute to a Touchable component of Animated.View causes problems with touchability.
  3. Something wrong with zindex or component ordering and touchability on Android since test 5 showed that a touchable component that is nested in a component and positioned absolute, cannot be touched outside of the wrapping component.

This is somewhat of a complicated example, but it is a real use case with examples where Android is not working correctly. If it would help I can recreate these tests with very stripped down components. Anyway I hope someone finds this useful in debugging their app.

@FrickHazard

This comment has been minimized.

Copy link

@FrickHazard FrickHazard commented Nov 22, 2019

@codypearce Thanks for the in depth work. Same issues with our code base. All issues specific to android.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
8 participants
You can鈥檛 perform that action at this time.