React Native :加载新闻列表
标签与内容页联动
上一节(React Native : 自定义视图)做到了点击标签自动移动,还差跟下面的视图进行联动。
首先创建 NewsList.js :
import React from 'react'
import {
View,
Text,
ListView,
Image,
StyleSheet,
Dimensions
} from 'react-native'
const {width, height} = Dimensions.get('window')
export default class NewsList extends React.Component {
render() {
const {style} = this.props
return (
<View style={[styles.view,style]}>
</View>
)
}
}
const styles = StyleSheet.create({
view: {
flex: 1,
backgroundColor:'red'
}
})
然后在 Home.js 引入,再加入 ScrollView ,现在 Home.js 的 redner() 是这样子的,这里加入的 ScrollView 我们在后文中称为 NewsScrollView
render() {
return (
<View style={styles.view}>
<NavigationBar
title="首页"
unLeftImage={true}
/>
<SegmentedView
ref="SegmentedView"
list={this.state.list}
style={{height: 30}}
/>
<ScrollView
style={styles.view}
ref="ScrollView"
horizontal={true}
showsHorizontalScrollIndicator={false}
pagingEnabled={true}
>
{ this._getNewsLists()}
</ScrollView>
</View>
)
}
_getNewsLists() 方法:
_getNewsLists() {
let lists = []
if (this.state.list) {
for (let index in this.state.list) {
let dic = this.state.list[index]
lists.push(
<NewsList
key={index}
style={{backgroundColor:'#' + this._getColor('',0), width: width, height: height - 49 - 64 - 30}}
dic={dic}
/>
)
}
}
return lists
}
_getColor(color, index) {
index ++
if (index == 7) {
return color
}
color = color + '0123456789abcdef'[Math.floor(Math.random()*16)]
return this._getColor(color, index)
}
根据返回的数据创建对应数量的视图,给随机颜色方便看效果。
先设置滑动 NewsScrollView 让标签跟着移动。
我们把 SegmentedView 中 items.push 中的 onPress 方法的实现单独写到一个方法里,然后在这里调用:
_moveTo(index) {
const { list } = this.props //获取到 传入的数组
this.state.selectItem && this.state.selectItem._unSelect()
this.state.selectItem = this.refs[index]
if (list.length > maxItem) {
let meiosis = parseInt(maxItem / 2)
this.refs.ScrollView.scrollTo({x: (index - meiosis < 0 ? 0 : index - meiosis > list.length - maxItem ? list.length - maxItem : index - meiosis ) * this.state.itemWidth, y: 0, animated: true})
}
}
这里会发现我们给 this.state 加了一个 itemWidth ,原来我们获取 itemWidth 是在 _getItems() 中计算的,但是在渲染的过程中无法调用 setState() ,我们把计算 itemWidth 的方法移动到 :
componentWillReceiveProps(props) {
const { list } = props //获取到 传入的数组
if (!list || list.length == 0) return
// 计算每个标签的宽度
let itemWidth = width / list.length
if (list.length > maxItem) {
itemWidth = width / maxItem
}
this.setState({
itemWidth
})
}
componentWillReceiveProps(props) 方法会在属性更新后调用,参数 props 是新的属性。
现在运行会发现点击标签可以正常改变标签的状态,然而拖动 NewsScrollView 只会让上一个选中的变为未选中,新的标签并没有变为选中,这是因为选中状态只在标签被点击的时候进行了设置,我们需要给 Item 添加一个选中的方法 :
_select() {
this.setState({
isSelect: true
})
}
然后在 _moveTo(index) 进行调用:
this.state.selectItem && this.state.selectItem._unSelect()
this.state.selectItem = this.refs[index]
this.state.selectItem._select()
现在运行滑动 NewsScrollView 上面的 SegmentedView 可以正常运行了。
最后设置点击标签可以让 NewsScrollView 滑动到对应的位置,我们需要给 SegmentedView 加入一个回调函数,在标签被点击的时候调用返回点击的 index
<SegmentedView
ref="SegmentedView"
list={this.state.list}
style={{height: 30}}
selectItem={(index) => {
this.refs.ScrollView.scrollTo({x: width * index, y: 0, animated: true})
}}
/>
在 SegmentedView 进行调用:
_getItems() {
const { list, selectItem } = this.props //获取到 传入的数组
if (!list || list.length == 0) return []
let items = []
for (let index in list) {
let dic = list[index]
items.push(
<Item
ref={index}
key={index}
isSelect={index == 0}
itemHeight={this.state.itemHeight}
itemWidth={this.state.itemWidth}
dic={dic}
onPress={() => {
this._moveTo(index)
selectItem && selectItem(index)
}}
/>
)
}
return items
}
加载新闻列表第一页数据 加载新闻列表第一页数据
在 Home.js 中已经给 NewsList 传入了数据,我们再给传入一个参数识别是否是第一页,初始只加载第一页的数据,也方便调试:
_getNewsLists() {
let lists = []
if (this.state.list) {
for (let index in this.state.list) {
let dic = this.state.list[index]
lists.push(
<NewsList
key={index}
style={{backgroundColor:'white'}}
dic={dic}
isRequest={index == 0}
/>
)
}
}
return lists
}
然后去 NewsList.js 进行请求数据:
// 构造
constructor(props) {
super(props);
// 初始状态
this.state = {
page: 1,
rn: 1,
};
}
componentDidMount() {
if (!this.props.isRequest) return
this._onRefresh()
}
_onRefresh(page) {
if (this.props.dic) {
let url = 'http://api.iapple123.com/newspush/list/index.html?clientid=1114283782&v=1.1&type='
+ this.props.dic.NameEN
+ '&startkey=&newkey=&index='
+ (page ? page : this.state.page)
+ '&size=20&ime=6271F554-7B2F-45DE-887E-4A336F64DEE6&apptypeid=ZJZYIOS1114283782&rn='
+ this.state.rn
LOG('url=》', url)
fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
})
.then((res) => {
res.json()
.then((json) => {
LOG('GET SUCCESSED then =>', url, json)
})
})
.catch((e) => {
LOG('GET ERROR then =>', url, e)
})
})
.catch((error) => {
LOG('GET ERROR=>', url, '==>', error)
})
}
}
请求到数据后我们需要用 ListView (官方文档) 来显示, 所以导入 ListView ,然后去 render() 加入:
render() {
const {style} = this.props
return (
<View style={[styles.view,style]}>
<ListView
style={{flex:1}}
dataSource={this.state.dataSource} //设置数据源
renderRow={this.renderRow} //设置cell
/>
</View>
)
}
然后加入 dataSource 和 renderRow:
// 构造
constructor(props) {
super(props);
var getRowData = (dataBlob, sectionID, rowID) => {
return dataBlob[sectionID][rowID]
};
// 初始状态
this.state = {
page: 1,
rn: 1,
dataSource: new ListView.DataSource({
getRowData: getRowData,
rowHasChanged: (r1, r2) => r1 !== r2,
}),
};
this.renderRow = this.renderRow.bind(this)
}
renderRow(rowData, rowID, highlightRow) {
return (
<View />
)
}
运行效果
我们要做的界面是这个样子

从上图可以看出来新闻分为 3 种样式,轮播图、有一张图片的和二、三张图片的。
接下来开始解析数据,解析完 json 数据发现只有一个数组,轮播图是取了前四个,剩下的根据 ImagesList 里图片的个数来判断,
去 .then((json) => { 加入
let list = json.NewsList
let swipers = []
let news = []
for (let index in list) {
let dic = list[index]
index < 4 ? swipers.push(dic) : news.push(dic)
}
news.splice(0, 0, swipers)
this.setState({
dataSource: this.state.dataSource.cloneWithRows(news)
})
现在 news 的数据结构为:
[
[
{},
{}
],
{},
{}
}
然后去 renderRow 处理数据
如果是数组,那么返回轮播图:
if (Object.prototype.toString.call(rowData) === '[object Array]') {
return (
<CarousePicture
index={2}
ref="ScrollView"
rowData={rowData}
style={{width, height: 200}}
touchIn={this.props.touchIn}
>
</CarousePicture>
)
}
这里的轮播图本来用的 Swiper,但是在 Android 上有很多 BUG,我只好自己写了一个,但是在 Android 上的体验差强人意,源码在这里,把文件导入项目即可。
具体的可以看这里
touchIn 是由于在 Andoird 上两个 ScrollView 重叠时,处于顶部的 ScrollView 滑动事件不会响应,因为底部的 ScrollView 进行了响应并拦截了事件,我们需要在手指接触到轮播图的时候禁用底部 ScrollView 的滑动属性,再手指离开的时候再进行恢复,所以还需要去 Home.js 加入:
_getNewsLists() {
let lists = []
if (this.state.list) {
for (let index in this.state.list) {
let dic = this.state.list[index]
lists.push(
<NewsList
key={index}
style={{backgroundColor:'white', width: width, height: height - 64 - 49 - 30}}
dic={dic}
isRequest={index == 0}
touchIn={(scrollEnabled) => {
this.refs.ScrollView.setNativeProps({scrollEnabled: !scrollEnabled})
}}
/>
)
}
}
return lists
}
然后根据 ImagesList 的个数来区分:
let imagesList = rowData.ImagesList
if (imagesList && imagesList.length == 1) {
return (
<TouchableOpacity style={{width, backgroundColor:'white'}}>
<View
style={{width, backgroundColor:'white', flexDirection:'row', justifyContent:'space-between', flex:1}}>
<Image
resizeMode="cover"
style={{marginTop: 10, marginBottom:10, marginLeft: 10, width: 80, height: 80, backgroundColor:'#EEEEEE'}}
source={{uri:imagesList[0].ImgPath}}
/>
<View
style={{ marginRight: 10,backgroundColor:'white', marginTop: 10, height: 80, width: width - 110}}
>
<Text>{rowData.Title}</Text>
<View style={{flex:1, flexDirection: 'row', justifyContent: 'space-between'}}>
<Text style={{marginTop:10, fontSize: 13, color: '#999999'}}>{rowData.Source}</Text>
<Text style={{marginRight:0,marginTop:10,fontSize: 13, color: '#999999'}}>{rowData.PublishTime}</Text>
</View>
</View>
</View>
<View style={{width, height:1, backgroundColor: '#EEEEEE'}}></View>
</TouchableOpacity>
)
}
let images = []
for (let index in imagesList) {
let dic = imagesList[index]
images.push(
<Image
resizeMode="cover"
key={index}
style={{marginRight: 10, marginLeft: index == 0 ? 10 : 0, marginTop:10, marginBottom: 10,flex:1, height: 90}}
source={{uri:dic.ImgPath}}
/>
)
}
return (
<TouchableOpacity style={{width, backgroundColor:'white'}}>
<View style={{width,backgroundColor:'white'}}>
<Text style={{marginLeft: 10, marginTop: 10}}>{rowData.Title}</Text>
</View>
<View style={{flexDirection:'row'}}>
{images}
</View>
<View style={{flex:1, flexDirection: 'row', justifyContent: 'space-between'}}>
<Text style={{marginLeft: 10, marginBottom: 10,fontSize: 13, color: '#999999'}}>{rowData.Source}</Text>
<Text style={{marginRight:10,fontSize: 13, marginBottom: 10,color: '#999999'}}>{rowData.PublishTime}</Text>
</View>
<View style={{width, height:1, backgroundColor: '#EEEEEE'}}></View>
</TouchableOpacity>
)
我这里的 style 没有进行整理,所以看着比较乱,正式开发中应该整理到 styles 里,看起来就简洁多了。
现在运行就可以显示第一页的数据了。
项目结构
项目结构如下:

React Native :加载新闻列表
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
React Native :加载新闻列表的更多相关文章
- 《React Native 精解与实战》书籍连载「React Native 网络请求与列表绑定」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
- React 16 加载性能优化指南
关于 React 应用加载的优化,其实网上类似的文章已经有太多太多了,随便一搜就是一堆,已经成为了一个老生常谈的问题. 但随着 React 16 和 Webpack 4.0 的发布,很多过去的优化手段 ...
- WP8.1开发中ListView控件加载图列表的简单使用(1)
我也是刚接触WP编程没几个月,就是在这段时间一直闲着没事,然后又比较喜欢WP这款系统,就学习了WP这方面的开发言语,自学是很困难的,掌握这方面的资料不多,很初级,就是自己在网上找资料学习过程中,看到别 ...
- 02 - Unit05:加载笔记列表
加载笔记列表 发送Ajax请求 绑定发送事件 获取参数: bookId 发送请求: /note/list.do 事件绑定 $(function(){ Ajax请求发送-->服务器处理--> ...
- Android UI开发第三十六篇——使用Volley加载图片列表
Android开发者可能会使用Universal Image Loader或者Square`s newer Picasso这些第三方的库去处理图片的加载,那么Volley是怎么加载图片列表的呢,这一篇 ...
- react热加载失败
react热加载失败 原因:路径名字大小写错误, 不是全部加载失败,有的时候可以用,有的时候不可以 热加载插件:webpack-dev-server
- js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符
js中对arry数组的各种操作小结 最近工作比较轻松,于是就花时间从头到尾的对js进行了详细的学习和复习,在看书的过程中,发现自己平时在做项目的过程中有很多地方想得不过全面,写的不够合理,所以说啊 ...
- PHP+Ajax点击加载更多列表数据实例
一款简单实用的PHP+Ajax点击加载更多列表数据实例,实现原理:通过“更多”按钮向服务端发送Ajax请求,PHP根据分页参数查询将最新的几条记录,数据以JSON形式返回,前台Query解析JSON数 ...
- JS window对象 返回前一个浏览的页面 back()方法,加载 history 列表中的前一个 URL。 语法: window.history.back();
返回前一个浏览的页面 back()方法,加载 history 列表中的前一个 URL. 语法: window.history.back(); 比如,返回前一个浏览的页面,代码如下: window.hi ...
随机推荐
- 树链剖分【p4116】Qtree3 - Query on a tree
Description 给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白 有两种操作: 0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑) 1 v : 询问1到v的路径上的第一个黑 ...
- 【线段树】bzoj3922 Karin的弹幕
设置一个值K. d<=K:建立多组线段树:d>K:暴力. 最优时间复杂度的伪计算: O(n*K*logn(建树)+m*logn(询问类型1)+m*n/K(询问类型2)+m*K*logn(修 ...
- 数列求和 Exercise06_13
/** * @author 冰樱梦 * 时间:2018年下半年 * 题目:数列求和 * */ public class Exercise06_13 { public static void main( ...
- 【R实践】时间序列分析之ARIMA模型预测___R篇
时间序列分析之ARIMA模型预测__R篇 之前一直用SAS做ARIMA模型预测,今天尝试用了一下R,发现灵活度更高,结果输出也更直观.现在记录一下如何用R分析ARIMA模型. 1. 处理数据 1.1. ...
- Scala实战高手****第15课:Scala类型参数编程实战及Spark源码鉴赏
1.Scala的类和方法.函数都可以是泛型 2.上界:表示泛型的类型必须是某种类型或者其类型的子类,语法:<: ,对类型进行限定 3.下界:表示泛型的类型必须是某种类型或者其类型的父类,语法:& ...
- ThinkPHP处理海量数据分表机制详细代码及说明
ThinkPHP处理海量数据分表机制详细代码及说明 应用ThinkPHP内置的分表算法处理百万级用户数据. 数据表: house_member_0 house_member_1 house_mem ...
- 最新Mac安装CocoaPods详细教程及各种坑解决办法
网上有很多教程,但要么内容很老,要么不详细,要么各种坑的情况没写.最近买新电脑了,正好要走一遍这些流程,所以写下次教程. 一.安装RVM及更新Ruby 安装RVM的目的是为了更新Ruby,如果你的Ru ...
- hadoop InputSplit
/** * <code>InputSplit</code> represents the data to be processed by an * individual {@l ...
- IntelliJ IDEA强制更新Maven的包
1.手动删除Project Settings里面的Libraries内容,[Ctrl]+[Alt]+[Shift]+[S],全选之后点击左上角的减号按钮. 2.在Maven Project的试图里的L ...
- ORA-12537:TNS连接已关闭
安装完11i的VIS版本后,客户端连接数据时会报“ORA-12537:TNS连接已关闭”,在网上找到以下解决办法: 今天在远程客户端配置EBS数据库连接的时候发生“ORA-12537:TNS连接已 ...