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={{ 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:{ 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:{ 90, 90, backgroundColor:'gray', }, rightViewStyle:{ ScreenW - 90 - 10 * 2, marginLeft:10, }, mainTitleStyle:{ fontSize:16, marginBottom:5, }, subTitleStyle:{ fontSize:14, color:'gray', }, }); // 输出类 module.exports = Home;
4.效果图