I have a problem with Animated.event with interpolate on scroll event. When I use Animated.event with
useNativeDriver: true
I receive next error:
Style property 'height' is not supported by native animated module
If I use opacity property - it works fine.
My code:
render() {
this.yOffset = new Animated.Value(0);
let event = Animated.event([
{
nativeEvent: {
contentOffset: {
y: this.yOffset
}
}
}
], {useNativeDriver: true});
let opacity = this.yOffset.interpolate({
inputRange: [0, 120],
outputRange: [1, 0],
});
let height = this.yOffset.interpolate({
inputRange: [0, 180],
outputRange: [200, 100],
});
return (
<View>
<Header
style={{
opacity,
height
}}
/>
<ScrollView
style={[
{
flexDirection: "column"
}
]}
scrollEventThrottle={1}
onScroll={event}
>
// some content
</ScrollView>
</View>
);
}
opacity - works.
height - didn't works.
Without useNativeDriver: true - all works fine.
Android Accelerated_x86 API 23
RN 0.43.0-rc.4
React 16.0.0-alpha.3
Problem exists also in RN 0.42.
As the React Native documentation says, you can only animate non-layout properties. Transform property is supported so you can use transform.scaleY instead of changing the height.
Not everything you can do with Animated is currently supported in
Native Animated. The main limitation is that you can only animate
non-layout properties, things like transform, opacity and
backgroundColor will work but flexbox and position properties won't.
Using Native Driver for Animated
This error comes from validateTransform function inside React Native lib.You can check the TRANSFORM_WHITELIST in NativeAnimatedHelper for the property supported by animated module.
Currently, there are these props supported
const TRANSFORM_WHITELIST = {
translateX: true,
translateY: true,
scale: true,
scaleX: true,
scaleY: true,
rotate: true,
rotateX: true,
rotateY: true,
rotateZ: true,
perspective: true,
};
'height' is not in TRANSFORM_WHITELIST; scaleY is.
Just change:
useNativeDriver: true
to
useNativeDriver: false
You can use another property, using gesture handler, there area a example on react-native-gesture handler with PanGestureHandler API:
<Animated.View style={{bottom: 0, transform: [{ translateY: this._translateY },] }}>...
<PanGestureHandler>...
<Animated.View>...
<View >....
Related
I am using react-native-image-picker library to capture image code as follow:
launchImageLibrary({
includeExtra: false,
mediaType: "photo",
selectionLimit: 0,
quality: 1,
maxWidth: 1000,
maxHeight: 1500
}, (res)=>{
console.log(res);
});
When I am taking capture using android real device(portrait) getting image with following:
{
uri: "string",
height: 1000,
width: 750
}
Expected and correct response:
{
uri: "string",
height: 750,
width: 1000
}
can someone help me out?
I advice you to use react-native-image-crop-picker library.
The code below works for me. You can use it without cropping if you do not need it.
import ImagePicker from 'react-native-image-crop-picker';
ImagePicker.openCamera({
width: 768,
height: 1024,
cropping: false,
}).then(image => {
console.log(image)
})
Looks like we have same aspect ratio 3/4. So I guess it may help you.
On android, i have the same problem on cropping the photo. The width are inverted by the height on the new photo cropped.
I fix the problem by removing the original width and height.
(But for Ios, the original width and height are important)
import ImagePicker from 'react-native-image-crop-picker' try {
ImagePicker.openCropper({
path: uri,
// width:2048,
// height: 4096,
includeExif: true,
hideBottomControls: true,
waitAnimationEnd: false,
cropperChooseText: 'ok',
cropperCancelText: 'Cancel',
}).then(async image => {
callback(image.path)
})
I'm playing with react Native and I have a problem with the animation of transition.
Windows 10 - Hyper V, Visual Code Emulator Android - Ignite Boilerplate.
What I'm trying to do:
When I click, I want to show a circle with a scale animation from 0 to 2 on the click position.
What I have:
See the picture below (I have put a setTimout to see the first frame). On the first click, The component is displayed a first time very quickly with its natural width and height but the scale on 0,001 has no effect. After that, the animation begins from the scale 0,001 to 2.
With the other clicks, The circle start the first frames with the dimension of the previous circle. and then, the animation begins. But one more time, the scale : 0 has no effect at the first frame.
Here is the code of the Lunch screen:
export default class LaunchScreen extends Component {
state = {
clicks: []
};
handlePress(evt) {
console.log(evt.nativeEvent.locationX, evt.nativeEvent.locationY)
let xCoord = evt.nativeEvent.locationX;
let yCoord = evt.nativeEvent.locationY;
this
.state
.clicks
.push({x: xCoord, y: yCoord});
this.setState({clicks: this.state.clicks});
}
renderClick() {
if (this.state.clicks.length > 0) {
return this
.state
.clicks
.map((item, i) =>< ClickAnimation key = {
item.x
}
x = {
item.x
}
y = {
item.y
} />)
} else {
return <View/>
}
}
render() {
return (
<View style={styles.container}>
<ScrollView
style={styles.scrollView}
horizontal={true}
showsHorizontalScrollIndicator={true}
contentContainerStyle={styles.scrollView}>
<TouchableWithoutFeedback
style={styles.touchableWithoutFeedback}
onPress=
{evt => this.handlePress(evt)}>
<View style={styles.scrollView}>
{this.renderClick()}
</View>
</TouchableWithoutFeedback>
</ScrollView>
</View>
)
}
}
And here the component of the circle:
import React from 'react';
import PropTypes from 'prop-types';
import {Animated, View, Easing} from 'react-native';
export default class ClickAnimation extends React.Component {
constructor() {
super();
console.log(this.state)
this.state = {
scaleAnim: new Animated.Value(0.001);
};
}
componentDidMount() {
Animated
.timing(this.state.scaleAnim, {
toValue: 2,
duration: 2000
})
.start();
.scaleAnim
}
render() {
return (<Animated.View
style={{
zIndex: 10,
borderColor: "blue",
borderRadius: 400,
borderWidth: 1,
position: "absolute",
top: this.props.y,
left: this.props.x,
width: 60,
height: 60,
backgroundColor: "red",
transform: [
{
scaleY: this.state.scaleAnim
? this.state.scaleAnim
: 0
}, {
scaleX: this.state.scaleAnim
? this.state.scaleAnim
: 0
}
]
}}/>);
}
}
Do you have an Idea why this is so?
I have found the solution.
This come with this issue:
https://github.com/facebook/react-native/issues/6278
I had seen it and this is why I wrote 0,001. But 0,001 is still to little. With 0,01 it works great.
So the answer is:
Just replace 0.001 by 0.01 because it was too little.
Running RN v0.40.0 on a Physical device on Android 5.1. I'm trying to animate a text to appear with fade-in and slide up in the following way:
export default class Example extends PureComponent {
constructor(props) {
super(props);
this.translate = new Animated.Value(-15);
this.fade = new Animated.Value(0);
}
componentWillReceiveProps() {
setTimeout(() => {
Animated.timing(this.translate, {
toValue: 0,
duration: 800,
easing: Easing.inOut(Easing.ease),
}).start();
Animated.timing(this.fade, {
toValue: 1,
duration: 800,
easing: Easing.inOut(Easing.ease),
}
).start();
}, 150);
}
render() {
return (
<View>
<Animated.View
style={{
transform: [
{translateY: this.translate},
],
opacity: this.fade
}}
>
<Text>
{this.props.text}
</Text>
</Animated.View>
</View>
);
}
And after I reload JS bundle from the dev menu and go to that view app crashes with no error log, sometimes showing Application ... stopped working, sometimes not. If I start the app from the android menu again it loads ok, crashes only for the first time. It definitely has something to do with animations since before I introduced animations I had no crashes. There are no logs, no clues, please, give me some advice what could that be and what should I try and what should I check. Thanks.
Btw, on that view with animations I have a pretty heavy background image (~400k) could that be a problem?
UPD: I have narrowed it down to that it crashes when I'm trying to run animations in parallel, either with setTimeout or with Animation.parallel. What could be the problem?
Not sure what's causing the crash, but using Animated.parallel has worked for me:
Animated.parallel([
Animated.spring(
this.state.pan, {
...SPRING_CONFIG,
overshootClamping: true,
easing: Easing.linear,
toValue: {x: direction, y: -200}
}),
Animated.timing(
this.state.fadeAnim, {
toValue: 1,
easing: Easing.linear,
duration: 750,
}),
]).start();
where SPRING_CONFIG is something like
var SPRING_CONFIG = {bounciness: 0, speed: .5};//{tension: 2, friction: 3, velocity: 3};
and pan and fadeAnim values are set in the constructor this.state values as:
pan: new Animated.ValueXY(),
fadeAnim: new Animated.Value(0),
with the animated View as
<Animated.View style={this.getStyle()}>
<Text style={[styles.text, {color: this.state.textColor}]}>{this.state.theText}</Text>
</Animated.View>
and the getStyle function is
getStyle() {
return [
game_styles.word_container,
{opacity: this.state.fadeAnim},
{transform: this.state.pan.getTranslateTransform()}
];
}
This tutorial helped me set this up...good luck!
I am using this library https://reactnavigation.org/docs/intro/ to build android by react-native. I can make the navigation happens on android device but how I can make the screen slide in from the right and fade in from the left. It seems that this behaviour happens on iOS device but not in Android. Is there any animation configuration for android app?
Please see below animation. This is recorded in iOS.
Starting from : "#react-navigation/native": "^5.5.1",
import {createStackNavigator, TransitionPresets} from '#react-navigation/stack';
const TransitionScreenOptions = {
...TransitionPresets.SlideFromRightIOS, // This is where the transition happens
};
const CreditStack = createStackNavigator();
function CreditStackScreen() {
return (
<CreditStack.Navigator screenOptions={TransitionScreenOptions}> // Don't forget the screen options
<CreditStack.Screen
name="Credit"
component={HomeScreen}
options={headerWithLogo}
/>
<HomeStack.Screen
name="WorkerDetails"
component={WorkerDetails}
options={headerWithLogoAndBackBtn}
/>
</CreditStack.Navigator>
);
}
You can watch this video to understand more:
https://www.youtube.com/watch?v=PvjV96CNPqM&ab_channel=UnsureProgrammer
You should use transitionConfig to override default screen transitions as written on this page.
Unfortunately there is no example provided how that function works but you can find some examples in this file: \react-navigation\lib\views\CardStackStyleInterpolator.js
So your code should look like this:
const navigator = StackNavigator(scenes, {
transitionConfig: () => ({
screenInterpolator: sceneProps => {
const { layout, position, scene } = sceneProps;
const { index } = scene;
const translateX = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [layout.initWidth, 0, 0]
});
const opacity = position.interpolate({
inputRange: [
index - 1,
index - 0.99,
index,
index + 0.99,
index + 1
],
outputRange: [0, 1, 1, 0.3, 0]
});
return { opacity, transform: [{ translateX }] };
}
})
});
For StackNavigatoin 6.x.x
Just import
import { TransitionPresets } from '#react-navigation/stack';
Then create a config:
const screenOptionStyle = {
// headerShown: false,
...TransitionPresets.SlideFromRightIOS,
};
And finally just assign them to the Stack Navigator Screen Options:
<Stack.Navigator
screenOptions={screenOptionStyle}
>
<Stack.Screen
...
...
All the above answers are correct, but the solutions work ONLY if you are using createStackNavigator, and not if you are using createNativeStackNavigator; unfortunatelly, if you are following the get started section from react-navigation's docs, you will end up using the latter.
Here you can find a SO question speaking about the differences between the two, but the most relevant one for this questions is that many of the options that your can pass to the former (such as transitionConfig), cannot be passed to the latter.
If you are using createNativeStackNavigator this is how you can do it:
import { createNativeStackNavigator } from '#react-navigation/native-stack'
const StackNavigator = createNativeStackNavigator()
const MyNativeStackNavigator = () =>{
return <StackNavigator.Navigation
screenOptions={{
animation: 'slide_from_right', //<-- this is what will do the trick
presentation: 'card',
}}
>
{routes}
</StackNavigator.Navigator>
}
you need to import StackViewTransitionConfigs from 'react-navigation-stack'
then, override the transitionConfing function.
const myStack = createStackNavigator({
Screen1,
Screen2,
Screen3
},{
transitionConfig: () => StackViewTransitionConfigs.SlideFromRightIOS
}
On #react-navigation/stack component version, the way to do a slide from the right animation is:
<Stack.Navigator
screenOptions={{
cardStyleInterpolator: ({index, current, next, layouts: {screen}}) => {
const translateX = current.progress.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [screen.width, 0, 0],
});
const opacity = next?.progress.interpolate({
inputRange: [0, 1, 2],
outputRange: [1, 0, 0],
});
return {cardStyle: {opacity, transform: [{translateX}]}};
},
}}>
<Stack.Screen name="MainScreen" component={MainScreen} />
...
</Stack.Navigator>
Better you can use the react native navigation for this. You can configure your screen using configureScene method. Inside that method use Navigator.SceneConfigs for animating screen. It's work for both android and iOS.
You can get useful information from index.d.ts file, find the export interface TransitionConfig , then press 'Ctrl' & left_click on NavigationTransitionSpec and NavigationSceneRendererProps, then you can get everything you want.
How do I transition between scenes without animations using Navigator?
When I do a Navigator.replace(), the view just switches instantly, I'd like to replicate this behavior with a Navigator.push() call.
I've been playing around with SceneConfigs and feel like that might be the right solution, but can't get it to work.
I found a hacky solution here. https://github.com/facebook/react-native/issues/1953
var NoTransition = {
opacity: {
from: 1,
to: 1,
min: 1,
max: 1,
type: 'linear',
extrapolate: false,
round: 100,
},
};
return {
...Navigator.SceneConfigs.FloatFromLeft,
gestures: null,
defaultTransitionVelocity: 100,
animationInterpolators: {
into: buildStyleInterpolator(NoTransition),
out: buildStyleInterpolator(NoTransition),
},
};