React native tabview configure sliding speed - animation

I'm using react native tab view https://github.com/react-native-community/react-native-tab-view to have something like a carousel. It seems to work fine, but the sliding transition is too fast for me. How can I configure it? Docs say that there's a configureTransition callback which should return the transition configuration, but doesn't say what's that configuration and how should it look like:
configureTransition - optional callback which returns a configuration for
the transition, return null to disable animation
Please, help me to find out how to configure transition speed.

Transition spec is defined in this file.
import { Animated } from 'react-native';
_configureTransition = () => {
return {
timing: Animated.spring,
tension: 300,
friction: 100,
};
}
render() {
return (
<TabViewAnimated
....
configureTransition={this._configureTransition}
/>
);
}

Related

Complex navigation in React Native using react-navigation and Redux

I have the following navigation structure in my React Native app:
StackNavigator configured with 3 routes:
Splash screen (React Component)
StackNavigator for my login flow
DrawerNavigator for my core app screens.
The DrawerNavigator has some dynamic multiple routes, but also one static route which is another StackNavigator.
Everything seems to be working as expected:
The store is being updated accordingly.
Navigation between screen works.
Go back between screen works when configured within each component, with the following command:
this.props.navigation.goBack();
My question is - is there a way for me to handle back button on Android globally? Currently when I click on the back button, nothing happens (due to the fact I'm using Redux). Should I handle the back button in each component or is there a way of doing it using Redux?
A bit late, but there is a way to handle this with redux. In your index.js file where you create your store you can make export a class and add a componentWillMount call to handle dispatching a call to your redux actions. Just remember to import the actions you need above.
const store = configureStore();
export default class Index extends Component {
componentWillMount = () => {
BackHandler.addEventListener('hardwareBackPress', () => {
const { nav: { routes } } = store.getState();
const currentRouteName = routes[routes.length-1].routeName;
if (currentRouteName === 'EditCoupleProfile') {
store.dispatch(editCoupleActions.navigateBack())
} else if ( currentRouteName === 'EditInterests' ) {
store.dispatch(interestsActions.navigateBack())
} else {
store.dispatch(popFromStack());
}
return true;
})
};
componentWillUnmount = () => {
BackHandler.removeEventListener('hardwareBackPress');
};
render() {
return (
<Provider store={store}>
<AppWithNavigation />
</Provider>
);
}
}

react-native: disable animations

We are using Animated and react-native-animatable quite heavily and starting to notice slowness on some old devices. All animations set useNativeDriver which makes us believe that we may have a few too many animations.
Is there a way to overwrite the Animated prototype to completely disable animations? I looked into this and it didn't seem simple.
Another option I'm considering is to leave my fade animations in but set the initial value in the constructor to the final value. This approach definitely doesn't show any animations but would it also bypass the animation in the native bridge as the value isn't changing?
class Item extends Component {
constructor(props) {
super(props);
this.state = {
opacity: 1 // Notice how this is set to 1
}
}
componentDidMount() {
setTimeout(() => {
this.setState({opacity: 1})
}, 1000)
}
render() {
return (
<Animatable.View style={{opacity}} easing='ease-in' transition='opacity' duration={500} useNativeDriver={true} />
)
}
}
Just create a wrapping component for it and use that instead of Animated.View
export default const AnimatedViewWrapper = (props) => {
if (/* slow device check */) {
return React.createElement(View, props)
} else {
return React.createElement(Animated.View, props)
}
}
You might need to filter the props you receive because View does not have many of the props that Animated.View has. You can get them through View.propTypes. You might need to do this only if __DEV__ is true as propTypes are stripped out in production builds

How I can detect window resize instantly in angular 2?

Some features in my component turn on or off depend on browser size, therefore I want to check browser width on resize event. However, I could do it using OnInit method. But I need to refresh browser when resize happened to update browser width
ngOnInit() {
if (window.innerWidth <= 767){
---- do something
}
}
I tried to use OnChanges method, but it does not work either.
OnChanges(changes:SimpleChanges){
console.log( 'width:====>' + changes[window.innerWidth].currentValue);
if ( changes[window.innerWidth].currentValue <= 767 ){
---- do something
}
}
is there any suggestions or alternative way to accomplish this?
You could just put handler on resize event over window object, but this will allow you to put only single resize event, latest registered event on onresize will work.
constructor(private ngZone:NgZone) {
window.onresize = (e) =>
{
//ngZone.run will help to run change detection
this.ngZone.run(() => {
console.log("Width: " + window.innerWidth);
console.log("Height: " + window.innerHeight);
});
};
}
To make it more angular way use #HostListener('window:resize') inside your component, which will allow to call your resize function(on which HostListner decorator has been mount) on resize of window.
#HostListener('window:resize', ['$event'])
onResize(event){
console.log("Width: " + event.target.innerWidth);
}
Use HostListener. You should probably debounce the resize event though before doing anything, it will fire everytime the size changes which could be dozens or hundreds of times in a few milliseconds as the user drags the window size.
import { Component, HostListener } from '#angular/core';
#Component({...})
class TestComponent {
#HostListener('window:resize')
onWindowResize() {
//debounce resize, wait for resize to finish before doing stuff
if (this.resizeTimeout) {
clearTimeout(this.resizeTimeout);
}
this.resizeTimeout = setTimeout((() => {
console.log('Resize complete');
}).bind(this), 500);
}
}
An easier way would be using the resize method on the html block that you want to detect:
<div class="some-class" (window:resize)="onResize($event)">...</div>
Then in your .ts file you can just add:
onResize(event) {
const innerWidth = event.target.innerWidth;
console.log(innerWidth);
if (innerWidth <= 767) {
...do something
}
}
Add this outside of the ngOnInit() {} unless you wanted the window size on page load.
When you resize your window, you'll see the console.log

Replace one component with another using animation

I'm looking to animate a text field into view and a button out of view at the same time, so that it looks like the text field is replacing the button. (They are both equal size and take up the same area of the screen).
What's the best way to do this using React Native animation?
At this point, I am rendering the button if one of my state values is false, and the text field if it is true.
You can animate any style property in react-native using the Animated API.
If you are able to represent the changes in a sequence of style changes, the Animated API can do it. For instance animating the opacity from 1 to 0 and back to 1 will give a nice fade in fade out effect. The docs explain the Animations much more clearly
Also you can you selective rendering to mount or hide the component
<View style={{/*style props that need to be animated*/}}
{ boolShowText? <Text/> : <View/> }
</View>
The fading example as found in react-native docs
class FadeInView extends React.Component {
constructor(props) {
super(props);
this.state = {
fadeAnim: new Animated.Value(0), // init opacity 0
};
}
componentDidMount() {
Animated.timing( // Uses easing functions
this.state.fadeAnim, // The value to drive
{toValue: 1}, // Configuration
).start(); // Don't forget start!
}
render() {
return (
<Animated.View // Special animatable View
style={{opacity: this.state.fadeAnim}}> // Binds
{this.props.children}
</Animated.View>
);
}
}

React Native: Triggering Animation on hide

I have an element controlling the rendering of a child element. (A TouchableHighlight that sets some state in its onPress.) In the child element's componentDidMount method I construct an Animated.spring and start it. This works for entry, but I need to do the same animation in reverse to exit (it's like a drawer). componentWillUnmount executes too quickly for Animated.spring to even start working.
How would I handle animating the child's exit?
I have implemented a FadeInOut component that will animate a component in or out when its isVisible property changes. I made it because I wanted to avoid explicitly handling the visibility state in the components that should enter/exit with an animation.
<FadeInOut isVisible={this.state.someBooleanProperty} style={styles.someStyle}>
<Text>Something...</Text>
</FadeInOut>
This implementation uses a delayed fade, because I use it for showing progress indicator, but you can change it to use any animation you want, or generalise it to accept the animation parameters as props:
'use strict';
import React from 'react-native';
const {
View,
Animated,
PropTypes
} = React;
export default React.createClass({
displayName: 'FadeInOut',
propTypes: {
isVisible: PropTypes.bool.isRequired,
children: PropTypes.node.isRequired,
style: View.propTypes.style
},
getInitialState() {
return {
view: this.props.children,
opacity: new Animated.Value(this.props.isVisible ? 1 : 0)
};
},
componentWillReceiveProps(nextProps) {
const isVisible = this.props.isVisible;
const shouldBeVisible = nextProps.isVisible;
if (isVisible && !shouldBeVisible) {
Animated.timing(this.state.opacity, {
toValue: 0,
delay: 500,
duration: 200
}).start(this.removeView);
}
if (!isVisible && shouldBeVisible) {
this.insertView();
Animated.timing(this.state.opacity, {
toValue: 1,
delay: 500,
duration: 200
}).start();
}
},
insertView() {
this.setState({
view: this.props.children
});
},
removeView() {
this.setState({
view: null
});
},
render() {
return (
<Animated.View
pointerEvents={this.props.isVisible ? 'auto' : 'none'}
style={[this.props.style, {opacity: this.state.opacity}]}>
{this.state.view}
</Animated.View>
);
}
});
I think you have the animation ownership inverted. If you move your animation logic to the parent that is opening and closing the child, the problem becomes much simpler. Rather than beginning the animation on componentDidMount, do it on the click of your TouchableHighlight in addition to, but independent of, whatever prop manipulations on the child you need to do.
Then when the user clicks to close, you can simply reverse the animation as per normal and you don't really even need to unload it. Also this would allow you to have a reusable drawer (the thing that slides up and down) and it's abstracted away from the content within it. So you can have a single drawer mechanism supporting multiple different types of content.

Resources