在开发weex时,如何较为完美的设置导航栏是我考虑了很久的问题。这篇文章是这2天学习内容的总结,主要包括了3个配置导航栏的方法:
- 整页开发,隐藏导航栏
- 采用weex提供的接口进行设置导航栏
- 在界面push之前,将导航栏的数据传给native进行设置
方法一:整页开发,隐藏导航栏
采用整页开发的方法,将原生自带的导航栏隐藏,然后自己在界面的顶部画一个导航栏,如下图所示:
主要有2个问题
- 如上图所示,采用这种方法时,整个界面会先是白屏,当js下载,解析并渲染成功后,整个界面才会被显示出来,由于导航栏也是在js中实现的,所以整个导航栏也会等到界面渲染后才能呈
现出来。 - 进入第二界面时,会看到第一个界面导航栏隐藏的效果,第一个界面在进行转场动画时,顶部原先导航栏位置会变成白色背景。
方法二: 采用weex提供的接口进行设置导航栏
ps: 由于本人知识限制,暂时先讨论weex在iOS平台的设置,Android会在学习相关知识后补上。
weekSDK的版本是 0.17.0
根据weex的官方文档,采用cocoaPods将WeexSDK导入到项目中后,可以在项目中查看WeexSDK的源码实现。在Weex的源码中,我们可以找到几个和导航栏navigation
有关的类,分别是WXComponent+Navigation
,WXNavigatorModule
,WXNavigationDefaultImpl
,WXNavigationProtocol
这4个文件。
WXNavigationProtocol
主要定义了和导航栏相关的一些接口,包括了导航栏的隐藏,背景颜色,标题等。
WXComponent+Navigation
是组件基类的一个类别,在该类别中实现解析.vue文件中的导航栏设置。在WXComponent+Navigation.m
文件中,可以找到- (void)_setupNavBarWithStyles:(NSMutableDictionary *)styles attributes:(NSMutableDictionary *)attributes
方法,如下图所示。
从代码中可以看出,如果将一个组件的dataRole
设置为navbar
,那么该组件就会被识别为拥有导航栏配置信息的组件,sdk可以从该组件的属性中读取到导航栏的相关配置并进行相应的设置。如下面代码:
<template>
<div dataRole = "navbar" :style="{ backgroundColor: 'black' }"></div>
</template>
// 将导航栏的背景颜色设置为黑色
效果图如下
从代码中可以看出可以直接进行设置的只有style
中的backgroundColor
属性,其他属性都没有找到相关的设置。这是由于weex将其他的一些配置如标题,左边按键,右边按键等都看成一个个item,在.vue中通过实现item的方式来显示导航栏上面的其他组件。
如果你要实现中间的标题,可以通过以下代码实现:
<template>
<div dataRole = "navbar" :style="{ backgroundColor: 'black' }">
<text
naviItemPosition="center"
:style="{ color: 'red' }"
class="center-text" value = "title"></text>
</div>
</template>
这段代码的作用是将导航栏的背景颜色设置为黑色,将导航栏的标题设置为title,颜色为红色。具体效果如下:
图中发现标题的颜色并没有改变,这是由于在weexSDK的WXNavigationDefaultImpl
中,只是读取了标题的内容,并赋值给了navigationItem
的title
,对于标题颜色并没有进行相应的设置
浏览整个WXNavigationDefaultImpl
文件可以发现有个titleView
方法生成了titleView
并设置了字体的颜色,但是该函数并没有被任何对象调用。
WXNavigationDefaultImpl
主要是实现了WXNavigationProtocol
协议的内容。
WXNavigatorModule
主要是暴露一些设置导航栏的接口给js,如何调用native暴露的方法请查看官方文档,暴露的接口如下所示:
WX_EXPORT_METHOD(@selector(open:success:failure:))
WX_EXPORT_METHOD(@selector(close:success:failure:))
WX_EXPORT_METHOD(@selector(push:callback:))
WX_EXPORT_METHOD(@selector(pop:callback:))
WX_EXPORT_METHOD(@selector(setNavBarBackgroundColor:callback:))
WX_EXPORT_METHOD(@selector(setNavBarLeftItem:callback:))
WX_EXPORT_METHOD(@selector(clearNavBarLeftItem:callback:))
WX_EXPORT_METHOD(@selector(setNavBarRightItem:callback:))
WX_EXPORT_METHOD(@selector(clearNavBarRightItem:callback:))
WX_EXPORT_METHOD(@selector(setNavBarMoreItem:callback:))
WX_EXPORT_METHOD(@selector(clearNavBarMoreItem:callback:))
WX_EXPORT_METHOD(@selector(setNavBarTitle:callback:))
WX_EXPORT_METHOD(@selector(clearNavBarTitle:callback:))
WX_EXPORT_METHOD(@selector(setNavBarHidden:callback:))
使用weex提供的接口设置导航栏
weex的官方demo中,有对导航栏的配置进行简单封装,可以较为方便的实现导航栏的设置 传送门
在include
文件夹中还封装了很多常用组件
采用上面的方法对导航栏进行简单的设置,并采用navigator模块进行界面跳转,效果如下:
![lvqr5-gsvqm.gif](http://upload-images.jianshu.io/upload_images/1925310-dad9c6fbd7fdca9a.gif?imageMogr2/auto-orient/stri
如上图片所示,使用weex提供的方法是可以实现导航栏的设置的,会有以下2个问题
- 当push一个新的界面是,是先进入了新的界面,等到js文件被解析后,才会修改导航栏的颜色和标题等属性,虽然进入界面就能看到导航栏,但和系统原生的对比,体验还不是很好。
- 当从view2 返回 view1 时,view1显示的导航栏背景颜色是view2设置的导航栏背景颜色,解决这个问题的办法是在每一个.vue文件界面中监听
viewappear
事件,当界面显示时,重新修改导航栏的颜色。
ps: 如果你的viewcontroller不是继承自WXBaseViewController 那么需要自己在viewcontroler的 viewDidAppear和viewDidDisappear中实现 调用[[WXSDKManager bridgeMgr] fireEvent:_instance.instanceId ref:WX_SDK_ROOT_REF type:@"viewdisappear" params:nil domChanges:nil] 来通知js层
优点
- weexSDK中就实现了相应的接口,我们可以很方便在js层调用相应的方法来使用原生的导航栏,不需要额外工作
方法三:在界面push之前,将导航栏的数据传给native进行设置
如果想在js层能够设置导航栏并且交互体验上接近与原生,那就在每一个界面push出来之前,将导航栏的数据传递给native。实现这个需要以下几个要点:
- 需要自己实现一个跳转模块,可以选择覆盖weex中的
WXNavigationProtocol
协议(可以自己实现WXNavigationProtocol
协议并在注册,只要在调用initSDKEnvironment
方法后面注册就行了),或者是自己实现一个简单的跳转module - 在跳转时,传输下一个界面的导航栏配置参数到native。
- native在下个界面
push
出来之前,先将js传过来的数据进行解析,并对导航栏进行相应的配置。 - native跳转出下个界面
实现跳转模块
这部分网上有很多教程,官方就提供了一个例子
传输导航栏配置信息
- 创建navigationBar相应的数据结构,这个结构可以依照个人的习惯配置,简单的配置可以如下:
{
"View1.js":{
"title":"view1",
"navigationBarTintColor":"white",
"background": {
"color":"#00ff00"
}
},
"view2.js":{
"title":"view2",
"navigationBarTintColor":"white",
"background": {
"color":"#00ff00"
}
}
}
- 根据跳转到的界面路径寻找对应的导航栏配置,并传输到native中
push(path) {
var bundleUrl = weex.config.bundleUrl;
var arr = bundleUrl.split('/')
arr.splice(arr.length-1,1,path)
var totlePath = arr.join('/');
console.log('-------vcnavigationInfos',navigationInfos);
var navigationBarInfo = navigationInfos[path]
var option = {
'url': totlePath,
'navigationBarInfo':navigationBarInfo
}
navigator.openURL(option, event => {
})
}
- native 端接收到配置文件后,进行相应的配置就可以了
- (void)openURL:(NSDictionary *)option callback:(WXModuleCallback)callback
{
NSString *newURL = [option valueForKey:@"url"];
if ([newURL hasPrefix:@"//"]) {
newURL = [NSString stringWithFormat:@"http:%@", newURL];
} else if (![newURL hasPrefix:@"http"]) {
}
NSDictionary *renderInfo = [option valueForKey:@"navigationBarInfo"];
EPBaseViewController *viewController;
viewController = [[EPBaseViewController alloc] initWithRenderInfo:renderInfo];
(viewController).url = [NSURL URLWithString:newURL];
[(QMUINavigationController*)((([UIApplication sharedApplication].keyWindow).rootViewController)) pushViewController:viewController animated:true];
callback(@{@"result":@"success"});
}
实现效果图如下