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] Calling setValue on an Animated.Value has no effect #25205

Closed
sbeca opened this issue Jun 10, 2019 · 2 comments
Closed

[Android] Calling setValue on an Animated.Value has no effect #25205

sbeca opened this issue Jun 10, 2019 · 2 comments
Labels
API: Animated Bug Platform: Android Android applications. Resolution: Locked This issue was locked by the bot.

Comments

@sbeca
Copy link

sbeca commented Jun 10, 2019

With the following example code:

Example code
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, { Component } from 'react';
import { Animated, Button, Easing, StyleSheet, View } from 'react-native';

type Props = {};
export default class App extends Component<Props> {
  _animatedValue1 = new Animated.Value(1);
  _animatedValue2 = new Animated.Value(1);

  render() {
    return (
      <View style={styles.container}>
        <Button title={'Start Animation'}
          onPress={() => { this._startAnimation(); }} />
        <Animated.View style={
          {
            ...styles.animatedViewBaseStyle,
            transform: [{
              scaleX: this._animatedValue1
            }]
          }
        } />
        <Animated.View style={
          {
            ...styles.animatedViewBaseStyle,
            transform: [{
              scaleX: this._animatedValue2
            }]
          }
        } />
      </View>
    );
  }

  _startAnimation() {
    this._animatedValue1.setValue(0);
    this._animatedValue2.setValue(0);

    Animated.sequence([
      Animated.timing(this._animatedValue1, {
        toValue: 1,
        delay: 0,
        duration: 1000,
        easing: Easing.back(),
        useNativeDriver: true,
      }),
      Animated.timing(this._animatedValue2, {
        toValue: 1,
        delay: 100,
        duration: 1000,
        easing: Easing.back(),
        useNativeDriver: true,
      })
    ]).start();
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  animatedViewBaseStyle: {
    height: 50,
    width: 100,
    marginTop: 10,
    backgroundColor: 'purple'
  },
});

I see the following animation on iOS, which is what I would expect to see:

iOS_Example

But on Android I see this animation, which looks incorrect:

Android_Example

Notice that on iOS, the scale values of both rectangles gets set to 0 at the start of the animation but on Android that is not the case. It looks to me like the calls to setValue(0) aren't working on Android.

React Native version:

info 
  React Native Environment Info:
    System:
      OS: macOS 10.14.5
      CPU: (8) x64 Intel(R) Core(TM) i7-6920HQ CPU @ 2.90GHz
      Memory: 209.27 MB / 16.00 GB
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 12.3.1 - /usr/local/bin/node
      Yarn: 1.16.0 - /usr/local/bin/yarn
      npm: 6.9.0 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2
      Android SDK:
        API Levels: 23, 28
        Build Tools: 28.0.3
        System Images: android-28 | Google APIs Intel x86 Atom
    IDEs:
      Android Studio: 3.4 AI-183.6156.11.34.5522156
      Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.3 => 16.8.3 
      react-native: 0.59.9 => 0.59.9 
    npmGlobalPackages:
      react-native-cli: 2.0.1
      react-native-macos-cli: 2.0.1

Steps To Reproduce

  1. Download attached example project
  2. Run example project on iOS and observe how the boxes animate
  3. Run example project on Android and observe how the boxes animate

Example project:
SetValueTest.zip

@sbeca
Copy link
Author

sbeca commented Jun 10, 2019

As a follow up, it looks this works on Android:

    this._animatedValue1.setValue(0.00001);
    this._animatedValue2.setValue(0.00001);

But this doesn't work on Android:

    this._animatedValue1.setValue(0);
    this._animatedValue2.setValue(0);

Both work fine on iOS.

@cabelitos
Copy link
Contributor

Hello everyone and @sbeca I created a fix for this issue.
Comments and suggestions are appreciated, please see: #25438

Thank you very much.

M-i-k-e-l pushed a commit to M-i-k-e-l/react-native that referenced this issue Mar 10, 2020
…cebook#25438)

Summary:
Prior to this commit React Native on Android was not properly setting
the transform's scale properly correctly when setting it to 0. In order
to properly set one would need to use values close to 0, like 0.0001.
This was happing due to BaseViewManager sharing sMatrixDecompositionContext
across all views in a React Native app.
In some cases the decomposeMatrix() method from the MatrixMathHelper would
return early and not set any new values in sMatrixDecompositionContext
(this is, the new transform values) and
since this is a shared object the BaseViewManager would set the transform values
from the a previous transform.

In order to prevent this issue, before setting the new transform values
always reset the sMatrixDecompositionContext values.

## Changelog

[Android] [Fixed] - Reset sMatrixDecompositionContext before applying transformations
Pull Request resolved: facebook#25438

Test Plan:
Run the code below on an Android device/emulator and you should see the following results:

### Android without the patch - current implementation
Notice that the scale 0 is not properly applied to the last rectangle and the second rectangle does not animate properly.

![android-not-working](https://user-images.githubusercontent.com/984610/60400418-d29e0500-9b49-11e9-8006-63d6956d3a44.gif)

### Android with the patch
Everything works fine

![android-working](https://user-images.githubusercontent.com/984610/60400420-d5005f00-9b49-11e9-9025-f11a9ee62414.gif)

### iOS - current implementation
Everything works fine

![ios-working](https://user-images.githubusercontent.com/984610/60400421-d6ca2280-9b49-11e9-9d81-608780c69936.gif)

```javascript
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * format
 * flow
 */

import React from 'react';
import { Animated, Button, StyleSheet, View, Text, SafeAreaView } from 'react-native';

const HorizontalContainer = ({ children, title }) => (
  <View style={styles.horizontalContainer}>
    {children}
    <Text style={styles.text}>{title}</Text>
  </View>
);

const App = () => {
  const animValue1 = React.useRef(new Animated.Value(1)).current;
  const animValue2 = React.useRef(new Animated.Value(1)).current;
  const onStartAnim = React.useCallback(() => {
    animValue1.setValue(0);
    animValue2.setValue(0);
    Animated.sequence([
      Animated.timing(animValue1, {
        toValue: 1,
        duration: 300,
        useNativeDriver: true,
      }),
      Animated.timing(animValue2, {
        toValue: 1,
        delay: 700,
        duration: 300,
        useNativeDriver: true,
      })
  ]).start();
  }, [animValue1, animValue2]);
  return (
    <SafeAreaView style={styles.container}>
      <Button title="Start Animation" onPress={onStartAnim} />
      <HorizontalContainer title="Animated scale from 0 to 1">
        <Animated.View style={[styles.view, { transform: [{ scaleX: animValue1 }] }]} />
      </HorizontalContainer>
      <HorizontalContainer title="Animated scale from 0 to 1 - delayed">
        <Animated.View style={[styles.view, { transform: [{ scaleX: animValue2 }] }]} />
      </HorizontalContainer>
      <HorizontalContainer title="Scale 0.4">
        <View style={[styles.view, { transform: [{ scaleX: 0.4 }] }]} />
      </HorizontalContainer>
      <HorizontalContainer title="Scale 0.2">
        <View style={[styles.view, { transform: [{ scaleX: 0.2 }] }]} />
      </HorizontalContainer>
      <HorizontalContainer title="Scale 0">
        <View style={[styles.view, { transform: [{ scaleX: 0 }, { translateY: 100 }] }]} />
      </HorizontalContainer>
    </SafeAreaView>
  );
};

export default App;

const styles = StyleSheet.create({
  text: {
    fontSize: 10,
    color: 'black',
    marginLeft: 10,
  },
  horizontalContainer: {
    justifyContent: 'center',
    alignItems: 'center',
    flex: 1,
    flexDirection: 'row',
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  view: {
    width: 100,
    height: 100,
    backgroundColor: 'indigo',
    marginVertical: 5,
  }
});
```
Closes facebook#25205
Closes facebook#6278
Closes facebook#6278

Differential Revision: D16071126

Pulled By: cpojer

fbshipit-source-id: 50820229db2e3c22cf6296831413d26b42f57070
@facebook facebook locked as resolved and limited conversation to collaborators Jul 1, 2020
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 1, 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. Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants