facebook / react-native

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

ImageBackground cannot use Animated component #16939

Closed MrHazimAli closed 6 years ago

MrHazimAli commented 6 years ago

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes

Environment

Environment: OS: macOS Sierra 10.12.6 Node: 8.7.0 Yarn: 1.2.1 npm: 5.4.2 Watchman: 4.9.0 Xcode: Xcode 8.3.3 Build version 8E3004b Android Studio: 2.3 AI-162.4069837

Packages: (wanted => installed) react: 16.0.0 => 16.0.0 react-native: 0.50.2 => 0.50.2

Steps to Reproduce

(Write your steps here:)

Expected Behavior

I expect it's still can be used after nested Image is not supported anymore.

Actual Behavior

I got red screen of death regarding this error because added animated to ImageBackground.

screen shot 2017-11-23 at 11 23 40 am

Reproducible Demo

https://github.com/MrHazimAli/CurrencyConverter

yshing commented 6 years ago

Dear @MrHazimAli , That's not a bug. And it not how Animated is supposed to be used.

Guess you were confused Animated with the package react-native-animatable. https://github.com/oblador/react-native-animatable

MrHazimAli commented 6 years ago

oh.. I see, because Im just following this tutorial and it stated that Animated is imported from react native and in the previous version I can just use nested children and use animated using both of the image component..

https://learn.handlebarlabs.com/courses/175915/lectures/2643157

screen shot 2017-11-24 at 12 27 36 pm screen shot 2017-11-24 at 12 28 01 pm
yshing commented 6 years ago

@MrHazimAli Animated.ImageBackground is something certainly doesn't exist. So though U were confused Animated with any other 3rd party lib.

<Animated.ImageBackground><Animated.Image /></Animated.ImageBackground>

And please read the Error Message. It states very clear that the Component U trying to render is not a component but an undefined

MrHazimAli commented 6 years ago

I see, alright.. noted.. just thought that maybe ImageBackground component will also support the animated like image before.. sorry for taking your time and thought it was a bug, will explore more :-)

thanks! 👍

mimccio commented 6 years ago

@yshing Hi.

So how can we animate the ImageBackground component ?

mimccio commented 6 years ago

@MrHazimAli Here is how I did it:

I wrapped the ImageBackground component in a View

// Logo.js

import React, { Component } from 'react';
import { View, Text, ImageBackground, Keyboard, Animated, Platform } from 'react-native';

import styles from './styles';

const ANIMATION_DURATION = 250;

class Logo extends Component {
  constructor(props) {
    super(props);

    this.containerImageWidth = new Animated.Value(styles.$largeContainerSize);
    this.imageWidth = new Animated.Value(styles.$largeImageSize);
  }

  componentDidMount() {
    let showListener = 'keyboardWillShow';
    let hideListener = 'keyboardWillHide';
    if (Platform.OS === 'android') {
      showListener = 'keyboardDidShow';
      hideListener = 'keyboardDidHide';
    }
    this.keyboardShowListener = Keyboard.addListener(showListener, this.keyboardShow);
    this.keyboardHideListener = Keyboard.addListener(hideListener, this.keyboardHide);
  }

  componentWillUnmount() {
    this.keyboardShowListener.remove();
    this.keyboardHideListener.remove();
  }

  keyboardShow = () => {
    Animated.parallel([
      Animated.timing(this.containerImageWidth, {
        toValue: styles.$smallContainerSize,
        duration: ANIMATION_DURATION,
      }),
      Animated.timing(this.imageWidth, {
        toValue: styles.$smallImageSize,
        duration: ANIMATION_DURATION,
      }),
    ]).start();
  };

  keyboardHide = () => {
    Animated.parallel([
      Animated.timing(this.containerImageWidth, {
        toValue: styles.$largeContainerSize,
        duration: ANIMATION_DURATION,
      }),
      Animated.timing(this.imageWidth, {
        toValue: styles.$largeImageSize,
        duration: ANIMATION_DURATION,
      }),
    ]).start();
  };

  render() {
    const containerImageStyle = [
      styles.containerImage,
      { width: this.containerImageWidth, height: this.containerImageWidth },
    ];

    const imageStyle = [styles.logo, { width: this.imageWidth }];

    return (
      <View style={styles.container}>
        <Animated.View style={containerImageStyle}> // <- here
          <ImageBackground
            source={require('./images/background.png')}
            style={styles.backgroundImage}
            resizeMode="contain"
          >
            <Animated.Image
              source={require('./images/logo.png')}
              style={imageStyle}
              resizeMode="contain"
            />
          </ImageBackground>
        </Animated.View>
        <Text style={styles.text}>Currency Converter</Text>
      </View>
    );
  }
}

export default Logo;
// styles.js
import EStyleSheet from 'react-native-extended-stylesheet';
import { Dimensions } from 'react-native';

const imageWidth = Dimensions.get('window').width / 2;

const styles = EStyleSheet.create({
  $largeContainerSize: imageWidth,
  $largeImageSize: imageWidth / 2,
  $smallContainerSize: imageWidth / 2,
  $smallImageSize: imageWidth / 4,

  container: {
    alignItems: 'center',
  },
  containerImage: {
    alignItems: 'center',
    justifyContent: 'center',
    width: '$largeContainerSize',
    height: '$largeContainerSize',
  },
  backgroundImage: {          // <- new
    alignItems: 'center',
    justifyContent: 'center',
    alignSelf: 'stretch',
    flex: 1,
  },
  logo: {
    width: '$largeImageSize',
  },
  text: {
    fontWeight: '600',
    fontSize: 28,
    letterSpacing: -0.5,
    marginTop: 15,
    color: '$white',
  },
});

export default styles;
alz10 commented 6 years ago

on Logo.js (Do not use the ImageBackground)

<View style={styles.container} resizeMode="contain" >
        <Image style={styles.containerImage} source={require('./images/background.png')} />
        <Image style={styles.image} source={require('./images/logo.png')} resizeMode="contain" />
        <Text style={styles.text}>Currency Converter</Text>
</View>

on styles.js (only change the image property)

image: {
    position: 'absolute',
    margin: 37,
    width: '$largeImageSize',
  },

I'm also taking this Currency Converter course and this Animated component does not work in ImageBackground component.

leoabacade commented 6 years ago

you can use var AnimatedImage = Animated.createAnimatedComponent(ImageBackground) instead of Animated.Image

https://stackoverflow.com/questions/48240857/animation-image-component-cannot-contain-child-even-when-child-component-positi

jhusdero commented 6 years ago

Thank you @leoabacade works for me