苦逼前端

react-native-tab-navigator引发的血案

Javascript2015-11-10 18:43

React Native for Android 自从9月15日发布至今已经近两个月了,喜欢折腾的小伙伴们早已做出了不少的例子,当然我们也跃跃欲试了,但过程中踩到一些坑是免不了的。

其中最大的问题,应该是一些组件在iOS平台已经很完善,但Android平台却依然处于todo状态,典型的当属TabBarIOS这个组件,也许这种底部固定tab的UI是iOS风格UI的缘故,名字都起成了iOS结尾...

进入这个组件的目录,通常位于:项目/node_modules/react-native/Libraries/Components/TabBarIOS, 我们会发现四个文件:
TabBarIOS.android.js,
TabBarIOS.ios.js,
TabBarItemIOS.android.js,
TabBarItemIOS.ios.js

以.android.js和.ios.js结尾的文件,分别对应了Android和iOS平台的代码,打开安卓平台的代码,发现里面寥寥的几行,根本无法使用,也就是说,这个功能还处于todo状态...

去官方issue找到这么一条问题:#issue3122
官方开发者astreet的回答发人深醒,android平台和iOS平台本就是风格有很大不同的两个平台,没有必要为了统一UI而去做一些违反平台设计原则的东西,但同时他也相信,会有这种组件出现的:)

但我们的设计师确实是把android和iOS平台的风格设计成基本一样的了,还好官方开发者ide祭出了他为android平台写的一个第三方组件:react-native-tab-navigator

起初并不知道如何安装这个第三方组件,先直接装到项目根目录下的node_modules目录下试试吧:
在项目目录执行npm install react-native-tab-navigator --save, 然后去官方github上找到示例代码,发现组件确实能被正确的引用到,但是报了很多的语法错误,打开这个组件的代码,发现用了两个es7的特性,分别是classpropertiesdecorators

然后去官方issue转了一圈,发现确实有人遇到了类似问题,解决方法是在项目根目录中新建一个.babelrc文件:

{
    "retainLines": true,
    "compact": true,
    "comments": false,
    "whitelist": [
        "es6.modules",
        "es7.classProperties",
        "es7.decorators",
        "regenerator",
        "flow",
        "react",
        "react.displayName"
    ],
    "sourceMaps": false
}

这样react-native在编译打包的时候会对这些es7的语法做兼容处理。然而增加了这个文件后,依然没有解决报错,这时候就有种束手无策的感觉了。根据以往的经验,会不会是代码有更新呢。

赶紧查看下,当前react-native的版本是0.12.0,而官方的stable版本已经发布到了0.14.2,果断更新,然后是漫长的等待,更新就绪后再运行,发现还有报错:

这个报错总算让我看到了希望,因为这表示先前的语法错误都已经解决,这报的是执行阶段的错误啊!看了下代码,发现可能是由于StatusBarIOS这个组件没有引入导致的,先不管它,果断删掉,再运行,终于跑起来了:

示例代码:

'use strict';

let React = require('react-native');
let {
    AppRegistry,
    Image,
    StatusBarIOS,
    StyleSheet,
    Text,
    TouchableOpacity,
    View,
} = React;
let TabNavigator = require('react-native-tab-navigator');

class HiddenTabBarDemo extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            selectedTab: 'home',
            showTabBar: true,
        };
    }

    render() {
        let tabBarStyle = {};
        let sceneStyle = {};
        if (!this.state.showTabBar) {
            tabBarStyle.height = 0;
            tabBarStyle.overflow = 'hidden';
            sceneStyle.paddingBottom = 0;
        }

        return (
        <TabNavigator tabBarStyle={tabBarStyle} sceneStyle={sceneStyle}>
            <TabNavigator.Item
                selected={this.state.selectedTab === 'home'}
                title="Home"
                onPress={() => this.setState({ selectedTab: 'home' })}>
                <View style={styles.scene}>
                    <TouchableOpacity onPress={this._toggleTabBarVisibility.bind(this)}>
                        <Text style={styles.button}>
                            {this.state.showTabBar ? 'Hide Tab Bar' : 'Show Tab Bar'}
                        </Text>
                    </TouchableOpacity>
                </View>
            </TabNavigator.Item>
            <TabNavigator.Item
                selected={this.state.selectedTab === 'profile'}
                title="Profile"
                onPress={() => this.setState({ selectedTab: 'profile' })}>
                <View style={styles.scene}>
                    <Text style={{ color: '#fff' }}>Profile</Text>
                </View>
            </TabNavigator.Item>
        </TabNavigator>
        );
    }

    _toggleTabBarVisibility() {
        this.setState(state => ({
            showTabBar: !state.showTabBar,
        }));
    }
}

let styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
    },
    scene: {
        backgroundColor: '#1e2127',
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    button: {
        color: '#007aff',
        fontWeight: '600',
    }
});

StatusBarIOS.setStyle('light-content');

AppRegistry.registerComponent('main', () => HiddenTabBarDemo);
评论(2)
  • yewei: 我的好像报错了 plication hiddenTabbarDemo has not been registered .this is either due to a require() error during initialization or failure to call AppRegistry.registerComponent4年6个月前
  • 邢文亮: AppRegistry.registerComponent注册应用的名称应该和你react native init的名称保持一致4年6个月前
还可输入200个字