React_Native 项目实战 (1) (首页,以及页面的切换)

写一个用reactnative 的项目 可以用于查看GitHub最受欢迎与最热项目的App。

https://github.com/liudao01/ReactNativeProject

github地址 还在更新中

项目开始 HomePage.js

PS 可以先拖动到底部看下效果图

新建一个reactnative项目 ,

底部因为有四个tab 选项卡 那么 我使用一个第三方组件react-native-tab-navigator

并且新建一个HomePage.js,关于第三方组件可以看下这篇文章 http://blog.csdn.net/true100/article/details/68066649

这里单独说下 npm install react-native-tab-navigator --save 后面这个–save 这个的作用是用户把这个库加入到package.json中去.

在Homepage.js里面 使用react-native-tab-navigatior

这是 index.android.js

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

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


import Homepage from "./js/pages/HomePage";
export default class testP extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Homepage/>
      </View>
    );
  }
}

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

AppRegistry.registerComponent('testP', () => testP);

这是 Hmepage.js

/**
 * Created by liuml on 2017/9/8.
 */
import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    Image
} from 'react-native';
import TabNavigator from 'react-native-tab-navigator';
import TabNavigatorItem from "react-native-tab-navigator/TabNavigatorItem";

export default class Homepage extends Component {

    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {selectedTab: 'papular'};
    }


    render() {

        return <View style={styles.container}>
            <TabNavigator>
                <TabNavigator.Item
                    selected={this.state.selectedTab === 'papular'}
                    title="最热"
                    slectedTitleStyle={{color: '#FFF'}}
                    renderIcon={() => <Image style={styles.icon}
                                             source={require('../../res/images/ic_popular.png')}></Image>}
                    renderSelectedIcon={() =>
                        <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                               source={require('../../res/images/ic_popular.png')}/>}
                    onPress={() => this.setState({selectedTab: 'papular'})}>

                    <View style={{backgroundColor: '#FF0', flex: 1}}/>
                </TabNavigator.Item>

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

                    <View style={{backgroundColor: '#0F0', flex: 1}}/>
                </TabNavigator.Item>

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

                    <View style={{backgroundColor: '#0FF', flex: 1}}/>
                </TabNavigator.Item>

                <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="我的">

                    <View style={{backgroundColor: '#FFF', flex: 1}}/>
                </TabNavigator.Item>

            </TabNavigator>
        </View>

    }
}

const styles = StyleSheet.create({

    container: {
        flex: 1
    },
    icon: {
        width: 26,
        height: 26
    }

});

解释:

我这里拿出一个item 出来解释

renderSelectedIcon 这是选中后的图片
tintColor 是给图片渲染
title 就是名字
我在构造函数中定义了一个变量selectedTab 让他默认是最热

// 初始状态
this.state = {selectedTab: ‘papular’};

然后在item中判断selected={this.state.selectedTab === ‘papular’} 值是否为最热

通过selected 判断是否选中状态 根据值是否相等

在onPress 点击事件 里面给他重新设置值

在每个item 中间可以看到我填充了一个view

<View style={{backgroundColor: '#FF0', flex: 1}}/>

这个就是作为填充的视图


        
                <TabNavigator.Item
                    selected={this.state.selectedTab === 'papular'}
                    title="最热"
                    slectedTitleStyle={{color: '#FFF'}}
                    renderIcon={() => <Image style={styles.icon}
                                             source={require('../../res/images/ic_popular.png')}></Image>}
                    renderSelectedIcon={() =>
                        <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                               source={require('../../res/images/ic_popular.png')}/>}
                    onPress={() => this.setState({selectedTab: 'papular'})}>

                    <View style={{backgroundColor: '#FF0', flex: 1}}/>
                </TabNavigator.Item>

然后 看下效果图

image


最后看下这个第三方库react-native-TabNavigator的item的源码 直接在import哪里点击引入就好(android studio
怎么点这里就怎么点)


export default class TabNavigatorItem extends React.Component {
  static propTypes = {
    renderIcon: PropTypes.func,
    renderSelectedIcon: PropTypes.func,
    badgeText: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    renderBadge: PropTypes.func,
    title: PropTypes.string,
    titleStyle: Text.propTypes.style,
    selectedTitleStyle: Text.propTypes.style,
    tabStyle: ViewPropTypes.style,
    selected: PropTypes.bool,
    onPress: PropTypes.func,
    allowFontScaling: PropTypes.bool,
  };

  static defaultProps = {
  };

  render() {
    let child = React.Children.only(this.props.children);
    return React.cloneElement(child, {
      style: [child.props.style, this.props.style],
    });
  }
}

可以看到 renderIcon renderSelectedIcon 等等的声明都在这里


最热页面 PapularPage.js : 以及导航栏 NavigationBar.js

说下对应关系 homepage 里面包含了最热页面 PapularPage.js 最热页面里面包含了导航栏 NaivgationBar.js

关于react native 布局 这篇文章很不错错 http://www.jianshu.com/p/688b9108a922

先写NavigationBar.js


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

export default class NavigationBar extends Component {

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

                <View style={styles.rightBar}>
                    <TouchableOpacity activeOpacity={0.7}>
                        <Image source={require('../../res/images/ic_search_white_48pt.png')}></Image>
                    </TouchableOpacity>
                    <TouchableOpacity activeOpacity={0.7}>
                        <Image source={require('../../res/images/ic_more_vert_white_48pt.png')}></Image>
                    </TouchableOpacity>

                </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'
    },
    rightBar: {
        flexDirection: 'row',
        alignItems: 'center',
        paddingRight:8
    }
});


看下效果图

mark

分析 从样式分析

statusBar

NavigationBar 会包含状态栏,还有顶部导航栏 状态栏用到一个控件 StatusBar (ios用的)

注意这里ios和android 稍微有点不同了ios StatusBar 有效果 就是显示顶部的状态栏.安卓没效果

关于状态栏说下 ios 可以使用 android 无效果 所以得区分下 这里我使用了Platfrom 判断是ios 还是android

navBar

flexDirection: ‘row’, 让主轴方向是横向

justifyContent: ‘space-between’, 让主轴排列方式是在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首

对齐,每行最后一个元素与行尾对齐。( 这里面有个技巧: 因为控件只有三个

会造成热门文字不在中间, 那么我就在最左边再添加一个view )

titleWrapper

flexDirection: ‘column’, 让主轴方向是纵轴

justifyContent: ‘center’, 主轴排列方式居中

alignItems: ‘center’, 交叉轴的排列方式也是居中的

position: 'absolute',
    left: 40,
    right: 40,   

说下为什么这里需要position ,可以尝试下不加position 会造成热门并不在中间.那么就给他使用position 并且微调下

position enum(‘absolute’,‘relative’)属性设置元素的定位方式,为将要定位的元素定义定位规则。

absolute 生成绝对定位的元素,元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。

relative:生成相对定位的元素,相对于其正常位置进行定位。因此,“left:20” 会向元素的 LEFT 位置添加 20 像素。

title

没啥说的就是设置了颜色和大小

navBtn

也没啥说的 就是给设置了宽高 右边的搜索和更多的图片宽高

rightBar

包裹右面两个图片的样式

flexDirection: ‘row’, 主轴方向横向

alignItems: ‘center’, 主轴对齐方式居中对齐

paddingRight: 8 居右8?  我不清楚这个是dp 还是像素

TouchableOpacity(透明度变化)

TouchableOpacity组件介绍
该组件封装了响应触摸事件。当点击按下的时候,该组件的透明度会降低。该组件使用过程中

并不会改变视图的层级关系,而且我们可以非常容易的添加到应用并且不会产生额外的异常错误。

创建 PapularPage.js 里面包含了NavigationBar.js

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

import NavigationBar from "../compoent/NavigationBar.js"
export default class PapularPage extends Component {

    render() {
        return <View style={styles.container}>
            <NavigationBar/>
        </View>
    }
}

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

没啥说的 非常简单就是把NavigationBar加入到了这个Papular页面

把上面的做好之后的效果图就是我上面的效果图


OK 下面在PapularPage页面内添加 可以左右滑动的控件(选项卡控件)

react-native-scrollable-tab-view

用到一个第三方组件 http://www.jianshu.com/p/b7788c3d106e

上面有使用方式 我把他引入我的项目


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

import NavigationBar from "../compoent/NavigationBar.js"
import ScrollableTabView from "react-native-scrollable-tab-view"
export default class PapularPage extends Component {

    render() {
        return <View style={styles.container}>
            <NavigationBar/>
            <ScrollableTabView
                tabBarBackgroundColor="#63B8FF"
                tabBarActiveTextColor="#FFF"
                tabBarInactiveTextColor="#F5FFFA"
                tabBarUnderlineStyle={{backgroundColor: "#E7E7E7", height: 2}}>
                <Text tabLabel='IOS'/>
                <Text tabLabel='Android'/>
                <Text tabLabel='Java'/>
                <Text tabLabel='JavaScript'/>
            </ScrollableTabView>
        </View>
    }
}

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

mark

比较简单没啥说的.

现在的数据是写死的 后面会动态改变

tabBarUnderlineStyle(style)
设置DefaultTabBar和ScrollableTabBarTab选中时下方横线的颜色

tabBarBackgroundColor(String)
设置整个Tab这一栏的背景颜色

tabBarActiveTextColor(String)
设置选中Tab的文字颜色

tabBarInactiveTextColor(String)
设置未选中Tab的文字颜色

tabBarTextStyle(Object)
设置Tab文字的样式,比如字号、字体等


下面是关于布局的总结:

容器的属性

flexDirection

flexWrap

justifyContent

alignItems

项目的属性

flex

alignSelf

flexDirection属性

flexDirection属性决定主轴的方向(即项目的排列方向)。
它可能有4个值:

row:主轴为水平方向,起点在左端。

row-reverse:主轴为水平方向,起点在右端。

column(默认值):主轴为垂直方向,起点在上沿。

column-reverse:主轴为垂直方向,起点在下沿。

flexWrap属性

默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。它可能取三个值。

(1)nowrap(默认):不换行。

(2)wrap:换行,第一行在上方。

justifyContent属性

justify-content属性定义了项目在主轴上的对齐方式。

它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。
flex-start(默认值):左对齐

flex-end:右对齐

center: 居中

space-between:两端对齐,项目之间的间隔都相等。

space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

alignItems属性

align-items属性定义项目在交叉轴上如何对齐。
它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

flex-start:交叉轴的起点对齐。

flex-end:交叉轴的终点对齐。

center:交叉轴的中点对齐。

baseline: 项目的第一行文字的基线对齐。

stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

flex属性

flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

flex-grow属性

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

alignSelf属性

alignSelf属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。

默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页