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

Animated.View doesn't respect zIndex #23836

Closed
haddow777 opened this issue Mar 10, 2019 · 9 comments
Closed

Animated.View doesn't respect zIndex #23836

haddow777 opened this issue Mar 10, 2019 · 9 comments
Labels
API: Animated Bug Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@haddow777
Copy link

🐛 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
Copy link
Author

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
Copy link
Author

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
Copy link

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/

@stale
Copy link

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 There has been a lack of activity on this issue and it may be closed soon. label Aug 4, 2019
@ksegla
Copy link

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 There has been a lack of activity on this issue and it may be closed soon. label Aug 9, 2019
@codypearce
Copy link

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
Copy link

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

@stale
Copy link

stale bot commented Feb 20, 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 Feb 20, 2020
@stale
Copy link

stale bot commented Feb 27, 2020

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.

@stale stale bot closed this as completed Feb 27, 2020
@facebook facebook locked as resolved and limited conversation to collaborators Feb 28, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
API: Animated Bug Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests

8 participants