zoukankan      html  css  js  c++  java
  • react-native 项目实战 -- 新闻客户端(6) -- 完善ListView头部视图

    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.效果图

  • 相关阅读:
    Webpack打包原理
    Vue——VNode
    Vue——响应式原理
    HTTP2.0——头部压缩
    HTTP2.0
    浏览器打开2个页面会有几个进程?
    计算机网络——TCP如何保证可靠性
    操作系统——进程之间的通信
    前端路由hash与history下
    前端路由hash与history上
  • 原文地址:https://www.cnblogs.com/crazycode2/p/7282733.html
Copyright © 2011-2022 走看看