1

enter image description here

I have created an extremely large button with a giraffe head and a blue sky with clouds behind. I am wondering how when you click on the giraffe head you can make the image (sky behind) disappear and then reappear when you click the giraffe again. I need lots of these buttons so I have tried to make a reusable button component.

I made a Stack of the Components. https://snack.expo.io/@tamsynjennifer/custom-button

Otherwise this is the code:

REUSABLE BUTTON.JS

import React from 'react';
import { View, StyleSheet, Image, TouchableWithoutFeedback } from 'react-native';

const Button = ({ backgroundImage, mainImage, onPress }) => (
  <View style={styles.container}>
    <Image
       style={styles.bgImage}
       source={backgroundImage}
       resizeMode={'contain'}
    />
    <TouchableWithoutFeedback 
      onPress={onPress}
      style={styles.button}
    >
     <Image
        style={styles.image}
        source={mainImage}
        resizeMode={'contain'}
     />
    </TouchableWithoutFeedback>
  </View>
);

const styles = StyleSheet.create({
  container: {
    height: 250,
    width: 250,
    justifyContent: 'center',
    alignItems: 'center',
    marginTop: 0,
  },
  button: {
    height: 200,
    width: 200
  },
  bgImage: {
    alignSelf: 'center',
    justifyContent: 'center',
    position: 'absolute',
    height: 250,
    width: 250,
  },
  image: {
   alignSelf: 'center',
    justifyContent: 'center',
    position: 'absolute',
    height: 200,
    width: 200
  },
});

export default Button;

APP.JS

import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { Constants } from 'expo';

const bgImage = require("./assets/BgImage.png");
const mainImage = require("./assets/MainImage.png");

import Button from './Button';

class App extends Component {
  render() {
    return (
      <View style={styles.container}>
          <View style={styles.button}>
             <Button
                backgroundImage={bgImage}
                mainImage={mainImage}
             />
          </View>

      </View>
     );
   }
}

const styles = StyleSheet.create({
  container: {
    height: 300,
    width: 300,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    height: 250,
    width: 250,
    alignSelf: 'center',
    position: 'absolute' 
  },
});

export default App;
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Tamsyn Jennifer
  • 517
  • 2
  • 6
  • 20

2 Answers2

1

This is how you can do it, I have fixed your code. Firstly you need to setState and change state onPress, so that the component re-render and change the image. Simply replace your class with this. Expo Link

import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { Constants } from 'expo';

const bgImage = require("./assets/BgImage.png");
const mainImage = require("./assets/MainImage.png");

import Button from './Button';

class App extends Component {
constructor(props){
super(props)
this.state = {
  imageVisibility: true,
  backgroundImagePath: require("./assets/BgImage.png")
}
}

  render() {
    return (
      <View style={styles.container}>
          <View style={styles.button}>
             <Button
                backgroundImage={this.state.backgroundImagePath}
                mainImage={mainImage}
                onPress= {() => {this.changeImgaeVisibility()}}
             />
          </View>

      </View>
     );
   }

   changeImgaeVisibility = () => {
   if(this.state.imageVisibility){
       this.setState({imageVisibility: false, backgroundImagePath: null})
   }else{
       this.setState({imageVisibility: true, backgroundImagePath: require("./assets/BgImage.png")})
   }
   }

   }

const styles = StyleSheet.create({
  container: {
    height: 300,
    width: 300,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    height: 250,
    width: 250,
    alignSelf: 'center',
    position: 'absolute' 
  },
});

export default App;
Haider Ali
  • 1,275
  • 7
  • 20
  • yes it did work although because I need lots of these buttons it becomes a problem when they are all on the same screen- when you click one they are all visible or all invisible. https://snack.expo.io/@tamsynjennifer/custom-button-2 So what I thought was I took your concept and put it in the Button Component instead to make it reusable and to have more than one button on the same screen. https://snack.expo.io/@tamsynjennifer/custom-button-2_separate-clicks – Tamsyn Jennifer Oct 03 '18 at 23:47
  • Maybe there is a really easy and better way to fix the problem of having more than 1 button on the screen? I am new to state so I am not sure if what I did is best practice?? Also I know the initial code didn't have two buttons. So thanks a lot for your help!! – Tamsyn Jennifer Oct 03 '18 at 23:49
  • https://snack.expo.io/@tamsynjennifer/custom-button-2_separate-clicks this works for having two buttons on the same screen. – Tamsyn Jennifer Oct 04 '18 at 00:09
  • Did you read my comments above and check the other two snack examples? – Tamsyn Jennifer Oct 04 '18 at 07:48
  • The code seems to look fine, you implemented the state change in your Button component, calling buttons separately will make a different object, It will work fine. – Haider Ali Oct 04 '18 at 07:58
  • Yes your code works! Thank you!!! I just thought I would show you that I moved it to the button component because I need more than 1 button on a screen and if you have it in the App.js then you can’t click separately. – Tamsyn Jennifer Oct 04 '18 at 08:06
0

You can add a function as a javascript object to your JSX to render the background image, this method will return the object that you need to render, as you can see in the example bellow:

const handleBackgroundImg = (imageBg, backgroundiImage) => {
  if (imageBg === true) {
   return <Image style={styles.bgImage} source={backgroundImage} resizeMode={'contain'}/>
  }
  return <Image />;
};

To add this function to your JSX code you have to change it like this:

const Button = ({ backgroundImage, mainImage, onPress, imageBg }) => (
  <View style={styles.container}>
    {handleBackgroundImg(imageBg, backgroundImage)}
    <TouchableWithoutFeedback 
      onPress={onPress}
      style={styles.button}
    >
     <Image
        style={styles.image}
        source={mainImage}
        resizeMode={'contain'}
     />
    </TouchableWithoutFeedback>
  </View>
);

Now when you use this component you have to pass the imageBg boolean as well, considering true when you want to show the bg and false when you want to hide it. See the code below:

<Button
  backgroundImage={bgImage}
  mainImage={mainImage}
  imageBg={true}
/>

If you have any doubt, ask here again and I can help you.

ROFactum
  • 21
  • 3
  • Thanks for taking the time to reply. I can't get your example to work. I get the error "Can't find variable: backgroundImage" – Tamsyn Jennifer Oct 03 '18 at 23:27
  • I edited the code to fix this problem, I forgot to pass your background as a parameter to the handleBackgroundImg function. I saw that you already used another way to fix the problem, but if you wanna try a different solution, hopefully it can help. – ROFactum Oct 04 '18 at 10:27
  • I tried it out and there are no errors now but when I click on the giraffe nothing happens. The background doesn't disappear. Does it work for you? Don't worry too much though there is another solution above. Thanks you anyway! – Tamsyn Jennifer Oct 04 '18 at 10:43
  • It is happening probably because in your onPress function you are not changing the state of the app. Every time something in the screen have to be re-rendered you have to change the state, therefore the render method will be called again. – ROFactum Oct 04 '18 at 11:12