soalrib
soalrib

Reputation: 599

Drag moving Animated.Image with react native

I'm making a short game with react native where one image at a time is moving from top to bottom of the screen using Animated. Now I need the moving image to be draggable so that I can programme the drop part after. I'm already using PanResponder but I still can't drag the image. You can see my code below. Any ideas on how to fix this? Thank you for your attention.

import React from 'react';
import { StyleSheet, Text, View, Image, StatusBar, Dimensions, Animated, TouchableOpacity, PanResponder } from 'react-native';
import { Actions } from 'react-native-router-flux';

const largura = Dimensions.get('window').width;
const altura = Dimensions.get('window').height;

export default class JogoArrasto extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            left: Math.floor(Math.random() * ((largura - 120) - 120)) + 120,
            randomImg: Math.floor(Math.random() * (5 - 1)) + 1,
            ingCair: null,
            maca: require('../imgs/maca.png'),
            doce: require('../imgs/doce.png'),
            gema: require('../imgs/gema.png'),
            corpoDeus: require('../imgs/corpoDeus.png'),
            acucar: require('../imgs/acucar.png'),
            pan: new Animated.ValueXY(),   //Step 1 do drag & drop
            ingCertos: 0,
            ingErrados: 0
        }

        this.animatedValue2 = new Animated.Value(0);

        this.panResponder = PanResponder.create({    //Step 2 do drag & drop
            onStartShouldSetPanResponder: () => true,
            onPanResponderMove: Animated.event([null, { //Step 3 do drag & drop
                dx: this.state.pan.x,
                dy: this.state.pan.y
            }]),
            onPanResponderRelease: (e, gesture) => { } //Step 4 do drag & drop
        });
    }

    componentDidMount() {
        if (this.state.randomImg === 1) {
            this.setState({
                ingCair: this.state.maca
            })
        } else if (this.state.randomImg === 2) {
            this.setState({
                ingCair: this.state.doce
            })
        } else if (this.state.randomImg === 3) {
            this.setState({
                ingCair: this.state.gema
            })
        } else if (this.state.randomImg === 4) {
            this.setState({
                ingCair: this.state.corpoDeus
            })
        } else if (this.state.randomImg === 5) {
            this.setState({
                ingCair: this.state.acucar
            })
        }

        this.moveIng2();
    }

    moveIng2 = () => {
        console.log('ing: ' + this.state.randomImg);

        this.animatedValue2.setValue(-120);

        Animated.sequence([
            Animated.timing(this.animatedValue2, {
                toValue: -120,
                duration: 1
            }),
            Animated.timing(this.animatedValue2, {
                toValue: 600,
                duration: 3000
            })
        ]).start(() => {
            this.animatedValue2.addListener(({
                value
            }) => this._value = value);

            let valor = this.animatedValue2._value.toFixed(1);
            this.confere(valor);
        });


    }

    confere = (atualValorIng) => {
        if (atualValorIng == 600) {
            Animated.timing(this.animatedValue2).stop();

            const novoRandom = Math.floor(Math.random() * (5 - 1)) + 1;

            this.setState({
                left: Math.floor(Math.random() * ((largura - 120) - 120)) + 120,
                randomImg: novoRandom
            })

            if (this.state.randomImg === 1) {
                this.setState({
                    ingCair: this.state.maca
                })
            } else if (this.state.randomImg === 2) {
                this.setState({
                    ingCair: this.state.doce
                })
            } else if (this.state.randomImg === 3) {
                this.setState({
                    ingCair: this.state.gema
                })
            } else if (this.state.randomImg === 4) {
                this.setState({
                    ingCair: this.state.corpoDeus
                })
            } else if (this.state.randomImg === 5) {
                this.setState({
                    ingCair: this.state.acucar
                })
            }


            this.moveIng2();
        }
    }

    render() {
        return (
            <View style={styles.main}>
                <StatusBar hidden />
                <TouchableOpacity style={styles.circle} onPress={() => { Actions.menu(); }}>
                    <Text style={styles.textoMenu}>Menu</Text>
                </TouchableOpacity>
                <View style={styles.viewImg}>
                    <Image style={styles.img1} source={require('../imgs/cestoOutros.png')} />
                    <Image style={styles.img2} source={require('../imgs/tacho.png')} />
                </View>

                <Animated.Image
                {...this.panResponder.panHandlers}
                style={[this.state.pan.getLayout(), {
                    position: 'absolute',
                    width: 90,
                    top: this.animatedValue2,
                    left: this.state.left
                }]} source={this.state.ingCair} />

            </View>
        );
    }
}

const styles = StyleSheet.create({
    main: {
        backgroundColor: '#324C5A',
        flex: 1,
        width: '100%',
        height: '100%',
        flexWrap: 'wrap',
        alignItems: 'center',
        alignContent: 'center',
    },
    circle: {
        width: 160,
        height: 80,
        justifyContent: 'center',
        borderBottomLeftRadius: 180,
        borderBottomRightRadius: 180,
        backgroundColor: '#fff',
        marginBottom: 20
    },
    textoMenu: {
        color: '#1D1D1D',
        fontWeight: 'bold',
        textAlign: 'center',
        fontSize: 18
    },
    img1: {
        display: 'flex',
        width: 128,
        marginRight: 20
    },
    img2: {
        display: 'flex',
        width: 128
    },
    viewImg: {
        flexDirection: 'row',
        justifyContent: 'center',
        position: 'absolute',
        bottom: 10,
        alignContent: 'center'
    }
})

Update If I comment these two lines top: this.animatedValue2, left: this.state.left I can drag the Image, but it stops falling from the top to the bottom of the screen. Help please...

Upvotes: 1

Views: 1770

Answers (2)

Derek Nelson
Derek Nelson

Reputation: 89

Not sure exactly what the issue is, but a few bits of advice that'll help:

  1. when I keep animated values in state, sometimes setting state in the middle of an animation makes for weird behavior, so I'd keep it out of state and use a standard animated value.
  2. instead of using top/left (which aren't supported by the native driver), use transform: [{ translateX }, { translateY }] that way you can use the native driver, it'll make the animation way more performant.
  3. check out rn-gesture-handler

Upvotes: 0

Masuk Helal Anik
Masuk Helal Anik

Reputation: 2283

I don't get what exactly do you want but after commenting out top: this.animatedValue2 left: this.state.left Your image response to draggable.

  <Animated.Image
                {...this.panResponder.panHandlers}
                style={[this.state.pan.getLayout(), {
                    position: 'absolute',
                    width: 90,
                    height:500,

                    // top: this.animatedValue2, <--- comment out this line
                    // left: this.state.left     <--- comment out this line
                }]}source={this.state.ingCair} />

Upvotes: 1

Related Questions