写在前面的话
RN初学者,写这些文章一是帮自己回顾知识,二是帮助下像我这样没有前端基础却对RN这块感兴趣的同学。大致会按照宁皓网上的demo来写。有兴趣的同学可以直接去网站里看视频(收费的)
ListView
写过原生的同学都应该了解ListView是多么的重要,在RN里facebook为我们封装好了ListView组件,我们先看下官方文档里的说明。这里官方给我们提供了一个最简单的例子
constructor(props) {
super(props);
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(['row 1', 'row 2']),
};
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
);
}
在ListView中有两个属性dataSource
和renderRow
,其中dataSource
就是数据源,类似原生中adapter
中传入的list,renderRow
就是每一行item
的样式,类似adapter
中给item
设置的layout
。constructor
方法就是构造方法,会在程序被调用时运行。rowHasChanged
表示只更新有数据变化的item
。
this.state = {
dataSource: ds.cloneWithRows(['row 1', 'row 2']),
};
state
就是表示组件的一个状态,这里设置了一个状态dataSource
,他的值就是ds.cloneWithRows(['row 1', 'row 2'])
,然后在ListView组件中使用了这个状态dataSource={this.state.dataSource}
。这样就是将数据源交给了ListView。(如果不明白state
的可以先看一下React入门熟悉下React的语法)
实现一个电影ListView
首先创建一个MovieList项目react-native init MovieList
,等待一会大约10分钟(是不是可以来两局皇室战争呢(手动斜眼笑))。这里强烈推荐修改hosts来翻墙,会快很多。
好了,项目创建好了后,用atom打开(配置atom插件,我用着atom没感觉到卡,一定要装language-babel这个插件啊。要是不喜欢,也可以用sublime),我们先直接修改index.android.js。先按照官方给出的例子来写点数据显示出来。
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
ListView,
View
} from 'react-native';
let data = ['apple','pear','banana','orange','apple','pear','banana',
'orange','apple','pear','banana','orange','apple','pear','banana','orange',
'apple','pear','banana','orange','apple','pear','banana','orange'];
class MovieList extends Component {
constructor(){
super();
this.dataSource = new ListView.DataSource({
rowHasChanged:(row1,row2) => row1 !== row2
})
};
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.dataSource.cloneWithRows(data)}
renderRow={(rowData) =>
<View style={{flex:1,margin:10}}>
<Text style={{fontSize:25}}>{rowData}</Text>
</View>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('MovieList', () => MovieList);
效果图:
水果list效果图
如果有的同学也用的genymotion,也用的android6.0,那么可能会出现这样的一个错误:
错误1
这种情况只要把模拟器的wifi连接就可以了。
这里我们用到了行内样式
<View style={styles.container}>
<ListView
dataSource={this.dataSource.cloneWithRows(data)}
renderRow={(rowData) =>
<View style={{flex:1,margin:10}}>
<Text style={{fontSize:25}}>{rowData}</Text>
</View>}
/>
</View>
简单的一些样式,就可以采用行内样式的写法来处理。不明白箭头函数的可以看这里。
上面就是把一些简单的数据用list的方式显示出来了,现在我们就来显示一些真实的数据,这里我们使用豆瓣的api来拿数据来显示电影的名称。网络请求使用fetch
。
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
ListView,
View
} from 'react-native';
const REQUEST_URL = 'https://api.douban.com/v2/movie/top250';
class MovieList extends Component {
constructor(){
super();
this.state = {
movies:new ListView.DataSource({
rowHasChanged:(row1,row2) => row1 !== row2
})
}
this.fetchData();
};
fetchData(){
fetch(REQUEST_URL)
.then(response => response.json())
.then(responseData => {
console.log(responseData);
this.setState({
movies:this.state.movies.cloneWithRows(responseData.subjects)
})
})
.done();
};
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.movies}
renderRow={(movie) =>
<View style={{flex:1,margin:10}}>
<Text style={{fontSize:25}}>{movie.title}</Text>
</View>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('MovieList', () => MovieList);
效果图:
豆瓣TOP250
请求数据的方法fetchData
的理解可以结合log
来理解(不会调试的看这里)
现在我们能够显示出电影的名字,但为免也太单调了,我们接着把电影的海报,别名,评分也显示出来。首先我们要调整一下listview的item的样式,其中要使用的另一个组件image,同时也将样式的写法统一。在使用到组件的时候需要在顶部的import里将组件包含进来。
注意在使用image组件的时候一定要给图片设置宽高,图片才会显示。
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
ListView,
Image,
View
} from 'react-native';
const REQUEST_URL = 'https://api.douban.com/v2/movie/top250';
class MovieList extends Component {
constructor(){
super();
this.state = {
movies:new ListView.DataSource({
rowHasChanged:(row1,row2) => row1 !== row2
})
}
this.fetchData();
};
fetchData(){
fetch(REQUEST_URL)
.then(response => response.json())
.then(responseData => {
console.log(responseData);
this.setState({
movies:this.state.movies.cloneWithRows(responseData.subjects)
})
})
.done();
};
renderMovieList(movie){
return(
<View style={styles.item}>
<View style={styles.itemImage}>
<Image
style={styles.image}
source={{uri:movie.images.large}} />
</View>
<View style={styles.itemContent}>
<Text style={styles.itemHeader}>
{movie.title}
</Text>
<Text style={styles.itemMeta}>
{movie.original_title} ({movie.year})
</Text>
<Text style={styles.redText}>
{movie.rating.average}
</Text>
</View>
</View>
);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.movies}
renderRow={
this.renderMovieList.bind(this)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
item:{
flexDirection:'row',
borderBottomWidth:1,
borderColor:'rgba(100,53,201,0.1)',
paddingBottom:6,
paddingTop:6,
flex:1,
},
itemText:{
fontSize:16,
fontFamily:'Helvetica Neue',
fontWeight:'400',
color:'rgba(0,0,0,0.8)',
lineHeight:26,
},
image:{
height:138,
width:99,
margin:6,
},
itemHeader:{
fontSize:18,
fontFamily:'Helvetica Neue',
fontWeight:'300',
color:'#6435c9',
marginBottom:6,
},
itemContent:{
flex:1,
marginLeft:13,
marginTop:6,
},
itemMeta:{
fontSize:16,
color:'rgba(0,0,0,0.6)',
marginBottom:6,
},
redText:{
color:'#db2828',
fontSize:15,
},
});
AppRegistry.registerComponent('MovieList', () => MovieList);
效果图:
豆瓣电影TOP250
这里可以看到图片,文字都正常的显示出来了,但在我们第一次加载的时候可以看到有很长时间的白屏时间,这就是我们的fetchData
方法在请求数据,正常情况下这里我们应该给用户一个正在加载的提示,我们将使用ActivityIndicator组件,他的显示效果就是在不停的转圈圈(ios中是小菊花,嘿嘿嘿)。配合这个组件,在请求数据的时候显示转圈圈(小菊花),数据请求完成后组件消失,显示正常的数据。这里就需要在state
中加一个loaded
变量,在请求数据的时候为false
,请求成功后为true
。(其实也就是设一个flag)
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
ListView,
Image,
ActivityIndicator,
View
} from 'react-native';
const REQUEST_URL = 'https://api.douban.com/v2/movie/top250';
class MovieList extends Component {
constructor(){
super();
this.state = {
movies:new ListView.DataSource({
rowHasChanged:(row1,row2) => row1 !== row2
}),
loaded:false
}
this.fetchData();
};
fetchData(){
fetch(REQUEST_URL)
.then(response => response.json())
.then(responseData => {
console.log(responseData);
this.setState({
movies:this.state.movies.cloneWithRows(responseData.subjects),
loaded:true
})
})
.done();
};
renderMovieList(movie){
return(
<View style={styles.item}>
<View style={styles.itemImage}>
<Image
style={styles.image}
source={{uri:movie.images.large}} />
</View>
<View style={styles.itemContent}>
<Text style={styles.itemHeader}>
{movie.title}
</Text>
<Text style={styles.itemMeta}>
{movie.original_title} ({movie.year})
</Text>
<Text style={styles.redText}>
{movie.rating.average}
</Text>
</View>
</View>
);
}
render() {
if (!this.state.loaded) {
return(
<View style={styles.container}>
<View style={styles.loading}>
<ActivityIndicator
size='large'
color='#eabb33'/>
</View>
</View>
)
}
return (
<View style={styles.container}>
<ListView
dataSource={this.state.movies}
renderRow={
this.renderMovieList.bind(this)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
item:{
flexDirection:'row',
borderBottomWidth:1,
borderColor:'rgba(100,53,201,0.1)',
paddingBottom:6,
paddingTop:6,
flex:1,
},
itemText:{
fontSize:16,
fontFamily:'Helvetica Neue',
fontWeight:'400',
color:'rgba(0,0,0,0.8)',
lineHeight:26,
},
image:{
height:138,
width:99,
margin:6,
},
itemHeader:{
fontSize:18,
fontFamily:'Helvetica Neue',
fontWeight:'300',
color:'#6435c9',
marginBottom:6,
},
itemContent:{
flex:1,
marginLeft:13,
marginTop:6,
},
itemMeta:{
fontSize:16,
color:'rgba(0,0,0,0.6)',
marginBottom:6,
},
redText:{
color:'#db2828',
fontSize:15,
},
loading:{
flex:1,
justifyContent:'center',
alignItems:'center',
},
});
AppRegistry.registerComponent('MovieList', () => MovieList);
这里其实就是在render
方法里加了一个判断,效果图:
这里我们一个简单的MovieList就写好了。下面放一张IOS的效果图,代码可以完全不变直接复制到index.ios.js
中。(这就是RN的优势,代码复用率基本在80%以上,而且现在我们采用的是复制的方法,还比较麻烦,下个笔记将会把这个页面提取出来,这样更方便。同时推荐开发RN还是弄个OS X系统吧,白苹果黑苹果的都可以,我的就是黑苹果,确实方便很多)
写在最后的话
这段时间基本会一周写一篇关于RN的文章,直到我江郎才尽写不出来为止。会尽量把我会的东西写出来,写明白。我也是在学习,如果能把东西写明白了那么应该也是有一定的理解了。如果有问题可以给我留言,我们一起讨论。
如果想看我以前关于android的文章,戳这里(其实也没有多少东西(╯‵□′)╯︵┻━┻)。
学习路漫漫,吾将上下而求索。
网友评论