写一个用reactnative 的项目 可以用于查看GitHub最受欢迎与最热项目的App。
项目开始 HomePage.js
新建一个reactnative项目,
底部因为有四个tab 选项卡 那么 我使用一个第三方组件react-native-tab-navigator
并且新建一个HomePage.js,关于第三方组件可以看下这篇文章 http://www.jb51.cc/article/p-xbpxvclq-ys.html
这里单独说下 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 * @H_502_25@@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,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}}/>
这个就是作为填充的视图
然后 看下效果图
最后看下这个第三方库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,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',paddingRight:8
}
});
看下效果图
分析 从样式分析
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,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,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
}
});
比较简单没啥说的.
现在的数据是写死的 后面会动态改变
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。