使用react-navigation实现headerRight菜单组件。
日常废话
上一篇文章讲了如何用react-navigation
创建各种自定义头部(header)。
这篇水文讲一下如何实现header右部的菜单项。暂时只支持IOS,原因后文会说明,并给出一些未论证的想法
正文
写的啥?
参考京东商品详情页右上角的交互。
怎么实现
自定义头部右侧很简单,配置navigationOptions
的headerRight
选项,传入我们的自定义组件即可。
const AppNavigator = createStackNavigator(
{
Home: {
screen: Home,
navigationOptions: {
title: '首页'
}
},
GoodDetail: {
screen: GoodDetail,
navigationOptions: ({navigation}) => ({
headerTransparent: true,
headerStyle: {
borderBottomWidth: 0,
},
headerTintColor: '#313131',
shadowOpacity: 0,
headerRight: <HeaderRight navigation={navigation}/>
})
}
}
)
HeaderRight怎么写?分析一哈:
- 样子是"三个点":用图片吧。
- 点它要有反应: 套一个<TouchableOpacity>吧
- 点完展现菜单:自身维护一个状态
isMenuVisible
- 暂时就那么多,先写写看。
class HeaderRight extends Component {
constructor() {
super()
this.state = {
isMenuVisible: false
}
}
toggleMenu = () => {
this.setState((prevState) => {
isMenuVisible: !prevState.isMenuVisible
})
}
render() {
return (
<TouchableOpacity onPress={this.toggleMenu}>
<Image source={require('/path/to/image')}/>
{
isMenuVisible && (
<HeaderMenu
navigation={this.props.navigation}
/>
)
}
</TouchableOpacity>
)
}
}
哦了,HeaderMenu
是一个无状态组件,也就是菜单项,样式根据业务自行写咯~
写完之后好像没什么问题的,但是如果你滚动你的页面(如果你的页面可以滚动),你会发现菜单项不会自己消失。
这怎么行!
解决方法: 我们给HeaderMenu
外层包裹一个View,宽高为容器宽高,绝对定位,使其充满整个屏幕。再在外层包裹一个TouchableWithoutFeedback
,注册onPress
,点击时执行隐藏菜单的函数,而这个函数可以定义在HeaderRight
中,通过props传递给HeaderMenu
为什么只支持IOS
其实我是在写这篇文章的时候才发现,我这个方法只支持IOS(以前用的是另外一个方法)。 究其原因是RN在Android端不支持显示超出父元素部分的内容,用css的话来讲就是overflow: hidden
而且只能是hidden。
这方面的呼声也不低,期待官方能解决吧。
Android下解决方法的设想
将HeaderMenu
部分写在对应的组件中。
在配置HeaderRight时,通过一个闭包保存菜单项的状态。每次点击通过navigation的setParams
API来对指定页面传递这个状态。
这个方法也有缺陷,如果header不是透明的,则菜单项会被header覆盖,就算紧贴header也会略显难看。 以及布局方便需要大改动,并且很麻烦。提一点:菜单项的position是absolute。
采用开源的方案(未验证)
react-native-view-overflow
这是我刚搜到的解决方案,通过包裹一层组件来达到显示超出部分的内容的效果。
import ViewOverflow from 'react-native-view-overflow';
<ViewOverflow>
<ComponentToEnableOverflow />
</ViewOverflow>
在我们这个情景下,就要改写默认的header组件,小伙伴可以自行尝试。(丢链接就跑,真刺激)
结尾
源代码可以在GitHub上看到。
效果图:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。