react-native-ios-navigator
v0.4.2
Published
A native wrapper component around `UINavigationController` for react-native
Downloads
38
Maintainers
Readme
react-native-ios-navigator
A native wrapper component around UINavigationController
for react-native.
🚧⚠️ Library WIP ⚠️🚧
- Currently in development... 😅 (See TODO.md for current progress).
- The documentation is incomplete (some parts/sections are marked as TBA i.e. "to be added").
- Some of the links in the documentation are broken (i.e. the URL points to
PLACE_HOLDER_LINK
).
Quick Links
😌💬 Hey there, if you're just checking this library out, I recommend jumping to the Showcase, Tests, and Demos section (It has a bunch of gifs showing all the various features).
| Section + Link | Description |
| :---------------------------------------------------------- | ------------------------------------------------------------ |
| ⭐️ Getting Started Guide | Discussion + step by step guide (w/ accompanying gifs + screenshots) on how to use this library and its various components.Related Links:1️⃣ Installation2️⃣ Basic Usage |
| 💖 Usage and Examples | Example usage that covers the various components and functionality of this library. |
| 💫 Showcase, Tests, and Demos | Just some gifs, screenshots + vibes that shows what this library can do. |
| 📝 Documentation | Documentation for all the various components, functions, types, etc.Sub-Section Links:1️⃣NavigatorView
Component2️⃣RouteViewPortal
Component3️⃣RouteViewEvents
Component4️⃣RouteHeaderView
Component5️⃣ Context6️⃣ Hooks7️⃣ Objects and Types8️⃣ Native-Related |
A. Introduction
Before you use this library, please first consider looking at react-navigation
, react-native-navigation
, and react-router
. They offer more features, are battle-tested, well maintained, and most importantly: cross-platform. This library is more of a personal pet project 😌.
A.1. Motivation
Expose Everything
This is a wrapper library, so the goal is (for better, or for worse) to expose almost everything to react-native.
I tried to expose, in some way or another, all the ways the UINavigationController
, UINavigationBar
, and UIViewController
could be configured and customized. Unfortunately, this means that the API + documentation is a little dense/complex, and might be a little bit confusing to non-iOS developers (so I tried to include as much explanations, examples + gifs and images as I could).
Resurrecting NavigatorIOS
Basically, react-native
deprecated the built-in NavigatorIOS
component starting on version 0.58
.
One thing that I liked about NavigatorIOS
is that it behaved like any regular old <View/>
component. Which is fun since you can just plop it down anywhere in your app, and it'll just "work" (this included the weird quirk of having multiple navigators 🤷♀️).
📝 Notes
- Modal support is handled via
react-native-ios-modal
(WIP) - Adding menu's/submenu's in the navigation bar is handled via
react-native-ios-context-menu
(WIP)
A.2. Features
💡 Tip: You can also just browse through the gifs/images in the Showcase, Tests, and Demos section.
- Support for using native routes (e.g.
UIViewController
). Allows you to combine js/react routes and native routes together.- Support for controlling the navigator from native/swift-side (e.g. pushing routes, etc.)
- Support for passing data (i.e.
routeProps
) between native and JS/React routes.
- Support for multiple initial react/native routes (useful for state-restoration, e.g. restoring the navigation stack on app startup).
- Support for using custom transitions (e.g. crossfade, slide, flip, etc).
- Support for customizing the navigation bar either through the "legacy" API (iOS 11 and below), or the newer appearance API (iOS 13+).
- This includes per-route customizations using either the "legacy" or "appearance" modes.
- Support for:
- Using routes with a
UISearchBar
in the navigation bar. - Using either custom react components or standard navigation bar controls (e.g. buttons, text, icons) for the navigation bar items (e.g. navigation bar title, left items, right items).
- Customizing the font style of the navigation bar title + large title.
- Per-route navigation bar visibility and status bar style.
- Customize the navigation bar tint, background color, background image, back indicator, blur effects, shadow, etc.
- Support for generating images (e.g. solid colors, gradients, rounded rects, etc) that can be used as the navigation bar background, navigation bar items... basically, anywhere that accepts an image.
- Etc.
- Using routes with a
- Exposes almost all of the
UINavigationController
/UIViewController
-related events. - Exposes all of the things that can be configured in the view controller's
UINavigationItem
(title
,prompt
,largeTitleDisplayMode
,backBarButtonItem
, etc). - Etc.
B. Installation
# install via npm...
npm install react-native-ios-navigator
# or install via yarn.
yarn add react-native-ios-navigator
# then run pod install (uses auto-linking)
cd ios && pod install
📝 Note: This library is written in swift, so if you're having troubles building your project, try adding an empty swift file so that Xcode will generate a bridging-header.h
file for your project.
Additional Setup
In your project's Info.plist
file, set the "View controller-based status bar appearance" key from NO
to YES
. Toggling this property allows you to set the status bar style on a per-route basis.
Troubleshooting
The following build errors can usually be resolved by adding an empty swift file:
However, the older versions of the react-native template (e.g. 0.63
and below) hard codes the swift library search paths to use swift 5.0
(which causes the linker to mismatch the swift system libraries bundled with Xcode + iOS version). To fix this issue, just remove the following entries from the project config's library search path:
Versions
| Library Version | Compatibility |
| ----------------- | ----------------------------- |
| 0.4.0
+ | iOS 10 to iOS 15Xcode 13 |
| 0.3.1
and Below | iOS 10 to iOS 14Xcode 12 |
C. Basic Usage
This snippet is an excerpt from the Navigation Hello World section.
import * as React from 'react';
import { SafeAreaView, TouchableOpacity, Text } from 'react-native';
import { NavigatorView } from 'react-native-ios-navigator';
// Route to show in the navigator
function ExampleRoute(props){
return (
<SafeAreaView>
<TouchableOpacity onPress={() => {
props.navigation.push({
routeKey: 'routeA'
});
}}>
<Text> Push: 'RouteA' </Text>
</TouchableOpacity>
</SafeAreaView>
);
};
export function App() {
return(
<NavigatorView
initialRoutes={[{routeKey: 'routeA'}]}
routes={{
routeA: {
renderRoute: () => (
<ExampleRoute/>
),
}
}}
/>
);
};
D. Documentation
💡 Tip: Most of the time, when a type or component is mentioned, you can click it to jump to that item in the README (or its declaration in the source code).
D.1. Components
D.1.1. NavigatorView
Component
This component is a wrapper around UINavigationController
, and as such, it also facilitates navigation in a stack-like manner (where in routes are "pushed" and "popped" in and out of the navigation stack). Only one route can be shown at a given time. However it is possible to have multiple NavigatorView
instances at the same time.
- Each instance will have their own separate navigation stack, allowing you to show multiple routes at once.
- But do note that the 1st instance will always be treated as the "root" navigation controller, and subsequently, it’ll become responsible for handling things like setting the color of the status bar, etc.
Internally, each NavigatorView
component corresponds to a UINavigationController
instance, and conversely, each route in the navigation stack corresponds to a UIViewController
instance.
- The “route content” (i.e. the element returned from a route’s
renderRoute
function) gets wrapped inside a view controller instance. - That view controller is then sent off to the
UINavigationController
.
Each route has a corresponding RouteOptions
object associated with it. This object is used internally to configure various aspects of the UINavigationController
, UINavigationBar
, UINavigationItem
, UIViewController
, etc.
NavigatorView
Component: Props
NavigatorView
General Props
| Prop Name and Type | Description |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| 🔤 Required: routes
⚛️ NavRoutesConfigMap
| Configures what routes can be used inside the navigator.This prop accepts a NavRoutesConfigMap
object. This object is a map/dictionary of NavRouteConfigItem
objects, where in the key of each property is its routeKey
(e.g. { RouteA: {...}, RouteB: {...} }
).These objects are used to create and configure the routes. Those "route config" objects include things like: • A. what component to show when the route becomes active (i.e. the NavRouteConfigItem.renderRoute
property),• B. the initial routeProps
that the route will receive (e.g. NavRouteConfigItem.initialRouteProps
), and• C. other misc. options that'll determine the look of the navigation bar, the route's transitions, etc. (i.e. NavRouteConfigItem.routeOptionsDefault
). 📝 Note: The routeKey
for the route config object must be unique for each route item.There are actually two types of routes that you can use:• A. The first one is a "JS route" (i.e. a route defined in react/js-side using standard react components).• B. The second one is a "native route" (i.e. a route defined in the native-side using native code (e.g. UIViewController
+ storyboards, auto layout, etc).📌 Related Sections:• RouteOptions
• RouteOptions
Precedence• NavRouteConfigItem
|
| 🔤 Required: initialRoutes
⚛️ Array<NavRouteItem>
| Used by the navigator to determine which initial routes to show when the navigator first mounts.This prop accepts an array of NavRouteItem
objects. The routeKey
values in the objects must match with a route configured in the routes
prop. This prop basically represents the navigation stack during the first mount (e.g. with the first item being the root route, and the last item being the topmost active route).For example, if you pass [[{routeKey: 'A'}, {routeKey: 'B'}]]
as the initial routes, then route "A" will become the root route, and route "B" will become the topmost route. Thus, on the first mount route "B" will first be shown, and by pressing the back button, route "B" will be popped, and then route "A" will be shown. 💡 Tip: This behavior of being able to set the initial routes is useful for state-restoration (or for when you want to show a different initial route based on some condition). |
| ⚛️ ViewProps
| This component also supports all the standard props from a <View/>
component. |
| 🔤 style
⚛️ ViewStyle
| The style applied to the the NavigatorView
component itself.📝 Note: The layout size of the NavigatorView
will also determine the layout size of the routes, so if the size of the navigator is 100 x 100, then the routes will also be 100 x 100. |
| 🔤 navBarPrefersLargeTitles
⚛️ boolean
✳️ Default: true
on iOS 11+ | Specifies whether or not to use the large title style for the navigation bar title. Defaults to true
on iOS 11 and above.Maps to the UINavigationBar.prefersLargeTitle
property,📝 Note: This prop can be overridden on a per route basis either via largeTitleDisplayMode
in the NavigatorView.routes
prop, or via the RouteViewPortal.routeOptions
prop. |
| 🔤 navBarAppearance
⚛️ NavBarAppearanceCombinedConfig
| This prop allows for the customization of the UINavigationBar
. The navigation bar can be customized via two modes, namely:• A. "legacy" mode (iOS 12 and below), and• B. "appearance" mode (iOS 13 and above).The "legacy" mode, as the name would suggest, uses "legacy customizations" (where in the navigation bar is customized using the old API via directly manipulating the navigation bar object's properties).The "appearance" mode on the other hand, uses UINavigationBarAppearance
to apply customizations for each of the "navigation bar" styles/states, namely:1️⃣ standardAppearance
(normal height),2️⃣ compactAppearance
(compact-height, e.g. iPhones in landscape, etc.),3️⃣ scrollEdgeAppearance
(when the navigation bar doesn't have content behind it and is currently scrolled all the way to the top), and 4️⃣ compactScrollEdgeAppearance
(a combination of compact and scroll edge, requires iOS 15+) .📝 Note: There is one big caveat though, once "appearance" mode is used, "legacy" mode no longer works (it's some sort of bug in UIKit
). In other words, switching between the two modes is not supported, only stick to one. When targeting iOS 12 and below, use "legacy", otherwise use "appearance".💡 Tip: Check the guides section for examples on how to customize the navigation bar, or browse the NavBarAppearanceCombinedConfig
object for the full list of properties.💡 Tip: The navigation bar can also be customized on a per-route basis via the RouteOptions.navBarAppearanceOverride
. You can set this property either via routeOptionsDefault
in a route's config (in the NavigatorView.routes
prop), or via the RouteViewPortal
component using the RouteViewPortal.routeOptions
prop. |
| 🔤 isNavBarTranslucent
⚛️ boolean
| Determines whether or not the the navigation bar is translucent. Maps to UINavigationBar.isTranslucent
. |
| isInteractivePopGestureEnabled
⚛️ boolean
| Enables or disables the interactivePopGestureRecognizer
. In other words, this prop sets whether swiping on the left edge of the screen will pop the current route. Defaults to true
. |
| 🔤 shouldSwizzleRootViewController
⚛️ boolean
| Determines whether or not the root view controller's default implementation is changed at run-time (i.e. "swizzled") to enable certain features (e.g. like enabling "view controller based status bar" via delegating childForStatusBarStyle
to a child view controller, etc).The "injected" implementation is lifted from RNIRootViewController
. Defaults to true
, however this will only take effect for the first NavigatorView
component, and also only if the parent view controller is the same instance as the one in window.rootViewController
.For brownfield projects with native code (or for projects with an existing navigation solution), set this to false
to disable this behavior. |
| 🔤 disableTransparentNavBarScrollEdgeAppearance
⚛️ boolean
✳️ Default: true
| In iOS 15+ the navigation bar by default is now configured to have a transparent background until the user scrolls and there's some content behind the navigation bar (i.e. the scrollEdgeAppearance
is now configured to be transparent by default).This prop determines whether or not to apply a background color to navigation bar using scrollEdgeAppearance
. Set this to false if you want to keep the default behavior📝 Note A: You can manually do what this prop does by providing your own scrollEdgeAppearance
appearance config either globally via the NavigatorView.navBarAppearance
prop, or on a per-route basis via the RouteOptions.navBarAppearanceOverride
property.📝 Note B: This prop only takes effect on iOS 15+ and when a route disables the large title. This prop does not affect native routes. |
NavigatorView
Render Props
| Prop Name and Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 renderNavBarLeftItem
⚛️ RenderNavItem
i.e. (navigation: NavigationObject) => ReactElement ¦ null ¦ undefined
📌 navigation: NavigationObject
| Sets a default left item for the navigation bar for all the routes.📝 Note A: The left navigation bar item can be overridden/replaced on a per route basis via NavRouteConfigItem.renderNavBarLeftItem
in the NavigatorView.routes
prop, or via RouteViewPortal.renderNavBarLeftItem
prop.📝 Note B: If this prop is used, it'll implicitly set RouteOptions.navBarButtonLeftItemsConfig
to { type: 'CUSTOM' }
for a route's routeOptions
. So if the navBarButtonLeftItemsConfig
is explicitly set to anything other than "custom", then this prop will not do anything.📝 Note C: If a route's RouteOptions.leftItemsSupplementBackButton
is set to false
(which it isn't by default), then it will replace the back button (i.e. the back button will not be shown). |
| 🔤 renderNavBarRightItem
⚛️ RenderNavItem
i.e. (navigation: NavigationObject) => ReactElement ¦ null ¦ undefined
📌 navigation: NavigationObject
| Sets a default right item for the navigation bar for all the routes.📝 Note A: The right navigation bar item can be overridden/replaced on a per route basis via NavRouteConfigItem.renderNavBarRightItem
in the NavigatorView.routes
prop, or via RouteViewPortal.renderNavBarRightItem
prop.📝 Note B: If this prop is used, it'll implicitly set RouteOptions.navBarButtonRightItemsConfig
to { type: 'CUSTOM' }
for a route's routeOptions
. So if the navBarButtonRightItemsConfig
is explicitly set to anything other than "custom", then this prop will not do anything. |
| 🔤 renderNavBarTitleItem
⚛️ RenderNavItem
i.e. (navigation: NavigationObject) => ReactElement ¦ null ¦ undefined
📌 navigation: NavigationObject
| Sets a default title item for the navigation bar for all the routes.📝 Note: The title navigation bar item can be overridden/replaced on a per route basis via NavRouteConfigItem.renderNavBarTitleItem
in the NavigatorView.routes
prop, or via RouteViewPortal.renderNavBarTitleItem
prop.💡 Tip: You can access the route's routeTitle
via the navigation
object (i.e. navigation.routeOptions.routeTitle
). |
NavigatorView
Event Props
| Prop Name and Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 onNavRouteWillPop
⚛️ OnNavRoutePopEvent
📌 OnNavRoutePopEventObject
| Event that is triggered when a route is about to be "popped" from the navigation stack (i.e. when the pop transition has started). |
| 🔤 onNavRouteDidPop
⚛️ OnNavRoutePopEvent
📌 OnNavRoutePopEventObject
| Event that is triggered when a route has been "popped" from the navigation stack (i.e. the pop transition has already been completed). |
| 🔤 onCustomCommandFromNative
⚛️ OnCustomCommandFromNativeEvent
📌 OnCustomCommandFromNativeEventObject
| Event that is triggered from the native-side via the RNINavigatorNativeCommands.sendCustomCommandToJS
delegate method.This event exists to receive custom user-defined commands from a RNINavigatorView
(i.e. for custom native code integration). |
| 🔤 onNavRouteWillShow
⚛️ OnNavRouteWillShowEvent
📌 OnNavRouteWillShowEventObject
| Gets called just before the navigator shows the route (similar to onRouteWillFocus
event).This event maps to UINavigationControllerDelegate.navigationController(_:willShow:animated:)
. |
| 🔤 onNavRouteDidShow
⚛️ OnNavRouteDidShowEvent
📌 OnNavRouteDidShowEventObject
| Gets called after the navigator shows the route (similar to onRouteDidFocus
event).This event maps to UINavigationControllerDelegate.navigationController(_:didShow:animated:)
. |
| 🔤 onUIConstantsDidChange
⚛️ OnUIConstantsDidChangeEvent
📌 OnUIConstantsDidChangeEventObject
| Gets called whenever the UI-related constants changes (e.g. this event is triggered when the screen rotates, the navigation bar visibility is changed, etc).The event object contains the current safe area values, status bar height, and the navigator frame.💡 Tip: You can also access the UI constants via NavigatorUIConstantsContext
or via the useNavigatorUIConstants
hook. |
NavigatorView
Component: Properties/Methods
NavigatorView
General/Misc. Methods
| Name | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 getActiveRoutes
⚛️ () => Array<NavRouteStackItem>
| Returns an array of NavRouteStackItem
objects that represents the current state of the navigation stack.This method is useful for getting the routeIndex
of a particular route, or for getting the current active routes. |
| 🔤 sendCustomCommandToNative
⚛️ (commandKey: string, commandData: object ¦ null) => Promise<object ¦ null>
| Will trigger the RNINavigatorViewDelegate.didReceiveCustomCommandFromJS
delegate method for the current navigator view instance.This method exists to send custom user-defined commands to the RNINavigatorView
's delegate (i.e. for custom native code integration).📌 Check the native integration guide section for more details. |
| 🔤 getNavigatorConstants
⚛️ () => Promise<NavigatorConstantsObject>
| Resolves to an object containing values related to UI (e.g. navBarHeight
, navigator bounds, safeAreaInsets
, statusBarHeight
), and the current state of the navigator (e.g. whether a view controller is being presented modally, the current activeRoutes
, the current topmost view controller, and the current visible view controller). |
| 🔤 dismissModal
⚛️ (animated: Bool) => Promise<void>
| This will close any modals that are currently being presented. |
NavigatorView
Navigation Commands
Listed in this section are commands that can be called to control the navigator (e.g. like showing or hiding a route, replacing a route in the navigation stack, etc). Unless specified otherwise, the commands listed here are really just invoking UINavigationController.setViewControllers
internally in the native side.
- The navigation commands are asynchronous, and as such, they will return a promise that resolves once the command is completed.
- Due to timing related issues, the
NavigatorView
internally has a command queue, as such, only one command can be executed at a given time. - So for example if you call
push
, then callpop
immediately (i.e. not waiting forpush
to complete first before callingpop
), they will always be executed in that order (i.e. it will always wait for the previous command to complete).
| Name and Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 push
⚛️ (routeItem, options?) => Promise<void>
📌 routeItem: NavRouteItem
📌 options: NavCommandPushOptions
| Push a new route into the navigation stack. The routeItem
to be pushed must be a route that is declared in the NavigatorView.routes
prop. This command maps to the UINavigationController.pushViewController
method.The routeItem
parameter accepts a NavRouteItem
object. Via this object you can define what route to show using the NavRouteItem. routeKey
property. You can also pass data to the new route using the NavRouteItem.routeProps
property, or optionally pass new route options via the NavRouteItem.routeOptions
property.💡 Tip: You can set a temporary push transition (e.g. FadePush
, SlideLeftPush
, etc), or disable the transition animation entirely via the options
parameter. |
| 🔤 pop
⚛️ (options?) => Promise<void>
📌 options: NavCommandPopOptions
| Pop the current active route out of the navigation stack. This command maps to the UINavigationController.popViewController
method.💡 Tip: You can set a temporary pop transition (e.g. FadePop
, SlideLeftPop
, etc.), or disable the transition animations entirely via the options
parameter. |
| 🔤 popToRoot
⚛️ (options?) => Promise<void>
📌 popToRoot: NavCommandPopOptions
| Pop all the routes except the first route in the navigation stack. This can be used as a quick way to go back to the root route.This command maps to the UINavigationController.popToRootViewController
method. |
| 🔤 removeRoute
⚛️ (routeIndex: number, animated?: boolean = false) => Promise<void>
| Removes a specific route from the navigation stack. The argument passed to routeIndex
determines which route to remove from the navigation stack (e.g. a value of 0
means to move the root route, and so on).• 💡 Tip: You can call getActiveRoutes
to get the current state of the navigation stack.• 💡 Tip: This command is useful for situations where in a given route in the navigation stack becomes "stale", i.e. it no longer makes sense to show that route when navigating backwards.• An example could be a user navigating from a "registration" route, to a "registration success" route. If the back button is pressed, it doesn't make sense for the "registration" route to appear again, so you remove it from the navigation stack. |
| 🔤 removeRoutes
⚛️ (routeIndices: number, animated?: boolean = false) => Promise<void>
| Removes the specified routes from the navigation stack. The argument passed to routeIndices
determines which routes to remove from the navigation stack, where a value of 0
means to remove the root route, and so on.This command is similar to removeRoute
, but this lets you remove multiple routes at once.💡 Tip: You can call getActiveRoutes
to get the current state of the navigation stack.💡 Tip: Similar to removeRoute
, this command is useful for selectively removing routes that have gone "stale" all at once. |
| 🔤 replaceRoute
⚛️ (prevRouteIndex: number, routeItem: NavRouteItem, animated?: boolean = false) => Promise<void>
📌 routeItem: NavRouteItem
| Replaces an existing active route in the navigation stack with a new route that matches the specified prevRouteIndex
argument.A new route will be created based on the specified routeItem
provided, and it will then be used as the replacement route. 📝 Note: Just like the push
command, the routeItem
must be a route that is declared in the NavigatorView.routes
prop.💡 Tip: You can call getActiveRoutes
to get the current state of the navigation stack. |
| 🔤 insertRoute
⚛️ (routeItem: NavRouteItem, atIndex: number, animated?: boolean = false) => Promise<void>
📌 routeItem: NavRouteItem
| Similar to the push
command, this lets you create a new route based on the provided routeItem
, and then add it to the navigation stack. But instead of only being able to add routes to the top, this command let's you arbitrarily add a route anywhere in the navigation stack based on the provided atIndex
argument.📝 Note: The routeItem
to be added must be a route that is declared in the NavigatorView.routes
prop, and the atIndex
argument must not exceed the current size of the stack. |
| 🔤 setRoutes
⚛️ (transform: SetRoutesTransformCallback, animated?: boolean = false) => Promise<void>
📌 transform: SetRoutesTransformCallback
📌 NavRouteStackPartialItem
| Allows for the manipulation of the current routes in the navigation stack. Amongst all the navigation commands, this is the most flexible (and complex) because it allows you to add, remove, reorder, replace, or completely change the current active routes in navigation stack.The transform
parameter accepts a function callback that, when called, will receive an array of objects that represents the current active routes in the navigation stack.The transform
callback must then return an array of route objects that will be used to set the new navigation stack (i.e. the new routes that will replace the current active routes).Any of the previous active routes that are not returned from the transform
callback will be removed from the navigation stack, and conversely, any new routes that weren't in the previous active routes will be created, and then added to the navigation stack.📝 Note: The transform
callback will receive an array of NavRouteStackPartialItem
objects that represents the current active routes in the navigation stack. This object has an optional property called routeID
. The number value in the routeID
property is auto-generated internally, and acts as a unique identifier for a route (as such, existing active routes in the navigation stack will have an existing associated routeID
).If the transform
callback returns a NavRouteStackPartialItem
object that does not have a routeID
, then it means that it's a new route (i.e. it will create a new route based on that object, and then add it to the navigation stack).Conversely, in order to "preserve" an active route and let it remain in the navigation stack, then simply return that route's corresponding object from the NavRouteStackPartialItem
items along with its associated routeID
value. 💡 Tip: This command is useful if you need complete control over the navigation stack. Amongst all the other navigation commands, this is the most direct mapping to UINavigationController.setViewControllers
. Jump to the setRoutes
guides section for usage examples. |
| 🔤 setNavigationBarHidden
⚛️ (isHidden: boolean, animated: boolean) => Promise<void>
| Programmatically shows or hides the navigation bar. Maps to the UINavigationController.setNavigationBarHidden
method.💡 Tip: If you want to immediately hide the navigation bar when a route is pushed (i.e. you don't want the navigation bar to be visible when that route is pushed), you can use the RouteOptions.navigationBarVisibility
property instead.The navigationBarVisibility
property can either be set via routeOptionsDefault
(which can be found in the route's config in the NavigatorView.routes
prop), or via the RouteViewPortal
component using the RouteViewPortal.routeOptions
prop.💡 Tip: Like all the other navigation commands, this command is also async. So this command is useful if you want to wait for the navigation bar hide animation to finish first before doing something else. |
NavigatorView
Convenience Navigation Commands
These are basically "presets" to existing navigation commands i.e. it uses the existing navigation commands available to provide shortcuts to common navigation actions for convenience.
| Name and Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 replacePreviousRoute
⚛️ (routeItem: NavRouteItem, animated?: boolean = false) => Promise<void>
📌 routeItem: NavRouteItem
| Replaces the previous route in the navigation stack with a new route. |
| 🔤 replaceCurrentRoute
⚛️ (routeItem: NavRouteItem, animated?: boolean = false) => Promise<void>
📌 routeItem: NavRouteItem
| Replaces the current route (i.e. the topmost route) in the navigation stack with a new route. |
| 🔤 removePreviousRoute
⚛️ (animated?: boolean = false) => Promise<void>
| Removes the previous route in the navigation stack. |
| 🔤 removeAllPrevRoutes
⚛️ (animated?: boolean = false) => Promise<void>
| Removes all of the previous routes in the navigation stack. |
D.1.2. RouteViewPortal
Component
The purpose of this component is to allow for the customization of a route after it's been pushed (e.g. like dynamically overriding/updating a route's RouteOptions
, or rendering custom components to show inside the navigation bar, etc).
📝 Note: The reason why this component has the "portal" suffix is because it's "transporting" things like the route options and the render props somewhere else.
This component is meant to be used inside a route (i.e. it must be used inside the renderRoute
function in the NavigatorView.routes
prop). This is because internally, this component relies on react context to communicate to the parent route container (i.e. NavigatorRouteView
) component.
For some extra background info, the NavigatorRouteView
component is responsible for:
- A. rendering the component returned by
renderRoute
, - B. managing the route's lifecycle, and
- C. communicating with the native views/modules, etc.
As such this component doesn't actually render anything directly, it's merely an intermediate component to pass things along.
- The components you pass to the
RouteViewPortal
are actually being rendered in a different place in the component tree. - Keep this in mind when using things like react context and state (this is a limitation I'm currently trying to fix).
RouteViewPortal
Component: Props
| Prop Name and Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 routeOptions
⚛️ RouteOptions
| This prop will override the existing route options that were provided either from: 1️⃣ the route's "route config" in the NavigatorView.routes
prop (i.e. NavRouteConfigItem.routeOptionsDefault
),2️⃣ the route options provided in the NavigatorView.initialRoutes
prop (i.e. NavRouteItem.routeOptions
), or3️⃣ the route options override provided via a navigation command (e.g. navigation.push({..., routeOptions: {...}})
).📝 Note A: The route options provided via this prop can be potentially be overridden by the navigation.setRouteOptions
command.📝 Note B: Internally, this prop is basically just setting the route options for the current route on your behalf whenever you provide a new value (or when the said value changes).💡 Tip: This prop is useful for dynamically changing the current route options based on some condition.For example, you can change the navigation bar title after loading a resource, or temporarily hide the back button while loading, etc.📌 Related Sections:• RouteOptions
Precedence |
| 🔤 renderNavBarLeftItem
⚛️ (navigation) => ReactElement
| This prop is used for rendering a custom left item component in the navigation bar.If leftItemsSupplementBackButton
in routeOptions
is set to true
(which it is by default), then it will replace the back button (i.e. the back button will not be shown).📝 Note: If this prop is used, it'll implicitly set navBarButtonLeftItemsConfig
to { type: 'CUSTOM' }
for a route's routeOptions
. So if the navBarButtonLeftItemsConfig
is explicitly set to anything other than "custom", then this prop will not do anything. |
| 🔤 renderNavBarRightItem
⚛️ (navigation: NavigationObject) => ReactElement
| This prop is used for rendering a custom right item component in the navigation bar.📝 Note: If this prop is used, it'll implicitly set navBarButtonRightItemsConfig
to { type: 'CUSTOM' }
for a route's routeOptions
. So if the navBarButtonRightItemsConfig
is explicitly set to anything other than "custom", then this prop will not do anything. |
| 🔤 renderNavBarTitleItem
⚛️ (navigation: NavigationObject) => ReactElement
| This prop is used for rendering a custom title item component in the navigation bar.💡 Tip: You can access the route's routeTitle
via the navigation
object (i.e. navigation.routeOptions.routeTitle
). |
| 🔤 renderRouteHeader
⚛️ (navigation: NavigationObject) => ReactElement
| This prop allows you to render a header at the top of the screen (check out NavigatorShowcase01
and NavigatorShowcase02
for examples).This prop accepts a function that must return a RouteHeaderView
as the root element. This component integrates with the route in the native side to enable the header behavior. Check the documentation for RouteHeaderView
for more details. |
RouteViewPortal
Example
- 📌 Declaration:
RouteViewPortalExample01.tsx
// 📝 Note: for the sake of brevity, some of the code is omitted...
export function RouteViewPortalExample01(){
const [index, setIndex] = React.useState(0);
return (
<SafeAreaView style={styles.routeContainer}>
<RouteViewPortal
routeOptions={{
// Change the navigation bar title text
routeTitle: `index: ${index}`,
// Disable large tile
largeTitleDisplayMode: 'never',
// Set the status bar tint to 'white'
statusBarStyle: 'lightContent',
// Customize navigation bar appearance...
navBarAppearanceOverride: {
mode: 'appearance',
useStandardAppearanceAsDefault: true,
standardAppearance: {
// Set the navigation bar tint to red
backgroundColor: Colors.RED.A700,
// Make the back button text white
backButtonAppearance: {
style: 'plain',
normal: {
titleTextAttributes: {
color: 'white',
fontSize: 16,
fontWeight: '600',
},
},
},
// Make the back button icon white
backIndicatorImage: {
type: 'IMAGE_SYSTEM',
imageValue: {
systemName: 'chevron.left',
weight: 'semibold',
},
imageOptions: {
tint: 'white',
renderingMode: 'alwaysOriginal',
},
},
}
},
}}
// Use a custom component for navigation bar title
renderNavBarTitleItem={({routeOptions}) => (
<TouchableOpacity
style={styles.buttonContainer}
onPress={() => {
// Reset the index when pressed
setIndex(0);
}}
>
<Text style={styles.buttonLabel}>
{routeOptions.routeTitle ?? 'N/A'}
</Text>
</TouchableOpacity>
)}
// Use a custom component for navigation bar right item
renderNavBarRightItem={() => (
<View style={styles.navBarLeftItemContainer}>
<TouchableOpacity
style={[styles.buttonContainer, styles.buttonRightSpace]}
onPress={() => {
// Decrement the index when pressed
setIndex(prevIndex => (prevIndex - 1));
}}
>
<Text style={styles.buttonLabel}>
{`--`}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.buttonContainer}
onPress={() => {
// Increment the index when pressed
setIndex(prevIndex => (prevIndex + 1));
}}
>
<Text style={styles.buttonLabel}>
{`++`}
</Text>
</TouchableOpacity>
</View>
)}
/>
<View style={styles.rootContainer}>
<Text style={styles.textTitle}>
{`Current Index: ${index}`}
</Text>
</View>
</SafeAreaView>
);
};
D.1.3. RouteViewEvents
Component
This component allows you to subscribe and listen to the route-related events for the current route (e.g. these events include things like: when a route is about to be pushed or popped, or when a navigation bar item has been pressed, etc).
Similar to the RouteViewPortal
component:
- 1. this component doesn't actually render anything, and
- 2. this component is also required to be used inside a route.
- This is because, like the
RouteViewPortal
component, this component also relies on react context to communicate to the parentNavigatorRouteView
component and receive the route-related events.
- This is because, like the
Internally, every route has an associated event emitter (i.e. a NavigatorRouteViewEventEmitter
instance).
- The "route event emitter" instance, as the name would suggest, emits route-related events. You can use the route event emitter to manually subscribe and listen for events.
- The route's event emitter can be accessed via the route's navigation object (e.g.
NavigationObject.getRefToNavRouteEmitter
). - Internally, this component uses the route's event emitter object to subscribe and listen to the route events.
- 💡 Tip: As an alternative, there's also the
useNavRouteEvents
hook.
Here is a list a list of the event props that this component supports. The various route-related events are documented and explained in the NavigatorRouteViewEvents
section.
- Push/Pop-related Events
onRouteWillPush
onRouteDidPush
onRouteWillPop
onRouteDidPop
- Focus/Blur-related Events
onRouteWillFocus
onRouteDidFocus
onRouteWillBlur
onRouteDidBlur
- Navigation Bar Item-related Events
onPressNavBarLeftItem
onPressNavBarRightItem
- Search Bar-Related Events
onUpdateSearchResults
onSearchBarCancelButtonClicked
onSearchBarSearchButtonClicked
RouteViewEvents
Component Example
import { RouteViewEvents } from 'react-native-ios-navigator';
// Route to show in the navigator
function ExampleRoute(props){
return (
<SafeAreaView>
<RouteViewEvents
onRouteDidPush={({nativeEvent}) => {
console.log(`Route ${nativeEvent.routeKey} was pushed...`);
}}
/>
</SafeAreaView>
);
};
D.1.4. RouteHeaderView
Component
A common UI navigation pattern is having a large header at the very top of the screen that acts as the centerpiece for a route.
- That header will either remain at a fixed size, or expand and collapse during scrolling.
- Check out
NavigatorShowcase01
,NavigatorShowcase02
andNavigatorShowcase03
for some examples.
The navigation bar cannot be easily customized (this is especially true you're trying to change the height).
- As such, this makes things like extending the navigation bar's height to show some custom UI elements underneath the title bar very difficult.
- It's also undesirable to create a custom built solution because the built-in navigation bar has a lot of expected native behaviors/functionality that will be hard to re-create (transitions, the back button, etc).
- To workaround this, some apps (e.g. spotify's album/playlist screen, etc) will just make the navigation bar's background transparent, and then show their custom UI elements underneath it.
- Other apps (like twitter's profile screen) will simply just hide navigation bar entirely, and show their own custom view (you can also do that using this library by pushing a route with
RouteOptions.navigationBarVisibility
).
- Other apps (like twitter's profile screen) will simply just hide navigation bar entirely, and show their own custom view (you can also do that using this library by pushing a route with
This component uses the "transparent navigation bar" approach. When in use, this component is displayed behind the navigation bar, and is anchored to the top of the screen.
- The header can either have a fixed height, or it can be paired with a scroll view so that the header will expand or collapse as the user scrolls.
- In order for your "custom navigation bar" to receive touch events, set
RouteOptions.allowTouchEventsToPassThroughNavigationBar
totrue
.
RouteHeaderView
Component Props
| Prop Name and Type | Description |
| :----------------------------------------------------------- | ----------- |
| 🔤 Required: config
⚛️ RouteHeaderConfig
| TBA |
| 🔤 headerTopPadding
⚛️ HeaderHeightConfig
| TBA |
| 🔤 style
⚛️ ViewStyle
| TBA |
D.2. Context
D.2.1. NavigationContext
TBA
| Name and Type | Description |
| :----------------------------------------------------------- | ----------- |
| 🔤 routeID
⚛️ number
| TBA |
| 🔤 navigatorID
⚛️ number
| TBA |
| 🔤 navigation
⚛️ NavigationObject
| TBA |
D.2.2. NavigatorUIConstantsContext
TBA
| Name and Type | Description |
| :----------------------------------------------------------- | ----------- |
| 🔤 navigatorID
⚛️ number
| TBA |
| 🔤 safeAreaInsets
⚛️ EdgeInsets
| TBA |
| 🔤 statusBarHeight
⚛️ number
| TBA |
| 🔤 navigatorSize
⚛️ Rect
| TBA |
D.3. Hooks
D.3.1. useNavRouteEvents
TBA
D.3.2. useNavigation
TBA
D.3.2. useNavigatorUIConstants
TBA
D.4. Objects and Types
This library is written using typescript. As such, all of the objects/types mentioned in the documentation (and all of the types exported by the library) will have a corresponding type declaration. Those type declaration can usually be found in the src/types
directory. If a particular object is not documented here, please refer to those type declaration files instead.
📄 Object Class: TSEventEmitter
See @dominicstop/ts-event-emitter for documentation.
📄 NavigatorRouteViewEventEmitter.ts
- 📌 Declaration:
NavigatorRouteViewEventEmitter,ts
Type: NavigatorRouteViewEventEmitter
This type represents a route's event emitter that is used to broadcast and listen to route-related events (e.g. route lifecycle, navigation bar-related events, etc). The route event emitter is a TSEventEmitter
object instance that is pre-typed with an event map based on the NavigatorRouteViewEvents
enum.
Enum: `NavigatorRouteViewEvents
NavigatorRouteViewEvents
Push/Pop-related Events
These events are triggered when the current route is about to be pushed or popped from the navigation stack.
| Enum Key and Event Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 onRouteWillPush
⚛️ OnRoutePushEvent
📌 OnRoutePushEventObject
| An event that is triggered when the current route is about to be pushed into the navigation stack (i.e. the push transition has begun). Internally, this event is triggered just before the UINavigationController.pushViewController
method is called. |
| 🔤 onRouteDidPush
⚛️ OnRoutePushEvent
📌 OnRoutePushEventObject
| An event that is triggered when the current route has been pushed into the navigation stack (i.e. the push transition has ended). This event fires after onRouteWillPush
. Internally, this event is triggered inside the completion block of the UINavigationController.pushViewController
method. |
| 🔤 onRouteWillPop
⚛️ OnRoutePopEvent
📌 OnRoutePopEventObject
| An event that is triggered when a route is about to be popped from the navigation stack (i.e. the pop transition has begun). Internally, this event is triggered by the UIViewController.willMove
lifecycle method.💡 Tip: The event.nativeEvent
object has a property called isUserInitiated
. This property specifies whether the pop transition was initiated by the navigation command (false
), or if it was initiated by the user (e.g. via the back button or swipe back gesture) (true
). |
| 🔤 onRouteDidPop
⚛️ OnRoutePopEvent
📌 OnRoutePopEventObject
| An event that is triggered when a route has been popped from the navigation stack (i.e. the pop transition has ended). This event fires after onRouteWillPop
. Internally, this event is triggered by the UIViewController.didMove
lifecycle method.💡 Tip: The event.nativeEvent
object has a property called isUserInitiated
. This property specifies whether the pop transition was initiated by the navigation command (false
), or if it was initiated by the user (e.g. via the back button or swipe back gesture) (true
). |
NavigatorRouteViewEvents
Focus/Blur-related Events
These events are triggered whenever the current route will receive or lose focus (this usually occurs whenever a route is pushed and popped from the navigation stack).
| Enum Key and Event Type | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| 🔤 onRouteWillFocus
⚛️ OnRouteFocusBlurEvent
📌 OnRouteFocusBlurEventObject
| An event that is triggered when the current route is about to become in focus (i.e. the pop transition for the topmost route item has begun).Internally, this event is triggered by the UIViewController.viewWillAppear
lifecycle method.📝 Note: This event will also fire alongside onRouteWillPush
(i.e. when the current route is about to become visible for the first time). |
| 🔤 onRouteDidFocus
⚛️ OnRouteFocusBlurEvent
📌 OnRouteFocusBlurEventObject
| An event that is triggered when the current route has received focus (i.e. the pop transition for the topmost route item has ended).Internally, this event is triggered by the UIViewController.viewDidAppear
lifecycle method.📝 Note: This event will also fire alongside onRouteDidPush
(i.e. when the current route has become visible for the first time). |
| 🔤 onRouteWillBlur
⚛️ OnRouteFocusBlurEvent
📌 OnRouteFocusBlurEventObject
| An event that is triggered when the current route is about to lose focus (i.e. a new route is about to be pushed into the navigation stack).Internally, this event is triggered by the UIViewController.viewWillDisappear
lifecycle method.📝 Note: This event will fire alongside onRouteWillPop
(i.e. when the current route is about to be popped from the navigation stack). |
| 🔤 onRouteDidBlur
⚛️ OnRouteFocusBlurEvent
📌 OnRouteFocusBlurEventObject
| An event that is triggered when the current route has lost focus (i.e. a new route has been pushed into the navigation stack).Internally, this event is triggered by the UIViewController.viewDidDisappear
lifecycle method.📝 Note: This event will fire alongside onRouteDidPop
(i.e. when the current route has been popped from the navigation stack). |
NavigatorRouteViewEvents
Navigation Bar Item-related Events
📝 Note: When using a custom navigation bar items (e.g. renderNavBarLeftItem
, etc.), the onPressNavBar
events will not be triggered.
- Instead, use a button component (e.g.
TouchableOpacity
), and then wrap your custom navigation bar item inside it.
💡 Tip: It's possible to have more than one navigation bar item.
- As such, to differentiate which item is pressed, you can use the properties provided by
event.nativeEvent
object that you'll receive from theOnPressNavBarItemEvent
. - Some of those properties are
nativeEvent.key
(an optional user-defined string), andnativeEvent.index
(the item's placement in the group).
| Enum Key and Event Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 onPressNavBarLeftItem
⚛️ OnPressNavBarItemEvent
📌 OnPressNavBarItemEventObject
| An event that is triggered when a navigation bar left item is pressed. |
| 🔤 onPressNavBarRightItem
⚛️ OnPressNavBarItemEvent
📌 OnPressNavBarItemEventObject
| An event that is triggered when a navigation bar right item is pressed. |
NavigatorRouteViewEvents
Search Bar-Related Events
These events are related to the route's search bar. A route can be configured to have a UISearchBar
in the navigation bar via the RouteOptions.searchBarConfig
property.
| Enum Key and Event Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 onUpdateSearchResults
⚛️ OnUpdateSearchResults
📌 OnUpdateSearchResultsEventObject
| An event that is triggered whenever the search bar's text changes. Internally, this event is triggered by the UISearchResultsUpdating.updateSearchResults
method.💡 Tip: This event is useful for updating a list of results. The event.nativeEvent
object will contain the search bar's current text value. Use the search text value to update the list accordingly. |
| 🔤 onSearchBarCancelButtonClicked
⚛️ OnSearchBarCancelButtonClicked
📌 OnSearchBarCancelButtonClickedEventObject
| An event that is triggered when the search bar's cancel button is pressed. When the cancel button is pressed, the search bar's text field will be cleared (this will trigger onUpdateSearchResults
). Internally, this event is triggered by UISearchBarDelegate.searchBarCancelButtonClicked
method.📝 Note: The search bar's cancel button will only appear when the search bar is in focus (unless specified otherwise via the RouteSearchControllerConfig.automaticallyShowsCancelButton
property in the route's search config). |
| 🔤 onSearchBarSearchButtonClicked
⚛️ onSearchBarSearchButtonClicked
📌 OnSearchBarSearchButtonClickedEventObject
| An event that is triggered when the search button (i.e the return key) is pressed in the iOS keyboard while the search bar is in focus.Internally, this event is triggered by UISearchBarDelegate.searchBarSearchButtonClicked
method.💡 Tip: The keyboard's return key label can modified via the search config (i.e. RouteSearchControllerConfig.returnKeyType
). |
📄 NavRouteConfigItem.ts
- 📌 Declaration:
NavRouteConfigItem.ts
Object Type: NavRouteConfigItem
This type is a union of NavRouteConfigItemJS
and NavRouteConfigItemNative
(i.e. so you can assign either a NavRouteConfigItemJS
object or a NavRouteConfigItemNative
object).
This type is used to configure a route item. For "JS/React" routes, use NavRouteConfigItemJS
, and for native routes use NavRouteConfigItemNative
.
Object Type: NavRouteConfigItemJS
This type is used to create and configure a "JS/React" route.
| Name and Type | Description |
| :----------------------------------------------------------- | ------------------------------------------------------------ |
| 🔤 isNativeRoute?
⚛️ false ¦ undefined
| Used to identify whether the config provided is a "JS/React" route, or a "native" route. This property is optional, you don't have to provide a value.Since this type is used to create "JS/React" route, you can only explicitly set this property to false
or undefined
. |
| 🔤 initialRouteProps?
⚛️ object
| Configures the initial "route props" that the route will receive.📝 Note A: The initialRouteProps
will be merged and potentially overridden by the following:1️⃣ NavigatorView.initialRoutes
prop (i.e. NavRouteItem.routeProps
).2️⃣ Via a navigation command, e.g. push({...routeProps: {...}})
.📝 Note B: The route's "route props" can be accessed via NavigationObject.routeProps
(see "The NavigationObject
" section for examples on how to get the route's navigation object). |
| 🔤 routeOptionsDefault?
⚛️ RouteOptions
| Used to set the initial "route options" that the route will receive.📝 Note: The default route options provided will be merged and potentially overridden by the following:1️⃣ NavigatorView.initialRoutes
prop (i.e. NavRouteItem.routeOptions
).2️⃣ Via a navigation command, e.g. push({...routeOptions: {...}})
.3️⃣ Using the route's NavigationObject.setRouteOptions(...)
command.4️⃣ Or through the RouteViewPortal.routeOptions
prop. |
| 🔤 Required: renderRoute
⚛️ (routeItem: NavRouteItem) => ReactElement<RouteContentProps>
📌 routeItem: NavRouteItem
📌 RouteContentProps
| Configures what component to show when the route becomes active.This property accepts a