In order to listen to activity lifecycle callbacks, set ActivityCallback
in MainApplication.onCreate
as follows:
public class MainApplication extends NavigationApplication {
@Override
public void onCreate() {
super.onCreate();
setActivityCallbacks(new ActivityCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
public class MyApplication extends NavigationApplication {
@Override
public void onCreate() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
});
}
}
MainActivity
won’t workMainActivity
extends SplashActiviy
which is used to start the react context. Once react is up and running MainActivity
is stopped and another activity takes over to run our app: NavigationActivity
. Due to this design, there’s usually no point in overriding lifecycle callbacks in MainActivity
.
Override getSplashLayout
or createSplashLayout
in MainActivity
to provide a splash layout which will be displayed while Js context initialises, for example:
import android.widget.LinearLayout;
import android.graphics.Color;
import android.widget.TextView;
import android.view.Gravity;
import android.util.TypedValue;
import com.reactnativenavigation.controllers.SplashActivity;
public class MainActivity extends SplashActivity {
@Override
public LinearLayout createSplashLayout() {
LinearLayout view = new LinearLayout(this);
TextView textView = new TextView(this);
view.setBackgroundColor(Color.parseColor("#607D8B"));
view.setGravity(Gravity.CENTER);
textView.setTextColor(Color.parseColor("#FFFFFF"));
textView.setText("React Native Navigation");
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40);
view.addView(textView);
return view;
}
}
Snackbars provide lightweight feedback about an operation. They show a brief message at the bottom of the screen. Snackbars appear above all other elements on screen and only one can be displayed at a time.
this.props.navigator.showSnackbar({
text: 'Hello from Snackbar',
actionText: 'done', // optional
actionId: 'fabClicked', // Mandatory if you've set actionText
actionColor: 'green', // optional
textColor: 'red', // optional
backgroundColor: 'blue', // optional
duration: 'indefinite' // default is `short`. Available options: short, long, indefinite
});
A screen can have a header, either an image or a react component, that collapses as the screen is scrolled.
export default class CollapsingReactViewScreen extends Component {
static navigatorStyle = {
navBarHideOnScroll: false,
navBarBackgroundColor: '#4dbce9', // This will be the TitleBars color when the react view is hidden and collapsed
collapsingToolBarComponent: 'example.header',
navBarTranslucent: true, // Optional, sets a translucent dark background to the TitleBar. Useful when displaying bright colored header to emphasize the title and buttons in the TitleBar
showTitleWhenExpended: false, // default: true. Show the screens title only when the toolbar is collapsed
collapsingToolBarCollapsedColor: 'green', // optional. The TitleBar (navBar) color in collapsed state
collapsingToolBarExpendedColor: 'red' // optional. The TitleBar (navBar) color in expended state
};
}
Note: example.header
represents a component that’s registered as a screen:
import Header from './Header';
Navigation.registerComponent('example.header', () => Header);
export default class CollapsingReactViewTopTabsScreen extends Component {
static navigatorStyle = {
navBarHideOnScroll: false, // false, since we collapse the TopBar and the TitleBar remains visible with the top tabs
topBarCollapseOnScroll: true,
navBarBackgroundColor: '#4dbce9', // This will be the TitleBar's color when the react view is hidden and collapsed
collapsingToolBarComponent: 'example.header', // id used to register the component
expendCollapsingToolBarOnTopTabChange: false, // Don't expend the TopBar when selected TopTab changes
collapsingToolBarCollapsedColor: '#4dbce9' // Optional, use this property with navBarTranslucent: true to animate between translucent and solid color title bar color
};
}
Specify topTab
in the screen object you use when starting your app:
Navigation.startSingleScreenApp({
screen: {
screen: 'example.collapsingReactViewTopTabsScreen',
title: 'Collapsing React TopTabs View',
topTabs: [
{
screenId: 'example.ListScreen',
icon: require('../img/list.png')
},
{
screenId: 'example.secondTabScreen',
icon: require('../img/list.png')
}
]
});
Screen transitions provide visual connections between different states through motion and transformations between common elements. You can specify custom animations for transitions of shared elements between screens.
The <SharedElementTransition>
component determines how views that are shared between two screens transition between these screens. For example, if two screens have the same image in different positions and sizes, the <SharedElementTransition>
will translate and scale the image smoothly between these screens.
First, wrap the view you would like to transition in a <SharedElementTransition/>
and give it a unique id. This is how our <Text/>
element is defined in the first screen:
<SharedElementTransition sharedElementId={'SharedTextId'}>
<Text style={{color: 'blue'}}>React Native Navigation</Text>
</SharedElementTransition>
In the second screen, we also wrap the corresponding <Text/>
element but this time, we also specify the transition props:
<SharedElementTransition
sharedElementId={'SharedTextId'}
showDuration={600}
hideDuration={400}
showInterpolation={
{
type: 'linear',
easing: 'FastOutSlowIn'
}
}
hideInterpolation={
{
type: 'linear',
easing:'FastOutSlowIn'
}
}
>
<Text style={{color: 'green'}}>React Native Navigation</Text>
</SharedElementTransition>
</View>
Finally, specify the elements you’d like to transition when pushing the second screen:
this.props.navigator.push({
screen: 'SharedElementScreen',
sharedElements: ['SharedTextId']
}
});
By default, when animating images, a basic scale transition is used. This is good enough for basic use cases where both images have the same aspect ratio. If the images have different size and scale, you can animate their bounds and scale by setting animateClipBounds={true}
on the final <SharedElementTransition/>
element.
The path
interpolator transitions elements along a curved path based on Bézier curves. This interpolator specifies a motion curve in a 1x1 square, with anchor points at (0,0) and (1,1) and control points specified using the showInterpolation
and hideInterpolation
props.
First, wrap the view you would like to transition in a <SharedElementTransition/>
and give it a unique id. In this example we are going to transition an `’.
<SharedElementTransition sharedElementId={'sharedImageId'}>
<Image
style={{height: 50, width: 50}}
source={this.props.image}/>
</SharedElementTransition>
In the <SharedElementTransition/>
wrapping the Image in the second screen, define control points in showInterpolation
and hideInterpolation
props:
<SharedElementTransition
sharedElementId={'sharedImageId'}
showDuration={600}
hideDuration={400}
showInterpolation={
{
type: 'path',
controlX1: '0.5',
controlY1: '1',
controlX2: '0',
controlY2: '0.5',
easing: 'FastOutSlowIn'
}
}
hideInterpolation={
{
type: 'path',
controlX1: '0.5',
controlY1: '0',
controlX2: '1',
controlY2: '0.5',
easing:'FastOutSlowIn'
}
}
>
<Image
style={{height: 100, width: 100}}
source={this.props.image}
fadeDuration={0} // Disable react-native's default 300 ms fade-in animation
/>
</SharedElementTransition>
As in the previous example, specify the elements you’d like to transition when pushing the second screen:
this.props.navigator.push({
screen: 'SharedElementScreen',
sharedElements: ['sharedImageId']
}
});
specify the rate of change of a parameter over time
accelerateDecelerate
- the rate of change starts and ends slowly but accelerates through the middle.accelerate
- the rate of change starts out slowly and and then accelerates.decelerate
- the rate of change starts out quickly and and then decelerates.fastOutSlowIn
- the rate of change starts fast but decelerates slowly.linear
- the rate of change is constant (default)When Shared Element Transition is used, a cross-fade transition is used between the entering and exiting screens. Make sure the root View
has a background color in order for the cross-fade animation to be visible.
To disable the cross-fade animation, set animated: false
when pushing the second screen. Disabling this animation is useful if you’d like to animate the reset of the elements on screen your self.
In most cases, Navigation.startSingleScreenApp()
or Navigation.startTabBasedApp
are called from global context. If the bundle is parsed when the app is not running, this will result in the app opening even though the developer had no intent to open the app.
Navigation.startSingleScreenApp()
or Navigation.startTabBasedApp
are called from global context since RNN assums react context isn’t created when the app is launched. When a background task completes, react context is put into a paused state and not destroyed. Therefore we should also handle the use case where our app is opened when react context is created , and the bundle has already been parsed. We do that by listening to RNN.AppLaunched
event.
import {Navigation, NativeEventsReceiver} from 'react-native-navigation';
Navigation.isAppLaunched()
.then(appLaunched => {
if (appLaunched) {
startApp(); // App is launched -> show UI
}
new NativeEventsReceiver().appLaunched(startApp); // App hasn't been launched yet -> show the UI only when needed.
});
function startApp() {
Navigation.startTabBasedApp({ ... });
}
You can easily reload your app from terminal using adb shell am broadcast -a react.native.RELOAD
. This is particularly useful when debugging on device.