1.因为需要定时器,所以我们要cd到当前项目根目录下安装这个类库:

$ npm i react-timer-mixin --save

2.Component/ScrollImage.js

/**
* 滚动图
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ScrollView,
Image
} from 'react-native'; // 引入Dimensions类库
var Dimensions = require('Dimensions');
var ScreenW = Dimensions.get('window').width; // 引入计时器类库
var TimerMixin = require('react-timer-mixin'); var ScrollImage = React.createClass({
// 注册计时器
mixins: [TimerMixin], // 设置固定值
getDefaultProps(){
return{
// 每隔多少时间
duration:2000,
// 所有的image对象数据
imageDataArr:[]
}
}, // 设置可变和初始化值
getInitialState(){
return{
// 当前页面
currentPage:0,
// 当前标题
title:this.props.imageDataArr[0].title,
}
}, render() {
return (
<View style={styles.container}>
<ScrollView
ref="scrollView"
horizontal={true}
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
// 当一帧滚动结束
onMomentumScrollEnd={(e)=>this.onAnimationEnd(e)}
// 开始拖拽scrollView
onScrollBeginDrag={this.onScrollBeginDrag}
// 停止拖拽
onScrollEndDrag={this.onScrollEndDrag}
>
{this.renderAllImage()}
</ScrollView>
<View style={styles.indicatorViewStyle}>
<Text style={{color:'white',marginLeft:10}}>{this.state.title}</Text>
<View style={{flexDirection:'row',alignItems:'center',marginRight:10}}>
{this.renderPageCircle()}
</View>
</View>
</View>
);
}, // 开始拖拽的时候调用
onScrollBeginDrag(){
// 停止定时器
this.clearInterval(this.timer);
}, // 停止拖拽的时候调用
onScrollEndDrag(){
// 开启定时器
this.startTimer();
}, // 组件已经加载完毕之后,实现一些复杂的操作
componentDidMount(){
// 开启定时器
this.startTimer();
}, // 开启定时器
startTimer(){
// 1.拿到scrollView
var scrollView = this.refs.scrollView;
var imgCount = this.props.imageDataArr.length; // 2.添加定时器 this.timer 可以理解成一个隐士的全局变量
this.timer = this.setInterval(function () {
// 2.1设置圆点
var activePage = 0;
// 2.2判断
if((this.state.currentPage+1) >= imgCount){ //越界
activePage = 0;
}else{
activePage = this.state.currentPage+1;
}
// 3.更新状态机,重新绘制UI
this.setState({
currentPage:activePage
}); //4.让scrollView滚动起来
var offsetX = activePage * ScreenW;
scrollView.scrollResponderScrollTo({x:offsetX,y:0,animated:true});
},this.props.duration);
}, // 返回图片
renderAllImage(){
// 数组
var allImage = [];
// 拿到图片数据
var imageArr = this.props.imageDataArr;
// 遍历
for(var i=0;i<imageArr.length;i++){
// 取出单个图片对象
var imgItem = imageArr[i];
// 创建组件装入数组
allImage.push(
<Image key={i} source={{uri:imgItem.imgsrc}} style={{width: ScreenW,height:150}} />
);
} // 返回
return allImage;
}, // 返回分页指示器圆点
renderPageCircle(){
// 定义一个数组放置所有的圆点
var indicatorArr = [];
var imgArr = this.props.imageDataArr; // 特殊样式
var style; for(var i=0;i<imgArr.length;i++){
// 判断style
style = (i==this.state.currentPage) ? {color:'orange'} : {color:'#fff'};
indicatorArr.push(
<Text key={i} style={[{fontSize:30},style]}>•</Text>
);
}
return indicatorArr;
}, // 当一帧滚动结束的时候调用
onAnimationEnd(event){
// 1.计算水平方向偏移量
var offsetX = event.nativeEvent.contentOffset.x
// 2.计算当前页码
var page = Math.floor(offsetX / ScreenW);
// 3.更新状态机,重新绘制UI
this.setState({
currentPage:page,
title:this.props.imageDataArr[page].title,
});
}, }); const styles = StyleSheet.create({
container:{
// marginTop:20,
},
// 分页指示器样式
indicatorViewStyle:{
width:ScreenW,
height:25,
backgroundColor:'rgba(0,0,0,0.4)',
position:'absolute',
bottom:0,
// 设置主轴方向,让圆点水平排列
flexDirection:'row',
// 侧轴方向
alignItems:'center',
// 主轴对齐方式
justifyContent:'space-between',
}
}); // 最后要输出这个类库
module.exports = ScrollImage;

  

3.Home.js

/**
* 首页
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView,
Image,
TouchableOpacity,
Platform,
} from 'react-native'; // 引入Dimensions类库
var Dimensions = require('Dimensions');
var ScreenW = Dimensions.get('window').width; // 导入本地json数据
var LocalData = require('../LocalData.json'); // 导入外部的组件类
var ScrollImage = require('../Component/ScrollImage'); var Home = React.createClass({
// 不可改变的默认值
getDefaultProps(){
return{
url_api:'http://c.m.163.com/nc/article/headline/T1348647853363/0-20.html',
key_word:'T1348647853363'
}
}, // 初始化
getInitialState(){
return{
// ListView头部轮播图的数据源
headerDataArr:[],
// cell的数据源
dataSource: new ListView.DataSource({
rowHasChanged:(r1,r2)=>{r1 !== r2}
})
}
}, render() {
return (
<View style={styles.container}>
{/*导航条*/}
{this.renderNavBar()}
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
renderHeader={this.renderHeader}
/>
</View>
);
}, // 导航条
renderNavBar(){
return(
<View style={styles.navOutViewStyle}>
<Text style={{color:'white',fontSize:16,fontWeight:'bold'}}>首页</Text>
</View>
)
}, // 返回ListView头部视图
renderHeader(){
// 如果没有头部banner数据
if(this.state.headerDataArr.length == 0) return; return(
<ScrollImage
imageDataArr={this.state.headerDataArr}
/>
)
}, // 返回LisView中的单个cell
renderRow(rowData){
return(
<TouchableOpacity activeOpacity={0.8}>
<View style={styles.cellViewStyle}>
<Image source={{uri:rowData.imgsrc}} style={styles.imgStyle} />
<View style={styles.rightViewStyle}>
<Text style={styles.mainTitleStyle}>{rowData.title}</Text>
<Text style={styles.subTitleStyle}>{rowData.digest}</Text>
</View>
</View>
</TouchableOpacity>
)
}, // 组件加载完毕之后调用
componentDidMount(){
// 请求网络数据
this.loadDataFromNet();
}, // 请求网络数据的方法
loadDataFromNet(){
fetch(this.props.url_api)
.then((response)=>response.json())
.then((responseData)=>{
// 拿到需要的数据
var jsonData = responseData[this.props.key_word]; // 处理数据
this.dealWithData(jsonData);
})
.catch((error)=>{
if(error){
// 网络请求失败,就用本地数据
console.log('网络请求失败');
var jsonData = LocalData[this.props.key_word];
this.dealWithData(jsonData);
}
})
}, // 处理网络数据的细节方法
dealWithData(jsonData){
// 定义临时变量
var headerArr = [], listDataArr = [];
// 遍历拿到的json数据
for (var i=0;i<jsonData.length;i++){
// 取出单个对象
var data = jsonData[i];
if(data.hasAD == 1){
// 取出广告数据
headerArr = data.ads;
}else {
// 非广告数据(行数据)
listDataArr.push(data)
}
} // 更新状态机
this.setState({
// ListView头部轮播图的数据源
headerDataArr:headerArr,
// cell的数据源
dataSource:this.state.dataSource.cloneWithRows(listDataArr),
}); console.log(headerArr,listDataArr);
},
}); const styles = StyleSheet.create({
// 导航条视图
navOutViewStyle:{
height:Platform.OS === 'ios' ? 64 : 44,
backgroundColor:'#468AFF',
// 主轴方向
flexDirection:'row',
// 侧轴对齐方式 垂直居中
alignItems:'center',
// 主轴方向居中
justifyContent:'center',
},
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
cellViewStyle:{
// 主轴方向
flexDirection:'row',
padding:10,
// 设置下边框
borderBottomColor:'#e8e8e8',
borderBottomWidth:0.8,
},
imgStyle:{
width:90,
width:90,
backgroundColor:'gray',
},
rightViewStyle:{
width:ScreenW - 90 - 10 * 2,
marginLeft:10,
},
mainTitleStyle:{
fontSize:16,
marginBottom:5,
},
subTitleStyle:{
fontSize:14,
color:'gray',
},
}); // 输出类
module.exports = Home;

  

4.效果图

react-native 项目实战 -- 新闻客户端(6) -- 完善ListView头部视图的更多相关文章

  1. 【腾讯Bugly干货分享】React Native项目实战总结

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/577e16a7640ad7b4682c64a7 “8小时内拼工作,8小时外拼成长 ...

  2. React Native 项目实战-Tamic

    layout: post title: React Native 项目实战 date: 2016-10-18 15:02:29 +0800 comments: true categories: Rea ...

  3. react-native 项目实战 -- 新闻客户端(5) -- 完善首页列表数据

    1.Home.js: /** * 首页 */ import React, { Component } from 'react'; import { AppRegistry, StyleSheet, T ...

  4. react-native 项目实战 -- 新闻客户端(7) -- 新闻详情页

    http://c.3g.163.com/nc/article/BUH64L0J00031H2L/full.html 观察这个地址,BUH64L0J00031H2L 就是每条新闻数据里的postid.  ...

  5. React Native 项目实战 -- DoubanProject

    引言:本文是我研究react-native时写的一个简单的demo,代码里有详细的注释,好废话不多说,直接上代码. 1.项目目录 2.index.android.js /** * index.andr ...

  6. React Native项目实战

    算是学习React Native的一次项目总结吧,目的还是提高自己. 包含的内容: 1>仿"美团"页面的实现; 2>封装项目中和自己常用的一些组件; 3>学习别人 ...

  7. react-native 项目实战 -- 新闻客户端(4) -- 请求网络数据

    1.Home.js /** * 首页 */ import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Te ...

  8. react-native 项目实战 -- 新闻客户端(2) -- 完善TabBar

    1.创建 drawable-xxhdpi 文件夹,保存 TabBar 的 icon图标 android  --  app  --  src  --  main  --  res  --  drawab ...

  9. react-native 项目实战 -- 新闻客户端(3) -- 包装导航控制器

    1.修改后的 Main.js /** * 主页面 */ import React, { Component } from 'react'; import { StyleSheet, Text, Vie ...

随机推荐

  1. 杭电oj2081、2091、1004、2057

    2081  手机短号 #include<stdio.h> #include<string.h> int main(){ int i,n; ]; while(scanf(&quo ...

  2. glRotatef 转动方向

    http://blog.sina.com.cn/s/blog_3c6889fe0100qko6.html glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLf ...

  3. Autotools Mythbuster

    Preface Diego Elio "Flameeyes" Pettenò Author and Publisher <flameeyes@flameeyes.eu> ...

  4. 一个C优先级队列实现

    刚下班没事干,实现了一个简单的优先级队列 #include <stdlib.h>#include <stdio.h> typedef void (*pqueue_setinde ...

  5. 关于python浮点数的精度问题。

    若想严格按照四舍五入进行,可使用Decimal,代码如下: from decimal import Decimal, ROUND_HALF_UP def round(x, n): return Dec ...

  6. 华农oj Problem B: Averyboy找密码【STL】

    Problem B: Averyboy找密码 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 83 Solved: 29 [Submit][Status] ...

  7. HDU 6396 Swordsman --------2018 Multi-University Training Contest 7 (模拟+读入挂)

    原题地址: 打怪升级 一开始有N个怪物:主角有K个能力:只有K个能力都击败怪物才能斩杀怪物并获得K个能力的增值:问最多能杀几个怪物: 做法: 用优先队列把怪物能力装进去:能力小放前面: 最重要的是数据 ...

  8. Count and Say (Array Length Encoding) -- LeetCode

    The count-and-say sequence is the sequence of integers beginning as follows:1, 11, 21, 1211, 111221, ...

  9. Linux守护进程的启动方法(转)

    作者: 阮一峰 日期: 2016年2月28日 "守护进程"(daemon)就是一直在后台运行的进程(daemon). 本文介绍如何将一个 Web 应用,启动为守护进程. 一.问题的 ...

  10. 开源 ≠ 免费,开源协议License详解

    凡是做过软件开发的,都会接触到开源软件或开源组件,它们都会基于某种协议来提供源码和授权,那么这些开源协议到底有哪些约束呢? 在介绍之前,必须告诉大家,针对开源协议,必须打消“开源 = 免费”这个念头, ...