I have a background image for my component. I want 1 more image which is 48 * 48 (small image)
to move on it from left to right and top randomly. Here is the code of my background image -
const sectionStyle = {
width: "100vw",
height: "100vh",
backgroundImage: `url(${Background})`,
backgroundSize: 'cover',
backgroundPosition: 'center'
};
Then the render of the compoent has div which uses sectionStyle.
How do I get this small image moving on the background image randomly every few seconds?
One way to accomplish this would be to use use absolute positioning and define state for position of your image. Then you can change positions with setInterval.
It might not be the best way possible but it will get the work done. Here's an example implementation. (I've taken random values for the ease of understanding) -
const styles = {
mainContainerStyle: {
margin: '50px',
background: 'yellow',
padding: '20px',
height: '600px',
},
backgroundContainer: {
position: 'absolute',
background: `url('YOUR_BACKGROUND_IMAGE')`,
width: '400px',
height: '400px',
},
imageStyle: {
position: 'absolute',
top: 0,
left: 0,
width: 45,
height: 45,
borderRadius: 5,
},
}
class ExampleComponent extends Component {
constructor(props) {
super(props);
this.state = {
left: 0,
top: 0,
}
}
randomMovement = () => {
this.setState((prevState) => ({
left: prevState.left + 30 * Math.random(),
top: prevState.top + 30 * Math.random(),
}));
}
render() {
return (
<div style={styles.mainContainerStyle}>
<div style={styles.backgroundContainer}>
<img
src="YOUR_IMAGE_URL"
style={{
...styles.imageStyle,
top: this.state.top,
left: this.state.left,
}}
/>
</div>
</div>
);
}
componentDidMount() {
this.startMovement = setInterval(this.randomMovement, 3000);
}
}
Hope it helps.
Related
I am trying to make an animated menu components which consists out of a main menu button and a few menu items. I am trying to make the menu items to be animated in the following way (see gif below):
See below what i have tried so far but i am unsure of how to accomplish the desired effect. Since i dont know how many menu items there will be and thus cannot set predefined sizes for the container.
In my current attempt i do use predefined sizes and also have no control over each specific item's bounce and delay.
I am new to react native and definitely completely lost when it comes to animating layouts. Any help or pointers would be greatly appreciated!
(this is a part of a more exhaustive menu component hence the additional parent views, but i left most of that out to keep the question to the point).
menu component:
const Menu = function (props: any) {
const anim_def = { duration: 500, easing: Easing.out(Easing.exp) }
const animated_height = useSharedValue(60);
const animated_menu = useAnimatedStyle(() => {
return {
position: "absolute",
bottom: 20,
left: 20,
display: "flex",
flexDirection: "column",
overflow: "hidden",
height: withTiming(animated_height.value, anim_def),
}
});
const generate_menuitems = (): ReactNode[] | null => {
const items: ReactNode[] = [];
if (props.menu_items === undefined) return null;
props.menu_items.forEach((item, index) => {
const styles: ViewStyle = {
marginTop: (index === 0) ? 0 : 20,
backgroundColor: item.backgroundColor
}
items.push(<ImageButton
image={item.image ?? 0}
onPress={() => { on_press_behaviour(index, item); }}
underlayColor={item.highlightColor}
style={[style.buttons, props.style?.buttons, styles]}
></ImageButton>)
});
return items;
}
const on_open_menu = () => {
animated_height.value = 300;
}
return (
<View pointerEvents="box-none" style={{ ...style.container, ...props.style?.container }}>
<View pointerEvents="box-none" style={style.container_wrapper}>
<Animated.View style={animated_menu}>
<ImageButton onPress={on_open_menu} onLayout={(l: LayoutChangeEvent) => {console.log(l.nativeEvent.layout)}} image={0} underlayColor="orange" style={[style.buttons, props.style?.buttons, { position: "absolute", left: 0, bottom: 0, zIndex: 2 }]}></ImageButton>
{generate_menuitems()}
</Animated.View>
</View>
</View>
);
}
component styles:
const style = StyleSheet.create({
container: {
position: "absolute",
left: 0,
bottom: 0,
width: "100%",
height: "100%",
},
container_wrapper: {
position: "relative",
width: "100%",
height: "100%",
},
buttons: {
width: 60,
aspectRatio: 1,
borderRadius: 30,
backgroundColor: "green",
marginTop: 20
}
});
I am new to React Native animated, and I am trying to incorporate it into my app. I currently have an object that appears to fall from the middle to the bottom of the screen, using frequent state updates like this:
const [objHeight, setObjHeight] = useState((Dimensions.get("screen").height)/2)
useEffect(()=>{
if(objHeight > 0){
timerId = setInterval(()=>{
setObjHeight(objHeight => objHeight - 3)
}, 30) //30ms
return ()=>{
clearInterval(timerId)
}
},[objHeight])
//then the object looks like:
<View
style = {[{
position: "absolute",
backgroundColor: 'blue',
width: 50,
height: 60,
bottom: objHeight,
}]}>
</View>
I understand that this is an inefficient way to do animations on react, and that by using react animated we can make animate this on the UI thread instead. I have tried to replicate the above using react native animated.
const objHeight = new Animated.Value(screenHeight/2)
Animated.loop(
Animated.timing(objHeight, {
toValue: objHeight>0 ? objHeight - gravity : null,
duration: 3000,
useNativeDriver: true
}),
{iterations: 1000}
).start()
<Animated.View
style = {[{
backgroundColor: 'blue',
width: 50,
height: 60,
bottom: 200,
transform:[{translateY: objHeight}]
}]}>
</Animated.View>
However, the object does not move/animate. It just stays at the same height. What am I doing wrong? I find the documentation on react native animated is not particularly helpful.
Thank you
Snack Link
First create an Animated.Value with some initial value:
const bottomAnim = useRef(new Animated.Value(Dimensions.get('screen').height / 2)).current;
Then on component mount start the animation:
useEffect(() => {
Animated.timing(bottomAnim, {
toValue: 0,
duration: 3000,
useNativeDriver: true,
}).start();
}, []);
Finally, bind the animated value to the component:
return (
<Animated.View
style={[
{
position: 'absolute',
backgroundColor: 'blue',
width: 50,
height: 60,
bottom: bottomAnim,
},
]}/>
);
This is inside a .tsx file. The styles variable is applied as styles={styles}
var styles = {
bmBurgerBars: {
height: '10px',
right: '20px'
}
//nth child for bmBars
}
I have tried the below code but it is not implementing on the UI
var styles = {
bmBurgerBars: {
height: '10px',
right: '20px',
'&:nth-child(2)': {
width: '80%',
left: '7px',
background: '#111'
}
}
}
Assuming you're using a library such as Material UI (or similar/forked), you can use the following spec:
var styles = {
bmBars: {
height: '10px',
right: '20px',
'&:nth-child(n)': {
color: 'red'
}
}
}
I am trying to animate the scale of my react component. It seems fairly simple and this was basically right out of the React-Motion examples:
var component = () => {
let style = { scale: spring(1.1, presets.wobbly)};
return (
<Motion style={style}>
{value =>
<div
style={{
backgroundColor: 'purple',
height: '50%', width: '50%',
transform: `scale(${value.scale})`,
WebkitTransform: `scale(${value.scale})`,
}}>
</div>
}
</Motion>
);
}
but the component keeps disappearing or not displaying properly for a variety of reasons. How do I get this component's scale to animate properly?
You don't want to use value.scale but just value. Also to improve readability you can use scale instead of value as your parameter. Check this article for a simple example
var component = () => {
let defaultStyle = {scale: 0};
let style = { scale: spring(1.1, presets.wobbly)};
return (
<Motion defaultStyle={defaultStyle} style={style}>
{({scale}) =>
<div
style={{
backgroundColor: 'purple',
height: '50px', width: '50px',
transform: `scale(${scale})`,
WebkitTransform: `scale(${scale})`,
}}>
</div>
}
</Motion>
);
}
In the next code:
return connectDropTarget(
<div style={{ ...style, backgroundColor }}>
{`Works with ${allowedDropEffect} drop effect`}
<br />
<br />
{isActive ? 'Release to drop' : 'Drag a box here'}
</div>,
)
what is the use of ...style for? I can't see any variable declared as style.
It's spread syntax that is being used to copy the contents of an existing style object and then adding/overwriting a backgroundColor property.
const styles = {
position: 'relative',
top: 0,
left: 0
};
const backgroundColor = {
background: '#FFF'
};
const newStyles = {...styles, backgroundColor };
console.log(newStyles);
// newStyles
// {
// position: 'relative',
// top: 0,
// left: 0,
// background: '#FFF'
// }
It can also be used to overwrite existing properties, but keep the others untouched:
const styles = {
position: 'relative',
top: 0,
left: 0,
background: '#222'
};
const backgroundColor = {
background: '#FFF'
};
const newStyles = {...styles, backgroundColor };
console.log(newStyles);
// newStyles
// {
// position: 'relative',
// top: 0,
// left: 0,
// background: '#FFF'
// }
So it's basically an es6 shorthand for Object.assign.
It means that the props of style will be passed as they exists
The style and background might already exists in your page :
const style = {fontSize: "9px", backgroundColor: "red"};