Animate paddingLeft React Native - reactjs

i am trying animate paddingLeft property on IOS it isn't work
state = {
paddingAnimation: new Animated.Value(40),
};
animate(){
let {paddingAnimation} = this.state;
Animated.timing( paddingAnimation, { toValue: 100, duration: 100}).start();
}
In Render
<AnimatedInputText style={[styles.search, {margin: paddingAnimation}]}>
It works on Android but not in IOS.
Any solutions ?

You want to Animate padding left then use paddingLeft not margin example
import {
View,
Text,
StyleSheet,Animated,
} from "react-native";
this.state = {paddingAnimation: new Animated.Value(40),}
componentWillMount()
{
Animated.timing( this.state.paddingAnimation, { toValue: 100, duration: 1000}).start();
}
render() {
return (
<View style={styles.container}>
<Animated.Text style={[{paddingLeft: this.state.paddingAnimation}]}>
LoginForm
</Animated.Text>
</View>
});
it will work in both Animated.Text To animate .
Animated exports the following animatable components using the above wrapper:
Animated.Image
Animated.ScrollView
Animated.Text
Animated.View
if you want to create your own use this
Animated.createAnimatedComponent()

Related

TextInput goes Missing, but Keyboard Stays After Every KeyStroke?

Trying to figure out an issue with the TextInput component I have which is acting weird. Basically, after every keystroke, the textinput seems to be losing its focus, but the keyboard seems to stay..
Im implementing it as a search bar that is triggered / animated when a search icon is touched by the user:
<TouchableHighlight
activeOpacity={1}
underlayColor={"#ccd0d5"}
onPress={onFocus}
style={styles.search_icon_box}
>
onFocus method:
const onFocus = () => {
setIsFocused(true);
const input_box_translate_x_config = {
duration: 200,
toValue: 0,
easing: EasingNode.inOut(EasingNode.ease)
}
const back_button_opacity_config = {
duration: 200,
toValue: 1,
easing: EasingNode.inOut(EasingNode.ease)
}
// RUN ANIMATION
timing(input_box_translate_x, input_box_translate_x_config).start();
timing(back_button_opacity, back_button_opacity_config).start();
ref_input.current.focus();
}
just a simple animation where when triggered the search bar will slide from the right side of the screen
<Animated.View
style={[ styles.input_box, {transform: [{translateX: input_box_translate_x}] } ]}
>
<Animated.View style={{opacity: back_button_opacity}}>
<TouchableHighlight
activeOpacity={1}
underlayColor={"#ccd0d5"}
onPress={onBlur}
style={styles.back_icon_box}
>
<MaterialIcons name="arrow-back-ios" size={30} color="white" />
</TouchableHighlight>
</Animated.View>
<SearchBar
placeholder='Search'
keyboardType='decimal-pad'
returnKeyType='done'
ref={ref_input}
value={searchText}
onChangeText={search}
onClear={onBlur}
onSubmitEditing={onBlur}
onFocus={() =>console.log("focus received" ) }
onBlur={() => console.log("focus lost") }
/>
</Animated.View>
Search
const search = (searchText) => {
setSearchText(searchText);
let filteredData = AnimalList.filter(function (item) {
return item.tag_number.toString().includes(searchText);
});
setFilteredData(filteredData);
}
So, when I clicked on the search icon, the search bar will present itself through animated view and the keyboard will automatically be focused. However, after entering a single character on the keyboard the searchbar just vanishes with keyboard still showing.
I tried to debug using onFocus={() =>console.log("focus received" ) } and it looks like the searchBar is still focused on, its just not showing
EDIT: Issue Video Here https://github.com/renwid/test/issues/1
You can show the full version of SearchBar to get more help
[Updated]
The initial step, Animated.Value must be
const input_box_translate_x = useRef(new Value(width)).current;
const back_button_opacity = useRef(new Value(0)).current;
instead of
const input_box_translate_x = new Value(width);
const back_button_opacity = new Value(0);
Because you using the function component and re-render might be re-create the component and the Animated.Value will be re-create too. So the Animated.Value can not keep the state and cause you issue

How to apply animation in react-native?

I want to add animation to this search bar.
when the user touches the search bar it size decreases and again increases and gets to its default size(like animation in popups)
This is my code
<View style={{flexDirection:'row',alignSelf:'center'}}>
<TextInput
onChangeText={(text) => setSearch(text)}
onFocus={()=>{
setSize('92%');
setInterval(()=>{setSize('95%')},1000)
}}
placeholder="Search"
style={{...styles.searchbox,width:size}}
></TextInput>
</View>
I am currently trying to change width..
Firstly, I suggest you to take a look at RN animated documentation, maybe it will help you to understand better how the animations work.
Also, it depends on what you're having there: a class component or a function component.
If you're using a function component, you could do it like this:
Creating a custom hook, called, let's say useAnimation(), which would look something like this
export const useAnimation = ({ doAnimation, duration, initialValue, finalValue }) => {
const [animation, setAnimation] = useState(new Animated.Value(initialValue))
useEffect(() => {
Animated.spring(animation, {
toValue: doAnimation ? initialValue : finalValue,
duration,
bounciness: 8,
useNativeDriver: false
}).start();
}, [doAnimation]);
return animation
}
As it is said in the documentation, you could animate only Animated components, and for example if you want to have an animated View, the tag will be <Animated.View> {...} </Animated.View, but for the <TextInput> we have to create the animated component:
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)
and combining the first 2 steps
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)
const [collapsed, setCollapsed] = useState(true)
const animation = useAnimation({ doAnimation: collapsed, duration: 300, initialValue: 20, finalValue: 200 });
const onFocusText = () => setWidth(false)
return (
<AnimatedTextInput
onFocus={onFocusText}
placeholder={"Search something"}
style={{width: animation, height: 50, borderColor: 'gray', borderWidth: 1, borderRadius: 4, padding: 10}}
/>
)
Also, if you're having a class component, you could have a method which will start the animation (but don't forget about the step 2 which is essential)
private size: Animated.Value = new Animated.Value(COLLAPSED_VALUE)
get resizeInputWidth(): Animated.CompositeAnimation {
return Animated.timing(this.size, {
toValue: EXPANDED_VALUE,
duration: 500,
})
}
startAnimation = () => this.resizeInputWidth.start()
<AnimatedTextInput
onFocus={this.startAnimation}
style={{ width: this.size }}
/>

React native no re-render after updating state array

I have the following code (full example):
import React, { useState, useEffect } from 'react';
import { SafeAreaView, View, Button, StyleSheet, Animated } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
const App = () => {
const [blocks, setBlocks] = useState([]);
const CreateBlockHandler = () => {
let array = blocks;
array.push({
x: new Animated.Value(0),
y: new Animated.Value(0)
});
setBlocks(array);
RenderBlocks();
};
const MoveBlockHandler = (index, event) => {
Animated.spring(blocks[index].x, { toValue: event.nativeEvent.x }).start();
Animated.spring(blocks[index].y, { toValue: event.nativeEvent.y }).start();
};
const RenderBlocks = () => {
return blocks.map((item, index) => {
return (
<PanGestureHandler key={index} onGestureEvent={event => MoveBlockHandler(index,event)}>
<Animated.View style={[styles.block, {
transform: [
{ translateX: item.x },
{ translateY: item.y }
]
}]} />
</PanGestureHandler>
)
});
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.pancontainer}>
<RenderBlocks />
</View>
<Button title="Add block" onPress={CreateBlockHandler} />
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
pancontainer: {
width: '95%',
height:'75%',
borderWidth: 1,
borderColor: 'black'
},
block: {
width: 50,
height: 50,
backgroundColor: 'black'
}
});
export default App;
What does this code do? It's a big square, and a button below it. When I click on the button, a new black square (50x50) is made in the big square. I do this by creating a new array element (the array = blocks). This is done in the function CreateBlockHandler. This does not work correctly!
The function MoveBlockHandler makes the little squares movable. This works!
What does not work? When I create a new black square, the black square is not rendered on the screen. Only when I refresh, the square is rendered. The square is created through CreateBlockHandler, because when I do a console.log(blocks) in that function, I can see that a new array element is added.
How can I force this code to do a full re-render with all the array elements? I tried to wrap the render of the square in a separate function (RenderBlocks) and I'm calling this function every time a new square is made (last line in CreateBlockHandler). The function is called (I can check this with a console.log()) but no squares are rendered.
When you assign blocks to array the reference gete copied which mutates the state, so it doesn't re-render on setState.
const CreateBlockHandler = () => {
let array = [...blocks];
array.push({
x: new Animated.Value(0),
y: new Animated.Value(0)
});
setBlocks(array);
RenderBlocks
There are multiple issues with your code.
As kooskoos pointed out, your state remains referentially equal (it's the same array, only the elements change). This will not trigger re-render.
Also, you are manipulating state of the App component. RenderBlocks component's props and state remain unchanged which implies that they don't need to be re-rendered. Since the component is an anonymous function and is recreated during every render of App, it probably gets re-rendered anyways.
In addition, you are directly calling RenderBlocks, which looks like a component. That is unnecessary and will do nothing here, but if it had any hooks, it would cause problems.
You should probably also conform to the convention that components are PascalCase capitalised and callbacks snakeCase capitalised.

How to translateX, translateY to a certain coordinate rather than a relative point?

My question is about using translateX and translateY in react and/or react-native animations, to animate an object to a certain point.
These two transformations move an object relative to the existing point.
But for the scenario, the existing coordinate is not important and I want to assure the object moves to a certain point wherever it may exist in the screen.
Additional limitation is, I can not animate styles top, bottom, left and right because in react-native, if we animate these styles then we can not use the useNativeDriver={true} directive which causes performance problems.
You can use the onLayout prop to get position (relative to parent) and height/width on any View component.
Something like this should work. You might need to get position of more parent View components, depending on your current structure.
componentDidMount() {
this.animatedValue = new Animated.Value(0);
}
animate() {
const { parentYPosition } = this.state;
Animated.Timing(this.animatedValue, {
toValue: FINAL_POSITION - parentYPosition
}).start();
}
render() {
return (
<View
onLayout={event => {
const { y } = event.nativeEvent.layout;
this.setState({parentYPosition: y})
}}
>
<Animated.View
style={{
position: 'absolute',
top: 0,
transform: [
{
translateY: this.animatedValue
}
/>
/>
);
}
https://facebook.github.io/react-native/docs/view#onlayout

How to scale the size of a button when the user holds down in Animated React / React Native?

I'm trying to create some code that increases the size of a button when the user holds it down then reverts back to the initial size when released.
I'm relatively new to React/RN and have searched tons of websites to find the result, but can't seem to find anything.
I can't tell whether I should be using PanResponder here or not. I also tried using Animated.timing, but the timing is hard-coded & not bound to the length of time that the user holds down the button. I tried Animated.spring, but again that's not bound to length of time that the user holds the button down.
I'll post a quick gif that replicates what I'm trying to go for.
https://imgur.com/a56pSQl
Here's what I have so far:
this.scaleAnimation = new Animated.value(3)
handlePress = () => {
Animated.spring(this.scaleAnimation, {
toValue: 4,
friction: 2,
tension: 160
}).start()
}
render() {
const pauseStyle = {
transform: [
{ scale: this.scaleAnimation }
]
}
return (
<TouchableWithoutFeedback onPress={this.handlePress}>
<Animated.View style={[ pauseStyle ]}>
<Ionicons name="md-pause" />
</Animated.View>
</TouchableWithoutFeedback>
)
}
Any takes are greatly appreciated :D
Please find the detailed answer with code snippets.
Add this to constructor of component
this.handlePressIn = this.handlePressIn.bind(this);
this.handlePressOut = this.handlePressOut.bind(this);
this.animatedValue = new Animated.Value(1);
This method is for scaling button with animation when button gets pressed
handlePressIn() {
Animated.spring(this.animatedValue, {
toValue: 3,
friction: 3,
tension: 40
}).start();
}
This method is for resetting button to its initial scale with animation when touch gets released
handlePressOut() {
Animated.spring(this.animatedValue, {
toValue: 1,
friction: 3,
tension: 40
}).start();
}
Render method
render() {
const animatedStyle = {
transform: [{ scale: this.animatedValue }]
}
return (
<TouchableWithoutFeedback
onPressIn={this.handlePressIn}
onPressOut={this.handlePressOut}
>
<Animated.View style={animatedStyle}>
<Text style={styles.text}>Press Me</Text>
</Animated.View>
</TouchableWithoutFeedback>
);
}
You can use different types of animations. Please find the link for reference:
https://facebook.github.io/react-native/docs/animated#configuring-animations

Resources