其他的一些问题 记录下
什么时候 要给函数加上括号:
加括号情况: 当函数需要立即执行的时候(需要立刻返回)
不加括号情况: 当事件需要延迟触发的时候. (比如点击事件的函数)
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.这样才能进行页面的跳转
下面说下我是怎么操作的
- 首先因为ios 和android 的index.js 的文件内容都差不多那么就把相同的部分抽取出来 抽取成一个Setup.js,然后在index.android.js 和index.ios.js里面调用
- 在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