Search code examples
reactjsreact-nativemobile-application

React Native - Randomized view (Circle) on the screen


I am new to react native. I am trying to build a functionality that needs a View (a circle) randomly moving on the screen. Can someone help me where to start with? Thanks in advance.

update: I am now trying to create a draggable component, which should be dragged along the moving circle and while our dragging component is inside the moving circle, there should be a stopwatch which is running and when we remove hand or the draggable component is outside the moving circle the timer should be reset and start from first. I have created the dragging component and the stop watch, but am not able to get the logic of how to combine these.

import React, {Component} from 'react'
import { View, Dimensions,TouchableHighlight,Text, StyleSheet, PanResponder, Animated} from 'react-native'
import { Stopwatch } from 'react-native-stopwatch-timer'
let {width:W,height:H} = Dimensions.get("window");
class Draggable extends Component {
constructor(props) {
super(props);
this.state = {
  showDraggable: true,
  pan: new Animated.ValueXY(),
  opacity: new Animated.Value(1)
};
}
componentWillMount() {
this._val = { x:0, y:0 }
this.state.pan.addListener((value) => this._val = value);
this.panResponder = PanResponder.create({
    onStartShouldSetPanResponder: (e, gesture) => true,
    onPanResponderGrant: (e, gesture) => {
      this.state.pan.setOffset({
        x: this._val.x,
        y:this._val.y
      })

      //console.log(this.state.pan);
      this.state.pan.setValue({ x:0, y:0})
    },
    onPanResponderMove: Animated.event([
      null, { dx: this.state.pan.x, dy: this.state.pan.y }

    ]),
    onPanResponderRelease: (e, gesture) => {
      this.state.pan.setOffset({x: this._val.x, y: this._val.y});
  }
  });
 }
render() {
return (
  <View>
    {this.renderDraggable()}
  </View>
);
}
renderDraggable() {
const panStyle = {
  transform: this.state.pan.getTranslateTransform()
}
if (this.state.showDraggable) {
  return (
      <Animated.View
        {...this.panResponder.panHandlers}
        style={[panStyle, styles.circle, styles.dragstyle,{opacity:this.state.opacity}]}
      />
  );
}
}
}

class MovingCircle extends React.Component{
constructor(props){
    super(props);
    this.state={
        pos:new Animated.ValueXY
    }
}
_loopAnimation(){
    let des = {x:W*Math.random(), y:Math.random()*H};
    //console.log(this.state.des)
    Animated.timing(this.state.pos, {
        toValue:des,
        duration:4000
    }).start(()=>{
        this._loopAnimation();
    });
}
componentDidMount(){
    this._loopAnimation();
}
render(){
    return <Animated.View style={{
        width:60,height:60,
        borderRadius:30,
        backgroundColor:"#0A8648",
        position:"absolute",
        left:this.state.pos.x,
        top:this.state.pos.y
    }}/>
  }
  }

export default class App extends React.Component {
constructor (props) {
super(props);
this.state = {
  stopwatchStart: false,
  stopwatchReset: false,
};
this.toggleStopwatch = this.toggleStopwatch.bind(this);
this.resetStopwatch = this.resetStopwatch.bind(this);
}
toggleStopwatch() {
this.setState({stopwatchStart: !this.state.stopwatchStart, stopwatchReset: false});
}
resetStopwatch() {
this.setState({stopwatchStart: false, stopwatchReset: true});
}
getFormattedTime(time) {
this.currentTime = time;
}
render() {
return (
  <View style={styles.mainContainer} >
    <MovingCircle />
    <View style={styles.dragContainer}>
      <Draggable />
    </View>
    <View style={styles.stopWatchHeader} >
      <Stopwatch laps msecs start={this.state.stopwatchStart}
        reset={this.state.stopwatchReset}
        getTime={this.getFormattedTime} />
      <View style={styles.startResetHeader} >
        <TouchableHighlight onPress={this.toggleStopwatch}>
          <Text style={{fontSize: 20}}>{!this.state.stopwatchStart ? "Start" : "Stop"}</Text>
        </TouchableHighlight>
        <TouchableHighlight onPress={this.resetStopwatch}>
          <Text style={{fontSize: 20}}>Reset</Text>
        </TouchableHighlight>
      </View>
    </View>
</View>
);
}
}

let CIRCLE_RADIUS = 25;
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
backgroundColor:"#D7B68A"
},
circle: {
backgroundColor: "#38395E",
width: CIRCLE_RADIUS * 2,
height: CIRCLE_RADIUS * 2,
borderRadius: CIRCLE_RADIUS
},
dragContainer: {
flex: 1,
flexDirection: "row",
height:150,
justifyContent: "flex-start",
alignItems: "flex-end"
},
stopWatchHeader:{
flexDirection:"row",
backgroundColor:"#FFDEAD",
alignItems:"center",
justifyContent:"space-between",
height:66,
padding:8,
borderRadius:4
},
startResetHeader:{
flex:1,
flexDirection:"row",
justifyContent:"space-around"
}
})

Solution

  • below is a sample, adjust the animation duration and view size by yourself. have a look at the official document of Animations

    import React, {Component} from 'react'
    import { View,
        Dimensions,
         StyleSheet, Animated} from 'react-native'
    
    let {width:W,height:H} = Dimensions.get("window");
    
    export default class test0123 extends React.Component{
    
        constructor(props){
            super(props);
            this.state={
                pos:new Animated.ValueXY
            }
        }
    
        _loopAnimation(){
            let des = {x:W*Math.random(), y:Math.random()*H};
            Animated.timing(this.state.pos, {
                toValue:des,
                duration:3000
            }).start(()=>{
                this._loopAnimation();
            });
        }
    
        componentDidMount(){
            this._loopAnimation();
        }
    
        render(){
            return <Animated.View style={{
                width:50,height:50,
                borderRadius:25,
                backgroundColor:"red",
                position:"absolute",
                left:this.state.pos.x,
                top:this.state.pos.y
            }}/>
        }
    }