想象一下,你是一名房企老板,你已经得到审批可以建设你自己的大厦了,工程人员和设计人员他们决定使用React-Native这种方式来建设这座大厦。
而你,作为一个懂技术懂设计的老板,你让你雇佣的设计师和工程师们给你介绍一下,他们准备如何使用React-Native这种方式建设大厦,大厦的结构是怎么样的,楼层之间是如何联通的等等。
这次,负责给各位老板讲解的建筑工程师,就是我。
声明
首先声明,我们使用React-Native的主要目的还是在iOS和Android的地基上盖大厦,web我们暂且不考虑。
大厦入口
每座优秀的大楼,肯定都有自己不同凡响的门面,那这次这个项目呢,我们使用React-Native方式来设计打造我们的入口。
首先,在package.json
中,我们可以配置入口文件。如下面的配置显示,我们选择expo/AppEntry.js
中提供的默认方式。
{ "main": "node_modules/expo/AppEntry.js",}
在它之中,它默认去注册了这个文件../../App
中的控件。
import registerRootComponent from 'expo/build/launch/registerRootComponent';
import App from '../../App';
registerRootComponent(App);
所以,真正的大门,我们要App中实现。
然而,各位老板如果有别的需求,我们也可以不在package.json
中配置,而在根目录下面建立index
入口文件,注册自己想要的控件。
import { AppRegistry, LogBox } from 'react-native';
LogBox.ignoreAllLogs(true);
AppRegistry.registerComponent('BossGate', () => require('./BossApp').default);
AppRegistry.registerComponent('EmployeGate', () => require('./EmployeApp').default);
当然,想保持神秘感的老板们可能并不想和自己的员工们使用同一个入口,应对这种需求,我们打算除了员工入口,给各位老板们单独开辟一个大门,更气派,更私密,更符合你的身份。
大厦基础结构
想象一下,你已经通过你自己私密恢弘的大门,进入到了大厦内部了。
接下来我要为各位老板介绍一下我们整个大厦的基础结构。
这个大厦基础结构,我们使用一个业界通用方案来解决,各位老板请放心,它非常可靠和稳定。
github地址: react-navigation
接下来我们一层层进行介绍。
const App = () => (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="HomeScreen"
component={HomeScreen}/>
<Stack.Screen name="DetailsScreen"
component={DetailsScreen}
options={{ headerShown: false }} />
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="WebViewPage"
component={WebViewPage}
options={{ statusBarStyle: STATUS_BAR_STYLE }}/>
</Stack.Group>
</Stack.Navigator>
</NavigationContainer>
);
NavigationContainer
这个是我们大厦的最外层结构,就像鸡蛋壳一样包裹着大厦内部所有组件。
有了它,我们可以管理我们的大厦,也就是APP中导航的各个状态,并且可以给内部各个组件提供导航的上下文。
function NavigationContainerInner(
{
theme = DefaultTheme,
linking,
fallback = null,
documentTitle,
onReady,
...rest
}: Props<ParamListBase>,
ref?: React.Ref<NavigationContainerRef<ParamListBase> | null>
)
从它的方法定义中可以看出,NavigationContainer
作为最外部的壳,可以处理主题,路由配置,web页面的标题以及当前整个大厦的状态等。
例如,现在我们的大厦是一个默认主题,比较清冷,各位老板可以根据自己的喜好调整我们大厦的主题色,文本颜色等等,就算是猛男粉也行。
并且我们可以在大厅就给大厦放一个整个大厦的地图linking
, 将来用来指导员工,如何从一个房间/楼层到另一个房间/楼层。
Navigator
再次进入大厦内部,我们会有各个楼层,有的老板喜欢打球,弄个一层的只用来打篮球,有的老板喜欢唱歌,那我们就把这一层都整成KTV。
各位老板浸淫建筑行业这么多年,相信大家也都了解,我们业界有一些基本的楼层组织方式,主要有以下几种:
→ Stack(createStackNavigator)
相信各位老板对于这种方式最熟悉。
image.png页面和页面之间使用栈的方式组织起来,从一个页面跳到下一个页面,然后可以一层一层返回到上一个页面。
想象一下,你作为一个财大气粗的老板,想不想拥有一个走也走不到尽头的大套间???
唯一的缺点就是,入口只有一个,你的卧室要是在最里面,早上想出门就只能再穿过一个一个房间出去。
不过这不妨碍你的内心就像这个栈一样深邃。
在实际施工当中,我们可能不会用到createStackNavigator
, 而是使用createNativeStackNavigator
。
createStackNavigator
使用的是 React Navigation 提供的默认堆栈导航器组件。它基于 JavaScript 实现,适用于多平台,包括 iOS、Android 和 Web。它提供了丰富的配置选项和功能,可以满足大多数应用的需求。但是缺点是在某些特定场景下性能稍低于原生导航器,我相信各位老板不想在穿越房间的时候有卡顿或者不够丝滑吧。
而createNativeStackNavigator
是针对原生平台的堆栈导航器组件。它基于原生导航器实现,保留原生的一些交互方面,性能也更加优秀。让你丝滑的穿越各个房间,还有漂亮的原生的过渡动画。
但是也有一丝丝缺点,就是定制化稍微差了点,并且因为需要根据不同地基,单独进行一些配置。
→ Tab-bar(createBottomTabNavigator)
话说回来,各位老板如此优秀,就算是如此深邃的心灵,你可能也想七窍玲珑,你说你想要七个这样的大套间?没问题,安排。 使用Tabbar,或者叫做BottomBar,我们给你建了一条走廊,走廊上并排把你的套间们都排列开,让你随意进入任何一个。
image.png→ Drawer(createDrawerNavigator)
当然,我们也知道,整整一层的超大套件,怎么可能就轻易满足各位老板的野心呢? 我当然知道你需要一部电梯,但是电梯还需要花费时间到达每一层,不够酷炫,我们直接上虫洞!让你轻松瞬间到达每一层! 为了掩饰我们已经达到了物理前沿,我们只能将这种技术起一个接地气的名字 —- 抽屉。
image.png→ Top-bar(createMaterialTopTabNavigator)
看样子我们已经解决了大部分酷炫的出行需求,可是我们忘了一点,在套间内部呢??? 我们难道真的会让老板们一层层从套件中走出来吗?
image.png当然不,我们决定,将套间中的房间进行功能区拆分,在一个大房间里,你就可以拥有客厅,卧室,洗手间,满足你的一切需求。 所以,我们使用Top-bar,或者也叫Page-view, 让你直接拥有一整个独立的功能区,并且利用这个通道,你能够快速到达你想去的房间。无论是滑(划动)过去,还是穿越(点)过去。
→ 配置
export declare type DefaultNavigatorOptions<ParamList extends ParamListBase, State extends NavigationState, ScreenOptions extends {}, EventMap extends EventMapBase> = DefaultRouterOptions<Keyof<ParamList>> & {
/**
* Optional ID for the navigator. Can be used with `navigation.getParent(id)` to refer to a parent.
*/
id?: string;
/**
* Children React Elements to extract the route configuration from.
* Only `Screen`, `Group` and `React.Fragment` are supported as children.
*/
children: React.ReactNode;
/**
* Event listeners for all the screens in the navigator.
*/
screenListeners?: ScreenListeners<State, EventMap> | ((props: {
route: RouteProp<ParamList>;
navigation: any;
}) => ScreenListeners<State, EventMap>);
/**
* Default options for all screens under this navigator.
*/
screenOptions?: ScreenOptions | ((props: {
route: RouteProp<ParamList>;
navigation: any;
}) => ScreenOptions);
};
这一层中有很多房间,我们可以用initialRouteName
设置楼层的初始房间是哪个;
也可以用screenOptions
来给这一层所有的房间,统一改变一下样式,例如:
1. title:设置屏幕的标题。
2. headerShown:控制是否显示导航栏。设置为false将隐藏导航栏。
3. headerStyle:设置导航栏的样式,如背景色、阴影等。
4. headerTitleStyle:设置导航栏标题的样式,如字体大小、颜色等。
5. headerTintColor:设置导航栏标题和图标的颜色。
6. headerTitleAlign:设置导航栏标题的对齐方式。
7. headerLeft和headerRight:自定义导航栏左侧和右侧的组件。
8. headerBackTitle和headerBackTitleVisible:设置返回按钮的标题和可见性。
9. headerBackImage:自定义返回按钮的图标。
10. cardStyle:设置屏幕的过渡效果和样式。
11. gestureEnabled:控制手势返回是否可用。
12. tabBarVisible:在标签导航器中,控制底部标签栏的可见性。
13. tabBarIcon:设置标签栏图标的显示。
等等
或者用screenListeners来在走廊中放置一些监控设备,来看看你的员工们有没有进入房间,是否有破坏房间。
Screen
各位老板现在已经知道我们大概会有哪些类型的楼层了,那么我们接下来介绍介绍房间里面。
每一个房间都是一个Screen,此处各位老板可以发挥自己的想象力,怎样的房间都行,无论是奥特曼主题还是兵马俑主题,无论是充满泡泡糖的房间,还是中间只有一盒巧克力的房间都行。
只需要给房间起个响亮的名字,然后把设计图交给我,再加点你的私人需求,一切皆可满足。
<Stack.Screen name="Root" component={Root} options={{ headerShown: false }}/>
甚至,是另一个楼层!以此,我们的大厦完成了进化,可以成为堪比重庆的4D城市!就像下面这样。
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Messages" component={Messages} />
</Tab.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
);
}
Group
老板们雇员一定很多,部门也很多,那这么多房间,我们当然也有办法将他们分门别类一下进行管理。
万一哪天老板大笔一挥,给技术部门分配上十个办公室,两个专门用来电竞!
此时,我们可以使用Group, 然后把这十个办公室不小心都变成了电竞室。😝
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Help" component={Help} />
<Stack.Screen name="Invite" component={Invite} />
</Stack.Group>
大厦内部出行方式
作为一名优秀的设计师,为了让老板们过的舒适,怎么能让老板自己走路呢?
首先,相信大家目前都能理解,我们整个大厦的内部结构,会使用各种navigator
和screen
进行不断地嵌套,进行构建。
并且每个navigator
和screen
都会有自己的名称,所以一旦老板们进入大厦,乘坐我们的Navigation,我们就能让你去到任何你想去的房间或者楼层。
那就是路由机制!Route
有了地址后,那我们的出行方式会有哪些呢?
Navigate
navigation.navigate(name, params)
这里,我们再次用上前沿科技!我们可以直接使用房间名称,从一个房间穿梭到另一个房间或者另一个楼层。
虽然,中间穿梭的过程只在一瞬间,但是实际上,在iOS和Android内部,系统帮我们做了很多页面生命周期的管理工作。
并且,相比于iOS或者Android原生都会更加方便。
比如,有一个经典的场景是这样,我们从帖子列表进入了帖子详情页正在看帖子,但是突然来了消息,此时,点击消息我们需要进入到消息聊天页面,但是退出的时候,需求是回到消息列表页。帖子列表位于第一个Tab, 消息列表位于第二个Tab。
如果是iOS传统开发,我们需要做的是,先从帖子详情退出到帖子列表,然后切换Tab到第二个,即消息列表,然后再进入到消息详情页。
但是在RN中,我们无需这么麻烦,只要一开始定义好这些页面的嵌套关系,再调用navigate
方法,系统会帮助我们处理这复杂的中间关系,页面之间的关系会自动遵循我们在定义中写的那样。
Modal
另外,我们也可以设置一下这个房间或者楼层的进入方式是Modal方式。
此方式也是一枚黑科技 — — 多次元!
想象一下,在这个房间或者楼层之上直接开辟另一个次元,进入其中,退出的时候,可以直接退出这整个次元,回到之前次元的房间中。
<NavigationContainer>
<StatusBar style="auto" />
<RootStack.Navigator initialRouteName="TabBar" screenOptions={{headerShown: false}}>
<RootStack.Screen
name="TabBar"
component={TabBar}/>
<RootStack.Screen
name="Post"
component={PostStack}
options={{presentation: 'fullScreenModal'}}/>
</RootStack.Navigator>
</NavigationContainer>
image.png
Replace — — Stack
navigation.replace(name, params)
设想一下,你现在大套间中,但是你正身处于其中的一个房间,他是一个很low的标间,不符合你的身份,你想换一个总统套房,而你作为老板,我们不会让你挪动一丝一毫的,我们让宇宙为你而变!
我们会直接干掉这个标间,用一个总统套房替换它!你可能会永远失去这个标间,但是这个房间已经为你变成总统套房啦!
replace
方法用于替换当前页面,并打开一个新的页面。使用 replace
方法后,当前页面将被销毁,同时新的页面将成为导航堆栈中的最新页面。
Reset — — Stack
navigation.reset(state)
和replace
相似,你可能根本连这一整个无限套间都不喜欢,没关系,我们直接使用reset
方法,清空这整个套间中的所有房间,然后把他变成一个超级大平层总统套房。
reset
方法用于重置导航堆栈。使用 reset
方法后,我们可以将整个堆栈的状态完全重置为新的状态。
Push — — Stack
navigation.push(name, params)
push
方法和navigate
方法类似,但是navigate
方法会自动管理之前的路由状态,如果要去的页面已经在堆栈中,他会直接返回到那个页面,而push
会忽略,所以使用push
方法可以使同一个页面进入多次,每次都生成一个新的,然后放在堆栈的最上层。
Pop — — Stack
navigation.pop(count)
pop
方法 帮助我们返回到堆栈中的上一个页面,我们可以自定义返回到第几个页面。
PopToTop — — Stack
navigation.popToTop()
popToTop
方法会直接让我们返回堆栈的第一个页面,即带我们回到套间的第一个房间中。
JumpTo — — BottomBar/TopBar/Drawer
navigation.jumpTo(name, params)
jumpTo
方法 可以帮助我们在BottomBar/TopBar/Drawer这几种楼层中,直接到达任何一个在楼层下面的房间。
goBack
navigation.goBack()
我们进入房间时,都会留有历史记录,而goBack
方法会帮助我们直接放回历史记录中的上一个房间或楼层,非常方便。
Deep linking
介绍到这里,相信各位老板已经胸有成竹,已经了解自己大厦中的各种特性了。
但是,我也知道,老板们交友广泛,难免会有些朋友要来造访,没有一份地图给这些尊贵的客人作为导航怎么行?
所以,为了应对这种情况,我们在大厅中,也会给外来访客放置一份地图,各位老板可以自己决定在地图上标识哪些房间和楼层,除此以外的房间当然只对内部开放喽。
这个地图,我们叫做Deep linking!
首先我们的大厦得在这城市当中有个名字,让客人方便找到:
const linking = {
prefixes: ['mychat://', 'https://mychat.com', 'https://*.mychat.com'],
};
加入我们现在想让客人去到W06会议室。我们可以如下设置:
const config = {
screens: {
Home: {
screens: {
Room: 'rooms/:name',
},
},
Profile: 'user',
},
};
我们把这份地图放到大厅当中,客人就可以通过mychat://rooms?name=W06
直接进入到W06会议室啦。
import { NavigationContainer } from '@react-navigation/native';
const config = {
screens: {
Home: {
screens: {
Room: 'rooms/:name',
},
},
Profile: 'user',
},
};
const linking = {
prefixes: ['mychat://', 'https://mychat.com', 'https://*.mychat.com'],
config,
};
function App() {
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
{/* content */}
</NavigationContainer>
);
}
rooms/:name
会帮我们找到Home/Room这Screen,然后传递过去name=W06这个参数。
结语
对于客户端来说,导航实际上是一个非常庞杂的系统功能,React Navigation的官网对于各个模块的介绍也都非常详尽。
我希望通过一个故事场景,然后用建筑结构来进行类比,能够把这些庞杂的功能串起来,让大家更加清晰的了解,这些设计的初衷和应用场景都是怎样的。可能针对代码和API的部分不够多,但是这部分官方文档其实更加详细,这里再写就有些赘述。
当然,可能有些地方类比的不是那么合适,大家有任何不明白的地方,希望能够与我一起讨论,可能会有新的理解产生,更好地服务于用户交互和业务。
Reference: https://reactnavigation.org
网友评论