react_native 项目实战 (3) 使用导航页面跳转 (ReactNaviation 完全自定义导航)


其他的一些问题 记录下

什么时候 要给函数加上括号:

加括号情况: 当函数需要立即执行的时候(需要立刻返回)

不加括号情况: 当事件需要延迟触发的时候. (比如点击事件的函数)

    static propTypes = {
    
    }

 static defaultProps = {
        
    }
    
propTypes 是用于传入类型的校验

defaultProps 是给props 设置默认的值

https://segmentfault.com/a/1190000007814801

http://blog.csdn.net/vispin/article/details/53002586


先来一张这次写的最终的效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TP0ibAK6-1585128114072)(http://ovji4jgcd.bkt.clouddn.com/blog/170927/9A4d9h6K4f.gif)]



分析下布局,我的页面,首先顶部是一个导航栏 我的 , 这个导航栏可以复用之前写的NavigationBar.js,

但是之前的文字是写死的,右边的控件也是写死的,现在需要把文字和右边的控件作为属性传过去

因为顶部控件是通用的 把他抽取出来

我敲下面的代码的时候

遇到的问题.

1,render() 没有 写 return 直接写了一个View 我一直在找这个问题 巨痛苦

2,出现PropTypes is not defined . 原来PropTypes这个东西 需要引入,和Compoent一起引入
在这里记录下

动态传递控件 顶部控件

再分析下 顶部导航栏是由三部分组成 左边视图 中间标题 右边视图

,那么我在NavigationBar里面接收从其他页面传递过来的组件就可以实现
顶部控件是动态的了.

那么现在先改造NavigationBar

/**
 * Created by liuml on 2017/9/11.
 */
import React, {Component, PropTypes} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    StatusBar,
    Platform,
    Image,
    TouchableOpacity
} from 'react-native';

export default class NavigationBar extends Component {

    static propTypes = {
        //验证,不传element组件类型,会报错提示
        rightButton: PropTypes.element,
        leftButton: PropTypes.element
    }

    render() {
        return <View style={styles.container}>
            <View style={styles.container}>
                <StatusBar hidden={false} barStyle="light-content"/>
            </View>
            {/*顶部导航栏*/}
            <View style={styles.navBar}>
                <View style={styles.leftBtnStyle}>
                    {this.props.leftButton}
                </View>
                <View style={styles.titleWrapper}>
                    <Text style={styles.title}>{this.props.title}</Text>
                </View>
                <View style={styles.rightBar}>
                    {this.props.rightButton}
                </View>

            </View>
        </View>
    }
}
const styles = StyleSheet.create({

    container: {
        backgroundColor: '#63B8FF',
    },
    statusBar: {
        height: Platform.OS === 'ios' ? 20 : 0
    },
    navBar: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        alignItems: 'center',

    },
    titleWrapper: {
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
        position: 'absolute',
        left: 40,
        right: 40,
    },
    title: {
        fontSize: 16,
        color: '#FFF'
    },
    navBtn: {
        width: 24,
        height: 24
    },
    rightBar: {
        flexDirection: 'row',
        alignItems: 'center',
        paddingRight: 8
    },
    leftBtnStyle: {
        flexDirection: 'row',
        alignItems: 'center',
        height: 24
    },
});


可以看到关键的几行代码

   static propTypes = {
        //验证,不传element组件类型,会报错提示
        rightButton: PropTypes.element,
        leftButton: PropTypes.element
    }

这是用于校验传入的左边的和右边的 是不是一个节点

  {/*顶部导航栏*/}
            <View style={styles.navBar}>
                <View style={styles.leftBtnStyle}>
                    {this.props.leftButton}
                </View>
                <View style={styles.titleWrapper}>
                    <Text style={styles.title}>{this.props.title}</Text>
                </View>
                <View style={styles.rightBar}>
                    {this.props.rightButton}
                </View>

            </View>
            

这是给顶部导航栏设置左边中间和右边的控件 通过props传递

然后在PapularPage 里面创建标题栏 右边的控件

/**
 * Created by liuml on 2017/9/11.
 */

import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    Image,
    ListView,
    RefreshControl,
    TouchableOpacity
}from 'react-native';

import NavigationBar from "../compoent/NavigationBar.js"
import ScrollableTabView from "react-native-scrollable-tab-view"
import ProjectRow from "../compoent/ProjectRow"

export default class PapularPage extends Component {


    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            languages: ["Android", "Ios", "Java", "React", "JS"]
        };
    }

    getRightBtn = () => {
        return <View style={{flexDirection: 'row', alignItems: 'center'}}>
            <TouchableOpacity activeOpacity={0.7}>
                <Image source={require('../../res/images/ic_search_white_48pt.png')}
                       style={{width:24,height:24}}></Image>
            </TouchableOpacity>
            <TouchableOpacity activeOpacity={0.7}>
                <Image source={require('../../res/images/ic_more_vert_white_48pt.png')}
                       style={{width:24,height:24}}></Image>
            </TouchableOpacity>
        </View>
    }

    render() {
        return <View style={styles.container}>
            <NavigationBar
                rightButton={this.getRightBtn()}
                title="热门"/>
            <ScrollableTabView
                tabBarBackgroundColor="#63B8FF"
                tabBarActiveTextColor="#FFF"
                tabBarInactiveTextColor="#F5FFFA"
                tabBarUnderlineStyle={{backgroundColor: "#E7E7E7", height: 2}}>
                {
                    this.state.languages.map((item, i) => {
                        return <PopularTab key={`tab${i}`} tabLabel={item}/>
                    })
                }
            </ScrollableTabView>
        </View>
    }
}

class PopularTab extends Component {

    //这里是Tab 的名字
    static defaultProps = {
        tabLabel: 'android',
    }
    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),//是一个优化,节省无用的UI渲染 判断前后数据是否改变 如果改变就更新
            isLoading: true
        };
    }

    /*componentDidMount() {
     /!*this.setState({
     dataSource: this.state.dataSource.cloneWithRows(['first', 'second', 'three'])
     }
     )*!/
     this.loadData();
     };*/

    //和上面一样的效果
    componentDidMount = () => {
        this.loadData();
    }

    //渲染ListView的每一行
    renderRow = (obj) => {
        return <ProjectRow item={obj}></ProjectRow>
        // return <Text>{obj.full_name}</Text>
    }


    //加载数据
    loadData = () => {
        this.setState({isLoading: true});
        fetch(`https://api.github.com/search/repositories?q=${this.props.tabLabel}&sort=stars`)
            .then(response => response.json()) //服务器响应response对象,继续变成json对象
            .then(json => {
                //更新dataSource
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(json.items),
                    isLoading: false,
                });
            })
            .catch((error) => {
                console.error(error);
            }).done();
    }

    handleRefresh = () => {
        this.loadData();
    }

    render() {
        return <View style={styles.container}>
            <ListView
                dataSource={this.state.dataSource}
                renderRow={this.renderRow}
                refreshControl={
                    <RefreshControl
                        refreshing={this.state.isLoading}
                        tintColor="#63B8FF"
                        title="正在加载..."
                        titleColor="#63B8FF"
                        colors={['#63B8FF']}
                    />
                }
            ></ListView>
        </View>
    }
}


const styles = StyleSheet.create({
    container: {
        flex: 1
    }
});

最后的做完的效果图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HefCyXVj-1585128114073)(http://ovji4jgcd.bkt.clouddn.com/blog/170917/1G94FmH0F2.gif)]

总结下我这里做了什么:

  • 把导航栏抽取出来了,让每个页面的导航栏作为props

使用导航跳转页面

https://reactnavigation.org/docs/intro/

这里是英文文档.

使用步骤 npm install --save react-navigation

需要先引入这个 react-navigation

可以看到英文文档有三个导航器 那么我这里只需要用到其中一个StackNavigator 堆导航 类似android的activity栈

具体看下我的另一篇blog http://blog.csdn.net/liudao7994/article/details/78033299

写的是基础 使用 我这里需要使用自定义的导航

看过文章后应该知道需要把所有的跳转页面在一个js里面定义一次, 如果想使用自定义的导航那么需要把navigation
每个页面都传递让每个页面都持有naviagation.这样才能进行页面的跳转

下面说下我是怎么操作的

  1. 首先因为ios 和android 的index.js 的文件内容都差不多那么就把相同的部分抽取出来 抽取成一个Setup.js,然后在index.android.js 和index.ios.js里面调用
  2. 在Setup.js中 使用ReactNaviation ,使用这个导航器 需要把所有需要跳转的页面在这里定义

下面上代码

这里是index.android.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    Image
} from 'react-native';

import SetUp from './js/pages/Setup';
export default class MyApp extends Component {
    render() {
        return (
            <SetUp/>
        );
    }
}
AppRegistry.registerComponent('testP', () => MyApp);

这是Setup.js 注意在所有的ReactNative中的控件首字母必须大写.不然会出错

/**
 * Created by liuml on 2017/9/17.
 */

import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    Platform
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Homepage from "./HomePage";
import MyPage from "../my/MyPage";
import CustomKeyPage from "../my/CustomKeyPage";

//各个页面路由配置
const RouteConfigs = {
    Home: {//首页
        screen: Homepage,
    },
    MyPage: {//我的
        screen: MyPage,
    },
    CustomKeyPage: {//自定义分类
        screen: CustomKeyPage,
    },
}

//导航器的配置,包括导航器的初始页面、各个页面之间导航的动画、页面的配置选项等等
const NavigatorConfig = {
    initialRouteName: 'Home', // 默认显示界面
    headerMode: 'none',//https://reactnavigation.org/docs/navigators/stack#StackNavigatorConfig

}

//导航注册
const RootNavigator = StackNavigator(RouteConfigs, NavigatorConfig);
export default RootNavigator;

这里需要解释下StackNavigator 是用于跳转的导航 在他的配置中 如果没有

headerMode: ‘none’ 参数会有自己默认的导航条 这里的意思就是隐藏默认的导航条

还有一些其他的参数看下我的注释和我之前写的一篇文章http://blog.csdn.net/liudao7994/article/details/78033299 就应该明白了

自定义ReactNativiation跳转

我现在需要做的是在<我的>页面进行跳转 ,跳转到<自定义分类>页面.

上代码

/**
 * Created by liuml on 2017/9/16.
 */
import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    Image,
    ListView,
    RefreshControl
}from 'react-native';

import  NavigationBar from "../compoent/NavigationBar";
/**
 * 我的页面
 */
export default class MyPage extends Component {


    //navigation 里的方法有navigate 是用于页面跳转 goBack是用于页面返回
    render() {
        const navigation = this.props.navigation.navigate;
        return <View style={styles.container}>
            <NavigationBar
                title="我的"/>
            <View style={{flexDirection: 'column', alignItems: 'center', marginTop: 30}}>
                <Text onPress={() => {
                    navigation('CustomKeyPage', {source: '自定义分类'});
                }}>自定义分类</Text>
            </View>
        </View>
    }
}

const styles = StyleSheet.create({

    container: {
        flex: 1
    }
})

可以看到我使用navigation 进行跳转 注意这个navigation 是从HomePage.js初始的

时候就有的,我把这个navigation 从HomePage传到了这个MyPage.js 页面 下面是传递的代码

因为HomePage.js 只改了传递参数的代码 我就只截取这一点代码 我参数传递是通过

es6语法 遍历传递的 三个点表示每一个参数一个个的传过去


                <TabNavigator.Item
                    selected={this.state.selectedTab === 'my'}
                    slectedTitleStyle={{color: '#0F0'}}
                    renderIcon={() => <Image style={styles.icon}
                                             source={require('../../res/images/ic_my.png')}/>}
                    renderSelectedIcon={() =>
                        <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                               source={require('../../res/images/ic_my.png')}/>}
                    onPress={() => this.setState({selectedTab: 'my'})}
                    title="我的">

                    <MyPage {...this.props}/>
                </TabNavigator.Item>

可以看到主要就是这个代码起作用

  <MyPage {...this.props}/>

-自定义分类页面

/**
 * Created by liuml on 2017/9/17.
 */
import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    Image,
    TouchableOpacity
} from 'react-native';
/**
 * 自定义分类页面
 */
import NavigationBar from '../compoent/NavigationBar'

export default class CustomKeyPage extends Component {

    handleBack = () => {
        this.props.navigation.goBack();
    }
    getLeftBtn = () => {
        return <View style={{flexDirection: 'row', alignItems: 'center'}}>
            <TouchableOpacity
                activeOpacity={0.7}
                onPress={this.handleBack}>
                <Image source={require('../../res/images/ic_arrow_back_white_36pt.png')}
                       style={{width: 24, height: 24}}/>
            </TouchableOpacity>
        </View>;
    }

    getRightBtn = () => {
        return <View style={{flexDirection: 'row', alignItems: 'center'}}>
            <TouchableOpacity activeOpacity={0.7}>
                <View style={{marginRight: 10}}>
                    <Text style={{fontsize: 16, color: '#FFF'}}>保存</Text>
                </View>
            </TouchableOpacity>
        </View>
    }

    render() {

        return <View style={styles.container}>
            <NavigationBar
                title="自定义分类"
                rightButton={this.getRightBtn()}
                leftButton={this.getLeftBtn()}/>
            <Text onPress={() => {
                this.handleBack();
            }}>CustomKeyPage</Text>
        </View>
    }
}

const styles = StyleSheet.create({

    container: {
        flex: 1
    },

});

注意我这里是怎么返回的

this.props.navigation.goBack();

navigation有goBack()方法 点击箭头后调用 下面来一张最终的效果图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fzpJEDfr-1585128110113)(http://ws2.sinaimg.cn/large/958c5b69ly1fwns7mhn62g20jm0noq7d.gif)]

github 地址 还没写完会继续更新

https://github.com/liudao01/ReactNativeProject

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值