zoukankan      html  css  js  c++  java
  • 【水滴石穿】react-native-video-project

    感觉这个是很有才华的博主,毕竟是可以在npm 包里面留后门的程序员
    博主的gihtub关于这个项目的地址是:https://github.com/ikimiler/react-native-video-project
    运行出来了项目我十分兴奋,因为项目很完整,先不去想复杂不复杂,但是看到这样的项目会很感恩开源的程序员
    先看效果图






    项目的界面大概是如上面的样子
    布局很多类似,但是看到项目就会很开心
    接下来我们分析项目

    //index.js定义了入口为App.js,然后有数据处理这些
    import React from 'react'
    import { AppRegistry, StatusBar, View } from 'react-native';
    import {} from './src/utils/ScreenUtils'
    import { Provider } from 'react-redux'
    import Store from './src/utils/ConfigRedux'
    import CodePush from 'react-native-code-push'
    import App from './App'
    
    class Root extends React.Component {
    
        render() {
            return (
                <Provider store={Store}>
                    <App />
                </Provider>
            );
        }
    }
    
    // var wrapper = CodePush({
    //   checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
    //   installMode: CodePush.InstallMode.ON_NEXT_RESTART
    // })(Root);
    
    AppRegistry.registerComponent('colavideoapp', () => Root);
    
    //src/utils/ScreenUtils.js
    //判断手机型号,缩放比例
    import {Dimensions,PixelRatio,StatusBar,Platform} from 'react-native'
    
    // 设备的像素密度,例如:
    //  PixelRatio.get() === 1          mdpi Android 设备 (160 dpi)
    //  PixelRatio.get() === 1.5        hdpi Android 设备 (240 dpi)
    //  PixelRatio.get() === 2          iPhone 4, 4S,iPhone 5, 5c, 5s,iPhone 6,xhdpi Android 设备 (320 dpi)
    //  PixelRatio.get() === 3          iPhone 6 plus , xxhdpi Android 设备 (480 dpi)
    
    export const window = Dimensions.get("window")
    export const screen= Dimensions.get("screen")
    
    const defaultWidth = 1080,defaultHeight = 1920,defaultRatio = 3;
    
    //px to dp
    const w2 = defaultWidth / defaultRatio;
    const h2 = defaultHeight / defaultRatio;
    
    //获取缩放比例
    const scale = Math.min(window.height / h2, window.width / w2);
    
    function dp(number){
        let size = Math.round(number * scale + 0.5) / defaultRatio;
        return size
    }
    
    // iPhoneX Xs
    const X_WIDTH = 375;
    const X_HEIGHT = 812;
    
    // iPhoneXR XsMax
    const XR_WIDTH = 414;
    const XR_HEIGHT = 896;
    
    // screen
    const SCREEN_WIDTH = Dimensions.get('window').width;
    const SCREEN_HEIGHT = Dimensions.get('window').height;
     
    //判断是否为iphoneX或Xs
    function isIphoneX() {
        return (
            Platform.OS === 'ios' && 
            ((SCREEN_HEIGHT === X_HEIGHT && SCREEN_WIDTH === X_WIDTH) || 
            (SCREEN_HEIGHT === X_WIDTH && SCREEN_WIDTH === X_HEIGHT))
        )
    }
    
    //判断是否为iphoneXR或XsMAX
    function isIphoneXR() {
        return (
            Platform.OS === 'ios' && 
            ((SCREEN_HEIGHT === XR_HEIGHT && SCREEN_WIDTH === XR_WIDTH) || 
            (SCREEN_HEIGHT === XR_WIDTH && SCREEN_WIDTH === XR_HEIGHT))
        )
    }
    
    global.dp = dp;
    global.DEVICE = {
        window.width,
        height:window.height,
        screenWidth: Platform.OS == 'ios'? window.width : screen.width,
        screenHeight:Platform.OS == 'ios'? window.height : screen.height,
        StatusBarHeight: StatusBar.currentHeight,
        android:Platform.OS === 'android',
        ios:Platform.OS == 'ios',
        isIphoneX:isIphoneX() | isIphoneXR(),
    }
    
    
    //src/utils/ConfigRedux.js
    //定义了redux的公共入口
    import {createStore,combineReducers,applyMiddleware} from 'redux'
    import promiseMiddleware from 'redux-promise-middleware'
    
    function reducer(state ={},action){
        return {}
    }
    const reducers = combineReducers({
        index:reducer
    })
    const store = createStore(reducers,applyMiddleware(promiseMiddleware))
    
    export default store;
    
    //src/views/MainTabNavigatorHeader.js
    //设置的公共的搜索头部
    import React from 'react'
    import {
        Text,
        View,
        Image,
        TouchableOpacity
    } from 'react-native'
    import Header, { HeaderItem } from '../components/Header'
    
    
    export default class MainTabNavigatorHeader extends React.Component {
    
        _enterSearchPage = () => {
            this.props.navigation.navigate('SearchPage')
        }
    
        render() {
            return (
                <Header>
                    <HeaderItem onClick={() => this.props.navigation.navigate('PersonCenterPage')}>
                        <Image source={require('../../source/image/main_my.png')}></Image>
                    </HeaderItem>
                    <TouchableOpacity
                        onPress={this._enterSearchPage}
                        activeOpacity={1}
                        style={[{ flex: 1, height: 35, borderRadius: 5, backgroundColor: 'rgba(0,0,0,0.1)', justifyContent: 'center', alignItems: 'center' },this.props.centerStyle]}>
                        <Text>搜一搜,全都有</Text>
                    </TouchableOpacity>
                    {this.props.rightIcon && <HeaderItem onClick={() => this.props.onRightClick()}>
                        <Image source={this.props.rightIcon}></Image>
                    </HeaderItem>}
                </Header>
            );
        }
    }
    

    //src/pages/OfflineVideoPlayer.js
    //点击进去的视频页面
    import React from 'react'
    import { View, StyleSheet, ScrollView, Text, TouchableOpacity, Image, Share, ListView, NativeModules } from 'react-native'
    import BaseComponent from '../components/BaseComponent'
    import VideoWrapper from '../views/VideoWrapper'
    import { writeHistoryVideo, queryCollectVideo, deleteCollectVideo, writeCollectVideo } from '../utils/DButils'
    import Colors from '../utils/Colors'
    import Toast from 'react-native-root-toast'
    import DownloadManager from '../utils/DownloadManager'
    import Loadding from '../components/Loadding'
    
    
    export default class OfflineVideoPlayer extends BaseComponent {
    
        state = {
            data: null,
        }
    
        initData(){
            let item = this.props.navigation.state.params.data;
            this.setState({data:item},() => this.update(this.LOAD_SUCCESS))
        }
    
        _renderHeader() {
            let item = this.state.data;
            if(!item) return null;
    
            return (
                <VideoWrapper
                    item={item}
                    navigation={this.props.navigation}
                    onProgress={options => this.progressOption = options}
                    onLoad={data => {
                        
                    }}
                    onEnd={() => {
                        
                    }} />
            )
        }
    
        renderComponent() {
            let data = this.state.data;
            let playCount = parseInt(data.playCount)
            if (playCount > 10000) {
                playCount = (playCount / 10000).toFixed(1) + '万'
            }
            let title = data.title + (data.index > 0 ? ` 第${data.index}集` : "")
    
            return (
                <View style={{ flex: 1, backgroundColor: 'white' }}>
                    <ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 10 }}>
                        <Text style={[styles.itemStyle, { fontSize: 18, color: 'black' }]}>{title}</Text>
                        <View style={styles.itemBetweenStyle}>
                            <Text>播放: {playCount}次</Text>
                            <Text style={[styles.buttonStyle, { backgroundColor: Colors.mainColor }]}>豆瓣: {data.imdbScore > 0 ? data.imdbScore : '6.0'}</Text>
                        </View>
                        <Text style={styles.itemStyle}>分类: {data.classifyTypeListValue}</Text>
                        <Text style={styles.itemStyle}>导演: {data.director}</Text>
                        <Text style={styles.itemStyle}>演员: {data.staring}</Text>
                        <Text style={styles.itemStyle}>简介: </Text>
                        <Text style={[styles.itemStyle, { marginTop: 10 }]}>      {data.intro}</Text>
                    </ScrollView>
                </View>
            );
        }
    }
    
    var styles = StyleSheet.create({
        itemBetweenStyle: {
            flexDirection: 'row',
            alignItems: 'center',
            justifyContent: 'space-between',
            minHeight: 40,
        },
        itemStyle: {
            flexDirection: 'row',
            alignItems: 'center',
            minHeight: 30,
            textAlignVertical: 'center'
        },
        buttonStyle: {
            backgroundColor: '#EFF0EB',
            borderRadius: 5,
            paddingHorizontal: 10,
            paddingVertical: 5,
            textAlign: 'center',
            textAlignVertical: 'center',
            color: 'white'
        },
        bottomStyle: {
            flexDirection: 'row',
            height: 45,
            alignItems: 'center'
        },
        bottomImageStyle: {
             20,
            height: 20
        }
    })
    
    //src/utils/DownloadManager.js
    //点击下载的功能
    import fs from 'react-native-fs'
    import { queryDownloadVideoAll, writeDownloadVideo,deleteDownloadVideo } from '../utils/DButils'
    import Toast from 'react-native-root-toast'
    
    
    const baseFile = DEVICE.android ? fs.ExternalStorageDirectoryPath + "/ColaApp" : fs.LibraryDirectoryPath + "/ColaApp";
    fs.exists(baseFile).then(exists => {
      if (!exists) {
        fs.mkdir(baseFile)
      }
    })
    
    
    class DownloadManager {
    
      /**
       * 删除文件
       * @param {*} data 
       */
      deleteCacheVideo(data) {
        return new Promise(async function(resolve,reject) {
          try {
            let file = data.file;
            let exitis = await fs.exists(file)
            if (exitis) {
              let lastIndex = file.lastIndexOf("/")
              let dir = file.substring(0, lastIndex)
              await fs.unlink(dir)
              //同时删除数据库的记录
              await deleteDownloadVideo(data)
              resolve(true)
            } else {
              reject(false)
            }
          } catch (error) {
            console.log('netlog-', error)
            reject(false)
          }
        })
      }
    
      checkSafeUrl(data) {
        let url = data.url;
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
          Toast.show("非法的下载链接")
          return false;
        } else if (url.indexOf('.m3u8') > -1) {
          if (url.indexOf('?') > -1) {
            data.url = url.substring(0, url.indexOf('?'))
          }
          return true;
        }
        Toast.show("暂不支持此格式视频")
        return false;
      }
    
      /**
       * 正在进行中的任务
       *  {
       *    maxProgress: 100,
            progress: 0,
            status:0, // 0 运行中 -1 失败 2成功
            toFile:toFile,
       *  }
       */
      allRunningTask = new Map()
      listeners = new Set();
    
      addListener(listener = () => { }) {
        this.listeners.add(listener)
      }
    
      removeListener(listener = () => { }) {
        if (this.listeners.has(listener)) {
          this.listeners.delete(listener)
        }
      }
    
      /**
       * 观察者模式,对外发送通知
       */
      _updatelisteners() {
        for (let listener of this.listeners) {
          listener && listener();
        }
      }
    
      downLoad(data) {
        let result = this.checkSafeUrl(data);
        if (result) {
          this.startDownloadM3U8(data)
        }
      }
    
      resetDownLoad(data) {
        let result = this.checkSafeUrl(data);
        if (result) {
          if (this.allRunningTask.has(data.id)) {
            this.allRunningTask.delete(data.id)
          }
          this.startDownloadM3U8(data)
        }
      }
    
      /**
       * 开始下载m3u8文件
       * @param {*} url 
       */
      async startDownloadM3U8(data) {
        console.log('netlog-download', data.id)
        //已经存在了,直接return
        if (this.allRunningTask.has(data.id)) {
          if (this.allRunningTask.get(data.id).status == 0) {
            Toast.show("任务已经在下载队列中了,请不要重复下载")
            return;
          } else if (this.allRunningTask.get(data.id).status == 2) {
            Toast.show("您已经下载过该视频,请不要重复下载")
            return;
          }
        }
    
        //查询本地已经下载成功的视频
        let videos = await queryDownloadVideoAll();
        let keys = Object.keys(videos)
        let localFile;
        for (let i = 0; i < keys.length; i++) {
          let obj = videos[keys[i]]
          if (obj && obj.id == data.id) {
            localFile = obj.file;
          }
        }
    
        if (localFile) {
          let flag = await fs.exists(localFile)
          if (flag) {
            Toast.show("您已经下载过该视频,请不要重复下载")
            return;
          }
        }
    
        Toast.show("开始下载...")
    
        //根据url获取到对应的本地目录
        let url = data.url;
        let urlSplits = url.split("/");
        let scheme = urlSplits[0];
        let baseUrl = urlSplits[2];
        let path = urlSplits.slice(3, urlSplits.length - 1).join("/")
        let fileName = urlSplits[urlSplits.length - 1]
    
        let toDirPath = baseFile + "/" + path;
        await fs.mkdir(toDirPath)
        let toFile = toDirPath + "/" + fileName;
    
        data.maxProgress = 100;
        data.progress = 0;
        data.status = 0;
        data.toFile = toFile;
        data.file = toFile;
        //添加m3u8下载任务到缓存
        this.allRunningTask.set(data.id, data)
    
        //开始下载m3u8文件
        let task = fs.downloadFile({
          fromUrl: url,
          toFile: toFile,
          connectionTimeout: 1000 * 60,
          readTimeout: 1000 * 60,
          begin: function (res) {
          },
          progress: function (res) {
          },
        });
    
        let result = await task.promise
        if (result.statusCode == 200) {
          console.log('netlog-m3u8下载成功', toFile, url, result)
          try {
            //m3u8下载成功,开始逐步下载ts文件
            await this.readM3U8File(data, url, toFile, toDirPath)
            console.log('netlog-', '所有ts文件都下载成功了')
            //标记下载成功
            this.allRunningTask.get(data.id).status = 2;
            //写入本地数据库
            await writeDownloadVideo(data)
            console.log('netlog-', '插入本地数据库成功了')
            //删除内存中缓存
            this.allRunningTask.delete(data.id)
            Toast.show(data.title + "下载成功了,请到下载中心查看")
            //通知出去
            this._updatelisteners()
          } catch (error) {
            Toast.show("哎哟,下载出现了异常", error)
            console.log('netlog-', '哎哟,下载出现了异常', error)
            this.allRunningTask.get(data.id).status = -1;
            //通知出去
            this._updatelisteners()
          }
        } else {
          console.log('哎哟,下载出现了异常')
          Toast.show("哎哟,下载出现了异常")
          this.allRunningTask.get(data.id).status = -1;
          //通知出去
          this._updatelisteners()
        }
      }
    
      /**
       * 读取m3u8对应的内容,获取到对应的ts文件地址
       * @param {*} m3u8Url 
       * @param {*} m3u8File 
       * @param {*} m3u8Dir 
       */
      async readM3U8File(data, m3u8Url, m3u8File, m3u8Dir) {
        let result = await fs.readFile(m3u8File)
        let lines = result.split('
    ');
    
        let tsUrls = [];
        for (let line of lines) {
          if (line.endsWith('.ts') || line.indexOf("ts") > -1) {
            tsUrls.push(line)
          }
        }
        //设置最大进度,默认为ts文件数为单位
        this.allRunningTask.get(data.id).maxProgress = tsUrls.length;
        //开始下载ts文件
        await this.startDownloadTS(data, m3u8Url, tsUrls, 0, m3u8Dir);
      }
    
      /**
       * 开始下载ts文件
       * @param {*} m3u8Url 
       * @param {*} tsUrls 
       * @param {*} index 
       * @param {*} m3u8Dir 
       */
      async startDownloadTS(data, m3u8Url, tsUrls, index, m3u8Dir) {
        if (index >= tsUrls.length) {
          return;
        };
        // if (index >= 10) {
        //   return;
        // };
    
        let url = tsUrls[index];
        //如果ts文件中包含路径,当文件夹形式处理
        if (url.lastIndexOf("/") > -1) {
          let targetDir = m3u8Dir + "/" + url.substring(0, url.lastIndexOf('/'))
          let exists = await fs.exists(targetDir)
          if (!exists) {
            await fs.mkdir(targetDir)
          }
        }
    
        let downloadUrl = m3u8Url.substring(0, m3u8Url.lastIndexOf("/") + 1) + url;
        let toFile = m3u8Dir + "/" + url;
        let result = await this.createDownloadTSPromise(downloadUrl, toFile)
        console.log('netlog-ts下载成功了', toFile, downloadUrl, result)
    
        //刷新进度
        this.allRunningTask.get(data.id).progress = index + 1;
        //通知出去
        this._updatelisteners()
        await this.startDownloadTS(data, m3u8Url, tsUrls, index + 1, m3u8Dir)
      }
    
      /**
       * 创建ts下载任务
       * @param {*} url 
       * @param {*} file 
       */
      createDownloadTSPromise(url, file) {
        let task = fs.downloadFile({
          fromUrl: url,
          toFile: file,
          connectionTimeout: 1000 * 60,
          readTimeout: 1000 * 60,
          begin: function (res) {
          },
          progress: function (res) {
          },
        });
        return task.promise
      }
    
    }
    
    const DownloadManagerInstance = new DownloadManager()
    
    export default DownloadManagerInstance;
    

    //src/pages/QueryMoreVideoPage.js
    //点击进入查看更多页面
    import React from 'react'
    import {
        View,
        Text,
        Image,
        StyleSheet,
        ScrollView,
        TouchableOpacity
    } from 'react-native'
    import BaseFlatListComponent from '../components/BaseFlatListComponent'
    import Colors from '../utils/Colors'
    import data from '../../data.json'
    import config from '../../config.json'
    
    const itemWidth = Math.floor((DEVICE.width - 10) / 3);
    const itemHeight = Math.floor(itemWidth * 1.3)
    const finalStyle = {  itemWidth, height: itemHeight }
    
    //this.props.id 0推荐 1电影 2电视剧 3动漫 4综艺
    export default class QueryMoreVideoPage extends BaseFlatListComponent {
    
        pageSize = 18
        numColumns = 3;
    
        paramsArray = [];
    
        contentContainerStyle = { flexDirection: 'row', flexWrap: 'wrap' }
    
        static navigationOptions = options => {
            return {
                title: options.navigation.state.params.title
            }
        }
    
        _initListState() {
            return {
                classData: null,
            }
        }
    
        componentDidMount() {
            // let url = `/api/app/video/ver2/video/queryClassifyList/2/7?videoType=${this.props.navigation.state.params.id}`
            // axios.get(url).then(res => {
            //     for (let i = 0; i < res.data.data.length; i++) {
            //         let childList = res.data.data[i].childList;
            //         this.paramsArray.push(""); //默认为全部
            //         childList = childList.splice(0, 0, { classifyName: res.data.data[i].classifyName, id: "", selected: true })
            //     }
            //     //flag 1 最多播放 2最近更新 3最多喜欢 5最高评分
            //     res.data.data.push({
            //         childList: [
            //             { classifyName: '最多播放', id: 1 ,selected:true},
            //             { classifyName: '最近更新', id: 2 ,selected:false},
            //             { classifyName: '最多喜欢', id: 3 ,selected:false},
            //             { classifyName: '最高评分', id: 5 ,selected:false},
            //         ]
            //     })
            //     this.paramsArray.push(1);
            //     this.setState({ classData: res.data.data }, () => super.componentDidMount())
            // }).catch(error => {
            //     console.log('netlog-', error)
            //     super.componentDidMount()
            // })
    
            setTimeout(() => {
                let res = {data:data.ClassTypes}
                for (let i = 0; i < res.data.data.length; i++) {
                    let childList = res.data.data[i].childList;
                    this.paramsArray.push(""); //默认为全部
                    childList = childList.splice(0, 0, { classifyName: res.data.data[i].classifyName, id: "", selected: true })
                }
                //flag 1 最多播放 2最近更新 3最多喜欢 5最高评分
                res.data.data.push({
                    childList: [
                        { classifyName: '最多播放', id: 1 ,selected:true},
                        { classifyName: '最近更新', id: 2 ,selected:false},
                        { classifyName: '最多喜欢', id: 3 ,selected:false},
                        { classifyName: '最高评分', id: 5 ,selected:false},
                    ]
                })
                this.paramsArray.push(1);
                this.setState({ classData: res.data.data }, () => super.componentDidMount())
            }, config.delayed);
        }
    
        getRequestAction(pageIndex, pageSize) {
            return new Promise((resolve,reject) => {
                setTimeout(() => {
                    resolve({data:data.ClassMoreData})
                }, config.delayed);
            })
        }
    
        enterDetialPage = data => {
            data.videoInfoId = data.id;
            this.props.navigation.navigate("VideoInfoPage", { data })
        }
    
        getTagName(obj) {
            return obj.tagName == '无标签' ? null : obj.tagName
        }
    
        _getTagBackgroundColor = tag => {
            if (tag == "抢鲜") {
                return "#573D1B"
            } else if (tag == "1080P") {
                return "#C47F14";
            } else {
                return "red"
            }
        }
    
        renderHeaderItem(item, index) {
            return item.childList.map((child) => {
                let bgColor = child.selected ? Colors.mainColor : 'white'
                let tvColor = child.selected ? 'white' : 'black'
                return (
                    <TouchableOpacity
                        style={{ padding: 5, borderRadius: 5, justifyContent: 'center', alignItems: 'center', marginRight: 10, backgroundColor: bgColor }}
                        onPress={() => {
                            this.paramsArray[index] = child.id;
                            let data = [...this.state.classData]
                            for (let i = 0; i < data[index].childList.length; i++) {
                                let z = data[index].childList[i]
                                z.selected = z == child;
                            }
                            this.setState({ classData: data }, () => {
                                this.onRefresh()
                            })
                        }}
                        activeOpacity={0.7}>
                        <Text style={{ color: tvColor }}>{child.classifyName}</Text>
                    </TouchableOpacity>
                );
            })
        }
    
        renderFlatViewHeader = () => {
            if (!this.state.classData) return null;
            let views = this.state.classData.map((item, index) => {
                return (
                    <ScrollView
                        showsHorizontalScrollIndicator={false}
                        horizontal={true}
                        contentContainerStyle={{ alignItems: 'center' }}
                        style={{marginTop:5, paddingLeft: 10 }}>
                        {this.renderHeaderItem(item, index)}
                    </ScrollView>
                )
            })
            return (
                <View>
                    {views}
                </View>
            )
        }
    
        renderRow = (rowData, sectionID, rowID, highlightRow) => {
            let obj = rowData;
            let index = rowID + 1;
            let style = index % 3 == 2 ? {
                marginHorizontal: 5,
                 itemWidth,
                alignItems: 'center',
                marginTop: 10,
            } : {
                     itemWidth,
                    alignItems: 'center',
                    marginTop: 10,
                }
            let tagName = obj.tagName == '无标签' ? null : obj.tagName
            let tagBackgroundColor = this._getTagBackgroundColor(tagName)
            let complete = obj.episodeState == 1;
            let updateTag;
            if (complete) {
                if (obj.episodeUploadCount > 1) {
                    updateTag = "已完结";
                }
            } else {
                updateTag = obj.episodeUploadCount > 1 ? obj.type != 4 ? `更新至${obj.episodeUploadCount}集` : `更新至${obj.episodeUploadCount}期` : null;
            }
            let image = obj.coverUrl ? { uri: obj.coverUrl } : require('../../source/image/nor.png')
            let playCount = parseInt(obj.playCount)
            if (playCount > 10000) {
                playCount = (playCount / 10000).toFixed(1) + '万'
            }
            return (
                <TouchableOpacity
                    activeOpacity={0.7}
                    onPress={() => this.enterDetialPage(obj)}
                    style={style}>
                    <View style={finalStyle}>
                        <Image style={finalStyle} resizeMode="cover" source={image}></Image>
                        {tagName ? (
                            <View style={{ position: 'absolute', borderRadius: 2, backgroundColor: tagBackgroundColor, top: 5, right: 5, paddingHorizontal: 5 }}>
                                <Text style={{ color: 'white', fontSize: 12 }}>{tagName}</Text>
                            </View>
                        ) : null}
                        {updateTag ? (
                            <View style={{ position: 'absolute',  '100%', bottom: 0, paddingVertical: 5, backgroundColor: 'rgba(0,0,0,0.3)', alignItems: 'center', justifyContent: 'center' }}>
                                <Text style={{ color: 'white', fontSize: 12 }}>{updateTag}</Text>
                            </View>
                        ) : null}
                    </View>
                    <View style={{ paddingVertical: 5 }}>
                        <Text numberOfLines={1} style={{ textAlign: 'center' }}>{obj.title}</Text>
                        <Text numberOfLines={1} style={{ textAlign: 'center' }}>{playCount} 播放</Text>
                    </View>
                </TouchableOpacity>
            )
        }
    }
    
    ```js
    //src/pages/VideoListPage.js
    import React from 'react'
    import {
        View,
        Text,
        Image,
        StyleSheet,
        TouchableOpacity
    } from 'react-native'
    import BaseFlatListComponent from '../components/BaseFlatListComponent'
    import data from '../../data.json'
    import config from '../../config.json'
    
    const itemWidth = Math.floor((DEVICE.width - 10) / 3);
    const itemHeight = Math.floor(itemWidth * 1.3)
    const finalStyle = {  itemWidth, height: itemHeight }
    
    
    export default class VideoListPage extends BaseFlatListComponent {
    
        pageSize = 18
        numColumns = 3;
        enbaleRefresh = false;
    
        contentContainerStyle = { flexDirection: 'row', flexWrap: 'wrap' }
    
        static navigationOptions = options => {
            return {
                title: options.navigation.state.params.title
            }
        }
    
        getRequestAction(pageIndex, pageSize) {
            return new Promise((resolve,reject) => {
                setTimeout(() => {
                    resolve({data:data.MoreData})
                }, config.delayed);
            })
        }
    
        enterDetialPage = data => {
            this.props.navigation.navigate("VideoInfoPage", { data})
        }
    
        getTagName(obj) {
            return obj.tagName == '无标签' ? null : obj.tagName
        }
    
        _getTagBackgroundColor = tag => {
            if(tag == "抢鲜"){
                return "#573D1B"
            }else if(tag == "1080P"){
                return "#C47F14";
            }else{
                return "red"
            }
        }
    
        renderRow = (rowData, sectionID, rowID, highlightRow) => {
            let obj = rowData;
            let index = rowID + 1;
            let style = index % 3 == 2 ? {
                marginHorizontal: 5,
                 itemWidth,
                alignItems: 'center',
                marginTop: 10,
            } : {
                     itemWidth,
                    alignItems: 'center',
                    marginTop: 10,
                }
            let tagName = obj.tagName == '无标签' ? null : obj.tagName
            let tagBackgroundColor = this._getTagBackgroundColor(tagName)
            let complete = obj.episodeState == 1;
            let updateTag ;
            if(complete){
                if(obj.episodeUploadCount > 1){
                    updateTag = "已完结";
                }
            }else{
                updateTag = obj.episodeUploadCount > 1 ? obj.type != 4 ? `更新至${obj.episodeUploadCount}集` : `更新至${obj.episodeUploadCount}期` : null;
            }
            let image = obj.coverUrl ? {uri : obj.coverUrl} : require('../../source/image/nor.png')
            let playCount = parseInt(obj.playCount)
            if(playCount > 10000){
                playCount = (playCount / 10000).toFixed(1) + '万'
            }
            return (
                <TouchableOpacity
                    activeOpacity={0.7}
                    onPress={() => this.enterDetialPage(obj)}
                    style={style}>
                    <View style={finalStyle}>
                        <Image style={finalStyle} resizeMode="cover" source={image}></Image>
                        {tagName ? (
                            <View style={{ position: 'absolute', borderRadius: 2, backgroundColor: tagBackgroundColor, top: 5, right: 5, paddingHorizontal: 5 }}>
                                <Text style={{ color: 'white', fontSize: 12 }}>{tagName}</Text>
                            </View>
                        ) : null}
                        {updateTag ? (
                            <View style={{ position: 'absolute',  '100%', bottom: 0, paddingVertical: 5, backgroundColor: 'rgba(0,0,0,0.3)', alignItems: 'center', justifyContent: 'center' }}>
                                <Text style={{ color: 'white', fontSize: 12 }}>{updateTag}</Text>
                            </View>
                        ) : null}
                    </View>
                    <View style={{ paddingVertical: 5 }}>
                        <Text numberOfLines={1} style={{ textAlign: 'center' }}>{obj.title}</Text>
                        <Text numberOfLines={1} style={{ textAlign: 'center' }}>{playCount} 播放</Text>
                    </View>
                </TouchableOpacity>
            )
        }
    }
    

    //视频详情页
    //src/pages/VideoInfoPage.js
    import React from 'react'
    import { View, StyleSheet, ScrollView, Text, TouchableOpacity, Image, Share, ListView ,NativeModules,BackHandler} from 'react-native'
    import BaseComponent from '../components/BaseComponent'
    import VideoWrapper from '../views/VideoWrapper'
    import { writeHistoryVideo, queryCollectVideo, deleteCollectVideo, writeCollectVideo } from '../utils/DButils'
    import Colors from '../utils/Colors'
    import Toast from 'react-native-root-toast'
    import DownloadManager from '../utils/DownloadManager'
    import Loadding from '../components/Loadding'
    import data from '../../data.json'
    import config from '../../config.json'
    
    
    export default class VideoInfo extends BaseComponent {
    
        videoItemIndex = 0;
        params = {};
        state = {
            data: {},
            totalVideoList: [],
            isCollect: false,
            downloadComponentShow: false,
        }
    
        componentWillMount(){
            this.subscription = BackHandler.addEventListener("hardwareBackPress",this.onBack)
        }
    
        onBack = () => {
            if(this.state.downloadComponentShow){
                this.setState({downloadComponentShow:false})
                return true;
            }else{
                return false;
            }
        }
    
        async componentWillUnmount() {
            this.subscription && this.subscription.remove()
            this.hideLoadding()
            //事件回调
            this.scrollTask && clearTimeout(this.scrollTask)
            //存储播放记录
            let data = this.state.data;
            if (!data.title || !data.id || !data.coverUrl || !this.progressOption) return;
            let id = data.id;
            let name = data.title;
            let level = this.videoItemIndex;
            let progress = (this.progressOption.currentTime / this.progressOption.seekableDuration) * 100
            let coverUrl = data.coverUrl;
            let obj = { id, name, coverUrl, progress, level }
            await writeHistoryVideo(obj)
            this.props.navigation.state.params.onBack && this.props.navigation.state.params.onBack();
        }
    
        initData() {
            this.queryVideoCollect();
            setTimeout(() => {
                this.queryTotalVideoList(data.VideoInfoData.data);
            }, config.delayed);
        }
    
        queryVideoCollect() {
            let data = this.props.navigation.state.params.data
            queryCollectVideo(data).then(res => {
                if (Object.keys(res).length) {
                    this.setState({ isCollect: true })
                } else {
                    this.setState({ isCollect: false })
                }
            })
        }
    
        addVideoCollect() {
            let data = this.props.navigation.state.params.data
            writeCollectVideo(data).then(res => {
                this.queryVideoCollect();
            })
        }
    
        deleteVideoCollect() {
            let data = this.props.navigation.state.params.data
            deleteCollectVideo(data).then(res => {
                this.queryVideoCollect();
            })
        }
    
        queryTotalVideoList(data) {
            this.setState({ data, totalVideoList: data.videoList }, () => this.update(this.LOAD_SUCCESS, () => {
                if (this.params.history) {
                    this.scrollTask = setTimeout(() => {
                        let videoItemIndex = this.params.level;
                        this.listview && this.listview.scrollTo(0, 55 * videoItemIndex)
                    }, this.params.level * 10);
                }
            }))
        }
    
        _renderHeader() {
            let item = null
            //从播放历史进入
            if (this.params.history) {
                this.videoItemIndex = this.params.level;
            }
            if (this.state.totalVideoList.length) {
                item = this.state.totalVideoList[this.videoItemIndex]
            }
    
            return (
                <VideoWrapper
                    ref={ref => this.videoWrapper = ref}
                    item={item}
                    navigation={this.props.navigation}
                    seek={this.params.progress}
                    onProgress={options => this.progressOption = options}
                    onLoad={data => {
                        if (this.params.history) {
                            this.params.history = false;
                            this.params.progress = 0;
                        }
                    }}
                    onEnd={() => {
                        let data = this.state.data;
                        if (data.videoList[this.videoItemIndex + 1]) {
                            this.videoItemIndex += 1;
                            this.forceUpdate(() => this.videoWrapper.startPlayVideo());
                        }
                    }} />
            )
        }
    
        dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 })
        itemWidth = (DEVICE.width - 70) / 5;
    
        _renderVideoItems = () => {
            let data = this.state.totalVideoList;
            let dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 })
            if (data.length > 1) {
                return (
                    <View>
                        <Text style={{ color: 'black', fontSize: 16 }}>选集</Text>
                        <ListView
                            removeClippedSubviews={DEVICE.android ? true : false}
                            horizontal={true}
                            showsHorizontalScrollIndicator={false}
                            ref={ref => this.listview = ref}
                            contentContainerStyle={{ paddingVertical: 10 }}
                            initialListSize={this.params.history ? this.params.level + 10 : 10}
                            dataSource={dataSource.cloneWithRows(data)}
                            renderRow={(rowData, sectionID, rowID, highlightRow) => {
                                let index = parseInt(rowID)
                                let i = index + 1;
                                let color = this.videoItemIndex == index ? "#C47F14" : '#666666'
                                let text = this.state.data.type == 4 ? `第${i}期` : i;
                                return (
                                    <TouchableOpacity
                                        activeOpacity={0.7}
                                        onPress={() => {
                                            if (this.videoItemIndex !== index) {
                                                this.videoItemIndex = index;
                                                this.forceUpdate()
                                            }
                                        }}
                                        style={[styles.buttonStyle, {
                                            marginRight: 10,
                                            padding: 0,
                                            minWidth: 45,
                                            height: 45,
                                            justifyContent: 'center',
                                            alignItems: 'center'
                                        }]}>
                                        <Text style={{ color, fontSize: 15, fontWeight: 'bold' }}>{text}</Text>
                                    </TouchableOpacity>
                                );
                            }}>
                        </ListView>
                    </View>
                );
            } else {
                return null;
            }
        }
    
    
        renderComponent() {
            let data = this.state.data;
            let playCount = parseInt(data.playCount)
            if (playCount > 10000) {
                playCount = (playCount / 10000).toFixed(1) + '万'
            }
            return (
                <View style={{ flex: 1, backgroundColor: 'white' }}>
                    <ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 10 }}>
                        {this._renderVideoItems()}
    
                        <Text style={[styles.itemStyle, { fontSize: 18, color: 'black' }]}>{data.title}</Text>
                        <View style={styles.itemBetweenStyle}>
                            <Text>播放: {playCount}次</Text>
                            <Text style={[styles.buttonStyle, { backgroundColor: Colors.mainColor }]}>豆瓣: {data.imdbScore > 0 ? data.imdbScore : '6.0'}</Text>
                        </View>
                        <Text style={styles.itemStyle}>分类: {data.classifyTypeList.join('/')}</Text>
                        <Text style={styles.itemStyle}>导演: {data.director}</Text>
                        <Text style={styles.itemStyle}>演员: {data.staring}</Text>
                        <Text style={styles.itemStyle}>简介: </Text>
                        <Text style={[styles.itemStyle, { marginTop: 10 }]}>      {data.intro}</Text>
                    </ScrollView>
                </View>
            );
        }
    
        /**
         * 下载选集对应得component
         */
        _renderOther2() {
            if (!this.state.downloadComponentShow) return null;
    
            let data = this.state.totalVideoList;
            let dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 })
            if (data.length > 1) {
                return (
                    <View style={{ position: 'absolute', left: 0, right: 0, bottom: 0, top: 0, backgroundColor: 'white' }}>
                        <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', height: 45,paddingHorizontal:10 }}>
                            <Text style={{ color: 'black', fontSize: 16 }}>选集</Text>
                            <Text 
                                style={{ color: 'black', fontSize: 16 }}
                                onPress={() => this.setState({downloadComponentShow:false})}
                                >关闭</Text>
                        </View>
                        <ListView
                            showsVerticalScrollIndicator={false}
                            initialListSize={data.length}
                            ref={ref => this.listview = ref}
                            contentContainerStyle={{ flexDirection: 'row', justifyContent: 'flex-start', flexWrap: 'wrap',paddingLeft:10 }}
                            dataSource={dataSource.cloneWithRows(data)}
                            renderRow={(rowData, sectionID, rowID, highlightRow) => {
                                let index = parseInt(rowID)
                                let i = index + 1;
                                let color = '#666666'
                                let text = this.state.data.type == 4 ? `第${i}期` : i;
                                return (
                                    <TouchableOpacity
                                        activeOpacity={0.7}
                                        onPress={() => {
                                            this.downloadVideo(rowData,i)
                                        }}
                                        style={[styles.buttonStyle, {
                                             Math.floor((DEVICE.width - 50) / 4),
                                            height: 45,
                                            marginRight:10,
                                            justifyContent: 'center',
                                            alignItems: 'center',
                                            marginBottom:10,
                                        }]}>
                                        <Text style={{ color, fontSize: 15, fontWeight: 'bold' }}>{text}</Text>
                                    </TouchableOpacity>
                                );
                            }}>
                        </ListView>
                    </View>
                );
            } else {
                return null;
            }
        }
    
        _renderOther() {
            let collectImg = this.state.isCollect ? require('../../source/image/shoucang.png') : require('../../source/image/icon_shoucang.png')
            let collectText = this.state.isCollect ? "取消收藏" : "  收藏  "
            return (
                <View style={styles.bottomStyle}>
                    <TouchableOpacity
                        activeOpacity={0.7}
                        onPress={() => {
                            Share.share({
                                title: '来嘻哈影视,看免费高清大片',
                                message: '最新,最全,无广告,请上嘻哈影视 https://github.com/andmizi',
                                url: '最新,最全,无广告,请上嘻哈影视https://github.com/andmizi'
                            })
                        }}
                        style={{ flex: 1, alignItems: 'center' }}>
                        <Image style={styles.bottomImageStyle} resizeMode='contain' source={require('../../source/image/icon_share.png')}></Image>
                        <Text style={{ color: 'black' }}>分享</Text>
                    </TouchableOpacity>
                    <TouchableOpacity
                        activeOpacity={0.7}
                        onPress={() => {
                            if (this.state.isCollect) {
                                this.deleteVideoCollect();
                            } else {
                                this.addVideoCollect()
                            }
                        }}
                        style={{ flex: 1, alignItems: 'center' }}>
                        <Image style={styles.bottomImageStyle} resizeMode='contain' source={collectImg}></Image>
                        <Text style={{ color: 'black' }}>{collectText}</Text>
                    </TouchableOpacity>
                    <TouchableOpacity
                        activeOpacity={0.7}
                        onPress={() => {
                            let data = this.state.totalVideoList
                            if(data.length == 0) return;
                            if (data.length > 1) {
                                this.setState({ downloadComponentShow: true })
                            } else {
                                this.downloadVideo(data[0],-1)
                            }
                        }
                        }
                        style={{ flex: 1, alignItems: 'center' }}>
                        <Image style={styles.bottomImageStyle} resizeMode='contain' source={require('../../source/image/icon_down.png')}></Image>
                        <Text style={{ color: 'black' }}>缓存</Text>
                    </TouchableOpacity>
                </View>
            );
        }
    
        showLoadding() {
            this.hideLoadding()
            this.loadding = Loadding.show();
        }
    
        hideLoadding() {
            this.loadding && Loadding.hide(this.loadding)
        }
    
        /**
         * 开始下载
         * @param {*} data 
         */
        startDownloadVideo(data,index){
            // let qualityMap = new Map();
            // if (data.m3u8Format['1080P']) {
            //     qualityMap.set('1080P', data.m3u8Format['1080P'])
            // }
            // if (data.m3u8Format['720P']) {
            //     qualityMap.set('720P', data.m3u8Format['720P'])
            // }
            // if (data.m3u8Format['480P']) {
            //     qualityMap.set('480P', data.m3u8Format['480P'])
            // }
            // if (data.m3u8Format['360P']) {
            //     qualityMap.set('360P', data.m3u8Format['360P'])
            // }
            // if (data.m3u8Format['free'] && data.freeShow) {
            //     qualityMap.set('free', data.m3u8Format['free'])
            // }
    
            // let playUrl = data.m3u8PlayUrl;
            // //默认取第一个
            // let arr = Array.from(qualityMap.keys());
            // let videoQuality = arr[0]
            // let url = playUrl + qualityMap.get(videoQuality);
    
            // console.log('netlog-',data.id,url)
            this.hideLoadding()
    
            // properties: {
            //     id:"int",
            //     url: 'string', //以url为准
            //     title:'string', //视频名称
            //     index:'int', //集数
            //     coverUrl:'string', //视频封面
            //     file:'string', //本地存储路径,m3u8文件
            //     playCount:'string',//播放次数
            //     imdbScore:'int',//豆瓣评分
            //     director:'string',//导演
            //     staring:'string',//演员
            //     intro:'string', //简介
            //     type:'int',//类型 电影 电视剧 动漫 综艺
            // }
            let params = Object.assign({},this.state.data)
            params.url = data;
            params.index = index;
            params.id = data.id;
            params.classifyTypeListValue = params.classifyTypeList.join('/')
            
            DownloadManager.downLoad(params)
        }
    
        /**
         * 开始下载视频
         * @param {*} data 
         */
        downloadVideo(data,index) {
            this.showLoadding()
            setTimeout(() => {
                this.startDownloadVideo(config.videoUrl,index)
            }, config.delayed);
        }
    }
    
    var styles = StyleSheet.create({
        itemBetweenStyle: {
            flexDirection: 'row',
            alignItems: 'center',
            justifyContent: 'space-between',
            minHeight: 40,
        },
        itemStyle: {
            flexDirection: 'row',
            alignItems: 'center',
            minHeight: 30,
            textAlignVertical: 'center'
        },
        buttonStyle: {
            backgroundColor: '#EFF0EB',
            borderRadius: 5,
            paddingHorizontal: 10,
            paddingVertical: 5,
            textAlign: 'center',
            textAlignVertical: 'center',
            color: 'white'
        },
        bottomStyle: {
            flexDirection: 'row',
            height: 45,
            alignItems: 'center'
        },
        bottomImageStyle: {
             20,
            height: 20
        }
    })
    
    //src/pages/VIPPage.js
    //vip页面
    import React from 'react'
    import { Text } from 'react-native'
    import BaseComponent from '../components/BaseComponent';
    import ScrollableTabView, { DefaultTabBar } from 'react-native-scrollable-tab-view'
    import Colors from '../utils/Colors'
    import VIPTabListPage from './VIPTabListPage'
    
    export default class VIPPage extends BaseComponent {
    
        state = {
            data: []
        }
    
        initData(pageIndex, pageSize) {
            let url = "/api/app/video/ver2/video/queryColumnDataSmall/2/7?modelName=4"
            axios.get(url).then(res => {
                let data = res.data
                if (data.success) {
                    if (data.data && data.data.length) {
                        this.setState({ data: data.data }, () => this.update(this.LOAD_SUCCESS))
                    } else {
                        this.update(this.LOAD_EMPTY)
                    }
                } else {
                    this.update(this.LOAD_FAILED)
                }
            }).catch(error => {
                console.log('netlog-', error)
                this.update(this.LOAD_FAILED)
            })
        }
    
        _renderPages = () => {
            return this.state.data.map(item => {
                return (
                    <VIPTabListPage
                        navigation={this.props.navigation}
                        tabLabel={item.title}
                        id={item.columnId}>
                    </VIPTabListPage>
                );
            })
        }
    
        renderComponent() {
            return (
                <ScrollableTabView
                    renderTabBar={() =>
                        <DefaultTabBar
                            tabStyle={{ backgroundColor: 'white', justifyContent: 'center', alignItems: 'center' }}
                            underlineStyle={{ backgroundColor: 'transparent', height: 0 }}
                        />
                    }
                    locked={true}
                    tabBarPosition='top'
                    tabBarTextStyle={{
                        fontSize: DEVICE.ios_OS ? 17 : 20,
                        fontWeight: DEVICE.ios_OS ? '600' : '500',
                    }}
                    tabBarActiveTextColor={Colors.mainColor}
                    ref={(tabView) => { this.tabView = tabView }}>
    
                    {this._renderPages()}
    
                </ScrollableTabView>
            );
        }
    }
    
    //src/pages/AboutPage.js
    import React from 'react'
    import {
        Text,
        View,
        Image,
        ScrollView
    } from 'react-native'
    
    export default class AboutPage extends React.Component {
    
        render() {
            return (
                <View style={{ flex: 1, backgroundColor: 'white', justifyContent: 'center', alignItems: 'center', padding: 10 }}>
    
                    <Text>影视爱好者,为广大网友提供免费的,高质量的影视作品</Text>
                    <Text style={{ marginTop: 5 }}>如有侵权,请联系告知~</Text>
    
                </View>
            )
        }
    }
    
    //src/pages/HelpPage.js
    import React from 'react'
    import {
        Text,
        View,
        Image,
        ScrollView
    } from 'react-native'
    
    export default class HelpPage extends React.Component{
    
        render(){
            return (
                <ScrollView
                    contentContainerStyle={{flex:1,padding:10,backgroundColor:'white'}} 
                    showsVerticalScrollIndicator={false}>
                    <View style={{height:40,justifyContent:'center'}}>
                        <Text style={{color:'red'}}>1.无法播放视频</Text>
                    </View>
                    <Text>如果出现某些视频无法播放,包含一直缓冲,闪退,网络异常,请尝试多打开几次,如果还是无法播放,请联系我们的客服进行反馈。</Text>
                    
                    <View style={{height:40,justifyContent:'center',marginTop:10}}>
                        <Text style={{color:'red'}}>2.搜索不到想看的视频</Text>
                    </View>
                    <Text>由于版权的原因,某些视频暂时无法提供,请联系我们的客服进行反馈。</Text>
    
                    <View style={{height:40,justifyContent:'center',marginTop:10}}>
                        <Text style={{color:'red'}}>3.界面展示异常</Text>
                    </View>
                    <Text>界面展示异常,不美观或适配遇到问题,请联系我们的客服进行反馈。</Text>
    
                    <View style={{height:40,justifyContent:'center',marginTop:10}}>
                        <Text style={{color:'red'}}>4.图标加载不出来</Text>
                    </View>
                    <Text>Android:如果遇到启动页图片,返回按键图标加载不出来,请到设置-应用程序-嘻哈影视-存储-清空数据。</Text>
                </ScrollView>
            )
        }
    }
    
    //src/pages/PersonCenterPage.js
    import React from 'react'
    import {
        Text,
        View,
        Image,
        TouchableOpacity,
        StyleSheet,
        ScrollView,
        Share,
        ImageBackground,
        StatusBar,
        Alert
    } from 'react-native'
    import BaseComponent from '../components/BaseComponent'
    import SetingItem from '../views/SettingItem'
    import { queryAllHistoryVideo, clearAllHistoryVideo } from '../utils/DButils'
    import { HeaderItem, appBarPaddingTop } from '../components/Header'
    import Toast from 'react-native-root-toast'
    import Colors from '../utils/Colors'
    
    const itemWidth = Math.floor((DEVICE.width - 40) / 4);
    const itemHeight = Math.floor(itemWidth * 1.1)
    const finalStyle = {  itemWidth, height: itemHeight }
    
    export default class PersonCenterPage extends BaseComponent {
    
        state = {
            historyVideo: [],
        }
    
        initData(){
            queryAllHistoryVideo().then(res => {
                let result = [];
                for(let key in res){
                    result.push(res[key])
                }
                this.setState({historyVideo:result},() => this.update(this.LOAD_SUCCESS))
            })
        }
    
        _onBack = () => {
            this.initData();
        }
    
        enterDetialPage = data => {
            data.videoInfoId = data.id;
            data.title = data.name;
            data.history = true;
            let params = Object.assign({},data)
            this.props.navigation.navigate("VideoInfoPage", { data:params, onBack: this._onBack })
        }
    
        _clearAllHistoryVideo = () => {
            clearAllHistoryVideo().then(res => {
                this.setState({historyVideo:[]})
            })
        }
    
        renderComponent() {
            console.log('netlog-item',this.state.historyVideo.length)
            let historyVideoViews = []
            for (let i = this.state.historyVideo.length - 1; i >= 0; i--) {
                if(historyVideoViews.length >= 30) break;
                let obj = this.state.historyVideo[i + ""];
                console.log('netlog-item',obj)
                let item = (
                    <TouchableOpacity
                        key={'history_' + i}
                        activeOpacity={0.7}
                        style={{ marginRight: 10 }}
                        onPress={() => this.enterDetialPage(obj)}>
                        <Image
                            style={[finalStyle]}
                            resizeMode="cover"
                            source={{ uri: obj.coverUrl }}></Image>
                        <Text
                            style={{  finalStyle.width, paddingVertical: 5, textAlign: 'center' }}
                            numberOfLines={1}>{obj.name}</Text>
                        <Text
                            style={{  finalStyle.width, textAlign: 'center' }}
                            numberOfLines={1}>观看至%{obj.progress}</Text>
                    </TouchableOpacity>
                );
                historyVideoViews.push(item)
            }
    
            let imageheight = DEVICE.width / 1.7;
            return (
                <ScrollView
                    contentContainerStyle={{ paddingBottom: 50 }}
                    style={{ backgroundColor: "#F1F1F1" }}>
                    <ImageBackground
                        source={require('../../source/image/profile_bg.png')}
                        resizeMode='cover'
                        style={{ justifyContent: 'center',  '100%', height: imageheight, alignItems: 'center', backgroundColor: 'white' }}>
                        {/* <Image source={require('../../source/image/profile_icon.png')}></Image> */}
                        <HeaderItem
                            onClick={() => this.props.navigation.goBack()}
                            style={{ position: 'absolute', left: 0, top: appBarPaddingTop }}>
                            <Image
                                resizeMode='contain'
                                style={{  25, height: 25 }}
                                source={require('../../source/image/player_return.png')}></Image>
                        </HeaderItem>
                    </ImageBackground>
    
                    <View style={{ flexDirection: 'row', paddingVertical: 10, backgroundColor: 'white' }}>
                        <TouchableOpacity
                            activeOpacity={0.7}
                            onPress={() => {
                                Toast.show('正在努力开发中...')
                            }}
                            style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                            <Image style={{  25, height: 25 }} resizeMode='contain' source={require('../../source/image/icon_mine_vip.png')}></Image>
                            <Text style={{ marginTop: 5, color: 'black' }}>神秘大片</Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            activeOpacity={0.7}
                            onPress={() => this.props.navigation.navigate("DownloadPage")}
                            style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                            <Image style={{  25, height: 25 }} resizeMode='contain' source={require('../../source/image/down.png')}></Image>
                            <Text style={{ marginTop: 5, color: 'black' }}>下载中心</Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            activeOpacity={0.7}
                            onPress={() => this.props.navigation.navigate('MyCollectPage') }
                            style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                            <Image style={{  25, height: 25 }} resizeMode='contain' source={require('../../source/image/shoucang.png')}></Image>
                            <Text style={{ marginTop: 5, color: 'black' }}>我的收藏</Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                            activeOpacity={0.7}
                            onPress={() => {
                                Toast.show('正在努力开发中...')
                            }}
                            style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                            <Image style={{  25, height: 25 }} resizeMode='contain' source={require('../../source/image/more.png')}></Image>
                            <Text style={{ marginTop: 5, color: 'black' }}>更多功能</Text>
                        </TouchableOpacity>
                    </View>
    
                    {historyVideoViews && historyVideoViews.length ? (
                        <View style={{ backgroundColor: 'white', marginTop: 10 }}>
                            <View style={{ flexDirection: 'row', alignItems: 'center', marginVertical: 10, paddingHorizontal: 10, justifyContent: 'space-between' }}>
                                <View style={{ flexDirection: 'row', alignItems: 'center' }}>
                                    <View style={{  3, height: 15, backgroundColor: "black" }}></View>
                                    <Text style={{ color: 'black', fontSize: 15, marginLeft: 5 }}>播放记录</Text>
                                </View>
                                <Text onPress={this._clearAllHistoryVideo}>清空记录</Text>
    
                            </View>
                            <ScrollView
                                showsHorizontalScrollIndicator={false}
                                horizontal={true}
                                contentContainerStyle={{ paddingLeft: 10, paddingBottom: 20 }}>
                                {historyVideoViews}
                            </ScrollView>
                        </View>
                    ) : null}
                    {/* 新手帮助页面 */}
                    <SetingItem style={{ marginTop: 10 }} onClick={() => { this.props.navigation.navigate('HelpPage') }} options={{ key: '新手帮助', value: '', hasArrow: true }}></SetingItem>
                    <SetingItem
                        onClick={() => {
                            Share.share({
                                title: '来嘻哈影视,看免费高清大片',
                                message: '最新,最全,无广告,请上嘻哈影视 https://github.com/andmizi',
                                url: '最新,最全,无广告,请上嘻哈影视https://github.com/andmizi'
                            })
                        }}
                        options={{ key: '分享给好友', value: '', hasArrow: true }}></SetingItem>
                </ScrollView>
            );
        }
    }
    
    const styles = StyleSheet.create({
    
    })
    
    //src/pages/SearchInfoPage.js
    //看不出来是做的什么
    import React from 'react'
    import {
        Text,
        View,
        Image,
        TouchableOpacity,
        StyleSheet
    } from 'react-native'
    import BaseFlatListComponent from '../components/BaseFlatListComponent'
    import Colors from '../utils/Colors'
    import data from '../../data.json'
    import config from '../../config.json'
    
    export default class SearchInfoPage extends BaseFlatListComponent {
    
        enbaleRefresh = false;
    
        static navigationOptions = options => {
            return {
                title: options.navigation.state.params.key
            }
        }
    
        filterResponse(result) {
            return result.data.data.map(item => {
                item.title = item.title.replace(/{/g, "").replace(/}/g, "").replace(/,/g, "");
                return item;
            })
    
        }
    
        getRequestAction(pageIndex, pageSize) {
            return new Promise((resolve,reject) => {
                setTimeout(() => {
                    resolve({data:data.ClassMoreData})
                }, config.delayed);
            })
        }
    
        enterDetialPage = data => {
            data.videoInfoId = data.id;
            this.props.navigation.navigate("VideoInfoPage", { data })
        }
    
        _getTagBackgroundColor = tag => {
            if(tag == "抢鲜"){
                return "#573D1B"
            }else if(tag == "1080P"){
                return "#C47F14";
            }else{
                return "red"
            }
        }
    
        renderRow = rowdata => {
            let tagName = rowdata.tagName == '无标签' ? null : rowdata.tagName
            let tagBackgroundColor = this._getTagBackgroundColor(tagName)
            let complete = rowdata.episodeState == 1;
            let updateTag;
            if(complete){
                if(rowdata.episodeUploadCount > 1){
                    updateTag = "已完结";
                }
            }else{
                updateTag = rowdata.episodeUploadCount > 1 ? rowdata.type != 4 ? `更新至${rowdata.episodeUploadCount}集` : `更新至${rowdata.episodeUploadCount}期` : null;
            }        
            let image = rowdata.coverUrl ? {uri : rowdata.coverUrl} : require('../../source/image/nor.png')
            let playCount = parseInt(rowdata.playCount)
            if(playCount > 10000){
                playCount = (playCount / 10000).toFixed(1) + '万'
            }
            return (
                <TouchableOpacity
                    activeOpacity={0.7}
                    onPress={() => this.enterDetialPage(rowdata)}
                    style={styles.itemStyle}>
                    <View style={{  120, height: 80 }}>
                        <Image style={{ 120, height: 80 }} resizeMode="cover" source={image}></Image>
                        {tagName ? (
                            <View style={{ position: 'absolute', borderRadius: 2, backgroundColor: tagBackgroundColor, top: 5, right: 5, paddingHorizontal: 5 }}>
                                <Text style={{ color: 'white', fontSize: 12 }}>{tagName}</Text>
                            </View>
                        ) : null}
                        {updateTag ? (
                            <View style={{ position: 'absolute',  '100%', bottom: 0, paddingVertical: 5, backgroundColor: 'rgba(0,0,0,0.3)', alignItems: 'center', justifyContent: 'center' }}>
                                <Text style={{ color: 'white', fontSize: 12 }}>{updateTag}</Text>
                            </View>
                        ) : null}
                    </View>
                    <View style={{ flex: 1, height: 80, justifyContent: 'space-between', marginLeft: 10 }}>
                        <Text numberOfLines={1}>{rowdata.title}</Text>
                        <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
                            <Text>播放{playCount}次</Text>
                            <Text style={styles.buttonStyle}>豆瓣: {rowdata.doubanScore > 0 ? rowdata.doubanScore : '6.0'}</Text>
                        </View>
                    </View>
                </TouchableOpacity>
            );
        }
    
    }
    
    const styles = StyleSheet.create({
        itemStyle: {
            flexDirection: 'row',
            alignItems: 'center',
            padding: 10,
            height: 100,
        },
        buttonStyle: {
            backgroundColor: Colors.mainColor,
            borderRadius: 5,
            paddingHorizontal: 10,
            paddingVertical: 5,
            textAlign: 'center',
            textAlignVertical: 'center',
            color: 'white'
        }
    })
    

    //src/pages/SearchPage.js
    import React from 'react'
    import {
        Text,
        View,
        Image,
        TouchableOpacity,
        TextInput,
        StyleSheet,
        ScrollView
    } from 'react-native'
    import Header, { HeaderItem } from '../components/Header'
    import BaseComponent from '../components/BaseComponent'
    import { writeHistorySearchContent, queryAllHistorySearchContent, clearAllHistorySearchConten } from '../utils/DButils'
    import Colors from '../utils/Colors'
    import Toast from 'react-native-root-toast'
    import data from '../../data.json'
    import config from '../../config.json'
    
    const backIcon = require('../../source/icons/back_icon.png')
    const itemWidth = (DEVICE.width - 20) / 2;
    
    export default class SearchPage extends BaseComponent {
    
        state = {
            datas: data.HotSearchData.data,
            historyContents: {},
            content: '',
            LOAD_STATE:this.LOAD_SUCCESS
        }
    
        initData() {
            this.queryHistoryVideo()
        }
    
        /**
         * 查询搜索历史记录
         */
        queryHistoryVideo(){
            queryAllHistorySearchContent().then(res => {
                this.setState({historyContents:res})
            })
        }
    
        enterSearchInfo(key, flag) {
            if (key) {
                if (flag) {
                    writeHistorySearchContent(key).then(res => {
                        this.queryHistoryVideo();
                    }).catch(error => {
                        console.log("netlog-",error)
                    })
                }
                this.props.navigation.navigate('SearchInfoPage', { key })
            }
        }
    
        _clearAllHistorySearchContens = () => {
            clearAllHistorySearchConten().then(res => {
                this.setState({historyContents:{}})
            })
        }
    
        _renderHeader() {
            return (
                <Header>
                    <HeaderItem onClick={() => this.props.navigation.goBack()}>
                        <Image source={backIcon}></Image>
                    </HeaderItem>
                    <TextInput
                        autoFocus={true}
                        numberOfLines={1}
                        onChangeText={text => this.setState({ content: text })}
                        maxLength={20}
                        placeholder="搜一搜,全都有"
                        returnKeyType="search"
                        onSubmitEditing={e => this.enterSearchInfo(e.nativeEvent.text,true)}
                        underlineColorAndroid='transparent'
                        style={{ flex: 1, height: 35, padding: 0, borderRadius: 5, backgroundColor: 'rgba(0,0,0,0.1)', justifyContent: 'center', alignItems: 'center', textAlign: 'center' }}>
                    </TextInput>
                    <HeaderItem onClick={() => this.enterSearchInfo(this.state.content, true)}>
                        <Text style={{ fontSize: 15, color: 'black', fontWeight: 'bold' }}>搜索 </Text>
                    </HeaderItem>
                </Header>
            );
        }
    
        renderComponent() {
            let keys = []
            keys = Object.keys(this.state.historyContents).reverse();
            keys.splice(10, keys.length);
            let showHistoryContents = keys.length > 0
           
            return (
                <ScrollView contentContainerStyle={{ padding: 10 }}>
                    {
                        showHistoryContents ? (
                            <View style={{ marginBottom: 15 }}>
                                <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginVertical: 10 }}>
                                    <View style={{ flexDirection: 'row', alignItems: 'center' }}>
                                        <View style={{  3, height: 15, backgroundColor: 'black' }}></View>
                                        <Text style={{ color: 'black', fontSize: 15, marginLeft: 5 }}>历史搜索</Text>
                                    </View>
                                    <Text onPress={this._clearAllHistorySearchContens}>清空记录</Text>
                                </View>
                                <View style={{ flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', }}>
                                    {
                                        keys.map((key, index) => {
                                            let item = this.state.historyContents[key]
                                            return (
                                                <Text
                                                    key={'search_children_' + index}
                                                    onPress={() => this.enterSearchInfo(item.name, true)}
                                                    numberOfLines={1}
                                                    style={{ fontSize: 15, margin: 5, padding: 5, color: 'white', backgroundColor: Colors.mainColor, borderRadius: 4 }}>{item.name}
                                                </Text>
                                            );
                                        })
                                    }
                                </View>
                            </View>
                        ) : null
                    }
    
                    <View style={{ flexDirection: 'row', alignItems: 'center', marginVertical: 10 }}>
                        <View style={{  3, height: 15, backgroundColor: 'black' }}></View>
                        <Text style={{ color: 'black', fontSize: 15, marginLeft: 5 }}>热门搜索</Text>
                    </View>
                    <View style={styles.container}>
                        {
                            this.state.datas.map((item) => {
                                return (
                                    <TouchableOpacity
                                        key={'search_' + item.id}
                                        style={{  itemWidth, marginVertical: 5, flexDirection: 'row', alignItems: 'center' }}
                                        onPress={() => this.enterSearchInfo(item.keyword, false)}
                                        activeOpacity={0.7}>
                                        <Text style={{ fontSize: 15 }}>{item.orderNum} </Text>
                                        <Text numberOfLines={1} style={{ fontSize: 15, marginLeft: 5 }}>{item.keyword}</Text>
                                    </TouchableOpacity>
                                );
                            })
                        }
                    </View>
                </ScrollView>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flexDirection: 'row',
            flexWrap: 'wrap',
            justifyContent: 'space-between'
        }
    })
    
    //src/pages/VarietyPage.js
    import React from 'react'
    import { DeviceEventEmitter } from 'react-native'
    import BaseFlatListComponent from '../components/BaseFlatListComponent'
    import Banner from '../views/Banner'
    import ListItem from '../views/ListItem'
    import MainTabNavigatorHeader from '../views/MainTabNavigatorHeader'
    import data from '../../data.json'
    import config from '../../config.json'
    
    export default class VarietyPage extends BaseFlatListComponent {
    
        pageSize = 4;
    
        _renderHeader() {
            return <MainTabNavigatorHeader
                onRightClick={() => {
                    this.props.navigation.navigate('QueryMoreVideoPage', { id: 4, title: '综艺' })
                }}
                rightIcon={require('../../source/image/sx_icon.png')}
                navigation={this.props.navigation} />
        }
    
        getRequestAction(pageIndex, pageSize) {
            return new Promise((resolve,reject) => {
                setTimeout(() => {
                    resolve({data:data.VarietyPageData})
                }, config.delayed);
            })
        }
    
        filterResponse(result) {
            return result.data.data;
        }
    
        renderFlatViewHeader = () => {
            return <Banner id={4} navigation={this.props.navigation}></Banner>
        }
    
        renderRow = rowData => {
            return (
                <ListItem navigation={this.props.navigation} data={rowData}></ListItem>
            );
        }
    }
    

    //初始首页
    
    import React from 'react'
    import { ScrollView, View, Text, Image, Alert, BackHandler, DeviceEventEmitter } from 'react-native'
    import { StackNavigator, TabNavigator, NavigationActions, DrawerNavigator, DrawerItems } from 'react-navigation'
    //
    import { HeaderItem } from './src/components/Header'
    import Toast from 'react-native-root-toast'
    import SplashPage from './src/pages/SplashPage'
    //推荐页面
    import RecommendPage from './src/pages/RecommendPage'
    //电影页面
    import MoviePage from './src/pages/MoviePage'
    //迷惑了不知道是做什么的了
    import TVPage from './src/pages/TVPage'
    //这个居然还是类似的组件,说明里面有优化空间
    import CartoonPage from './src/pages/CartoonPage'
    //封装的组件页面
    import VarietyPage from './src/pages/VarietyPage'
    //搜索页面
    import SearchPage from './src/pages/SearchPage'
    //不知道干啥的
    import SearchInfoPage from './src/pages/SearchInfoPage'
    //个人中心页面
    import PersonCenterPage from './src/pages/PersonCenterPage'
    //help页面
    import HelpPage from './src/pages/HelpPage'
    //关于页面
    import AboutPage from './src/pages/AboutPage'
    //vip页面
    import VIPPage from './src/pages/VIPPage'
    //视频详情页
    import VideoInfoPage from './src/pages/VideoInfoPage'
    //
    import VideoListPage from './src/pages/VideoListPage'
    //
    import MyCollectPage from './src/pages/MyCollectPage'
    //带你进入查询更多视频页面
    import QueryMoreVideoPage from './src/pages/QueryMoreVideoPage'
    //下载的方法
    import DownloadPage from './src/pages/DownloadPage'
    //进入的是单个的视频页面
    import OfflineVideoPlayer from './src/pages/OfflineVideoPlayer'
    //定义了根搜索
    import MainTabNavigatorHeader from './src/views/MainTabNavigatorHeader'
    
    import Colors from './src/utils/Colors'
    
    const TabNav = TabNavigator({
      Recommend: {
        screen: RecommendPage,
        navigationOptions: {
          tabBarLabel: options => {
            return <Text style={{ color: options.tintColor }}>推荐</Text>
          },
          tabBarIcon: options => {
            let img = options.focused ? require('./source/image/main_choice_click.png') : require('./source/image/main_choice.png')
            return <Image source={img}></Image>
          },
          tabBarOnPress: obj => {
            DeviceEventEmitter.emit("Recommend");
            obj.jumpToIndex(obj.scene.index)
          },
        }
      },
      Movie: {
        screen: MoviePage,
        navigationOptions: {
          tabBarLabel: options => {
            return <Text style={{ color: options.tintColor }}>电影</Text>
          },
          tabBarIcon: options => {
            let img = options.focused ? require('./source/image/main_movie_click.png') : require('./source/image/main_movie.png')
            return <Image source={img} ></Image>
          },
          tabBarOnPress: obj => {
            DeviceEventEmitter.emit("Movie");
            obj.jumpToIndex(obj.scene.index)
          },
        }
      },
      TV: {
        screen: TVPage,
        navigationOptions: {
          tabBarLabel: options => {
            return <Text style={{ color: options.tintColor }}>电视剧</Text>
          },
          tabBarIcon: options => {
            let img = options.focused ? require('./source/image/main_tv_click.png') : require('./source/image/main_tv.png')
            return <Image source={img} ></Image>
          },
          tabBarOnPress: obj => {
            DeviceEventEmitter.emit("TV");
            obj.jumpToIndex(obj.scene.index)
          },
        }
      },
      Cartoon: {
        screen: CartoonPage,
        navigationOptions: {
          tabBarLabel: options => {
            return <Text style={{ color: options.tintColor }}>动漫</Text>
          },
          tabBarIcon: options => {
            let img = options.focused ? require('./source/image/icon_cartoon_nor_click.png') : require('./source/image/icon_cartoon_nor.png')
            return <Image source={img} ></Image>
          },
          tabBarOnPress: obj => {
            DeviceEventEmitter.emit("Cartoon");
            obj.jumpToIndex(obj.scene.index)
          },
        }
      },
      Variety: {
        screen: VarietyPage,
        navigationOptions: {
          tabBarLabel: options => {
            return <Text style={{ color: options.tintColor }}>综艺</Text>
          },
          tabBarIcon: options => {
            let img = options.focused ? require('./source/image/icon_variety_nor_click.png') : require('./source/image/icon_variety_nor.png')
            return <Image source={img} ></Image>
          },
          tabBarOnPress: obj => {
            DeviceEventEmitter.emit("Variety");
            obj.jumpToIndex(obj.scene.index)
          },
        }
      },
      // VIP: {
      //   screen: VIPPage,
      //   navigationOptions: {
      //     tabBarLabel: options => {
      //       return <Text style={{ color: options.tintColor }}>神秘大片</Text>
      //     },
      //     tabBarIcon: options => {
      //       let img = options.focused ? require('./source/image/main_tv_click.png') : require('./source/image/main_tv.png')
      //       return <Image style={{  dp(55), height: dp(55) }} source={img} resizeMode="cover"></Image>
      //     },
      //   }
      // }
    }, {
        tabBarPosition: 'bottom',
        lazy: true,
        swipeEnabled: false,
        animationEnabled: false,
        initialRouteName: "Recommend",
        removeClippedSubviews: DEVICE.android ? true : false,
        tabBarOptions: {
          activeTintColor: Colors.mainColor,
          inactiveTintColor: Colors.mainColor,
          showIcon: true,
          showLabel: true,
          style: {
            backgroundColor: 'white',
            elevation: 5,
          },
          indicatorStyle: {
            height: 0
          }
        }
      });
    
    const RootNav = StackNavigator({
      Splash: {
        screen: SplashPage,
        navigationOptions: {
          header: null
        }
      },
      Root: {
        screen: TabNav,
        navigationOptions: function (options) {
          return {
            header: null,
            headerLeft: null
          }
        }
      },
      VideoInfoPage: {
        screen: VideoInfoPage,
        navigationOptions: {
          header: null
        }
      },
      VideoListPage: {
        screen: VideoListPage,
      },
      SearchPage: {
        screen: SearchPage,
        navigationOptions: {
          header: null
        }
      },
      SearchInfoPage: {
        screen: SearchInfoPage,
      },
      PersonCenterPage: {
        screen: PersonCenterPage,
        navigationOptions: {
          header: null
        }
      },
      HelpPage: {
        screen: HelpPage,
        navigationOptions: {
          title: "新手帮助"
        }
      },
      AboutPage: {
        screen: AboutPage,
        navigationOptions: {
          title: "关于我们"
        }
      },
      MyCollectPage: {
        screen: MyCollectPage,
        navigationOptions: {
          title: "我的收藏"
        }
      },
      QueryMoreVideoPage: {
        screen: QueryMoreVideoPage,
      }, 
      DownloadPage:{
        screen:DownloadPage,
        navigationOptions : {
          title: "下载中心"
        }
      },
      OfflineVideoPlayer:{
        screen:OfflineVideoPlayer,
        navigationOptions : {
          header: null
        }
      },
    }, {
        initialRouteName: "Splash",
        cardStyle: {
        },
        navigationOptions: function (options) {
          return {
            headerLeft: <HeaderItem onClick={() => options.navigation.goBack()}><Image source={require('./source/icons/back_icon.png')}></Image></HeaderItem>
          }
        }
      });
    
    const defaultStateAction = RootNav.router.getStateForAction;
    RootNav.router.getStateForAction = (action, state) => {
      if (DEVICE.android && state && action.type === NavigationActions.BACK && state.routes.length === 1) {
        Alert.alert('提示', '确定要退出吗?', [{ text: '取消', onPress: () => { } },
        {
          text: '退出', onPress: () => {
            BackHandler.exitApp();
          }
        }]);
        const routes = [...state.routes];
        return {
          ...state,
          ...state.routes,
          index: routes.length - 1,
        };
      } else {
        return defaultStateAction(action, state);
      }
    };
    
    
    
    import { TestPage } from './src/TestPage'
    
    export default RootNav;
    

    //src/views/Banner.js
    import React from 'react'
    import {
        Image,
        View,
        Text,
        TouchableOpacity,
        ScrollView
    } from 'react-native'
    import BaseComponent from '../components/BaseComponent'
    import Swiper from 'react-native-swiper'
    import Colors from '../utils/Colors'
    
    import data from '../../data.json'
    import config from '../../config.json'
    
    const finalStyle = {  DEVICE.width, height: DEVICE.width * 0.5 };
    
    //this.props.id 0推荐 1电影 2电视剧 3动漫 4综艺
    export default class Banner extends BaseComponent {
    
        containerStyle = finalStyle;
    
        state = {
            datas: [],
            classDatas: []
        }
    
        filterData(data) {
            //过滤掉广告轮播
            return data.filter(item => {
                return item.targetType == 2 && item.videoInfoId != 0;
            })
        }
    
        initData() {
            setTimeout(() => {
                let result = this.props.id == 0 ? data.RecommendBannerData : (
                    this.props.id == 1 ? data.MovieBannerData : (
                        this.props.id == 2 ? data.TVBannerData : (
                            this.props.id == 3 ? data.CartoonBannerData : data.VarietyBannerData
                        )
                    )
                )
                this.setState({
                    datas: this.filterData(result.data)
                }, () => this.update(this.LOAD_SUCCESS))
            }, config.delayed);
        }
    
        _enterVideoInfo = data => {
            data.coverUrl = data.thumbnailUrl;
            this.props.navigation.navigate("VideoInfoPage", { data })
        }
    
        renderComponent() {
            let items = [];
            for (let i = 0; i < this.state.datas.length; i++) {
                let obj = this.state.datas[i];
                let image = obj.thumbnailUrl ? { uri: obj.thumbnailUrl } : require('../../source/image/nor.png')
                let item = (
                    <TouchableOpacity
                        key={'banner' + i}
                        onPress={() => this._enterVideoInfo(obj)}
                        activeOpacity={1}>
                        <Image style={finalStyle} source={image} resizeMode="cover"></Image>
                        <View style={{ position: 'absolute', bottom: 0, paddingBottom: 25, paddingTop: 5, paddingLeft: 5,  '100%', backgroundColor: 'rgba(0,0,0,0.3)' }}>
                            <Text
                                numberOfLines={1}
                                style={{ color: 'white', fontWeight: '400', fontSize: 15 }}>{obj.title}</Text>
                        </View>
                    </TouchableOpacity>
                );
                items.push(item)
            }
            return (
                <Swiper
                    removeClippedSubviews={DEVICE.android ? true : false}
                    paginationStyle={{ bottom: 10, justifyContent: 'flex-end', paddingRight: 5 }}
                    style={finalStyle}
                    width={finalStyle.width}
                    height={finalStyle.height}
                    loop={true}
                    activeDotColor={Colors.mainColor}
                    dotColor="white"
                    autoplay={true}
                    showsPagination={true}>
                    {items}
                </Swiper>
            );
        }
    }
    

    代码感觉很复杂啊,又不是很复杂,但是很难沉下心一句一句弄懂,只能似是而非,其实是不懂,下一篇喽~

  • 相关阅读:
    elasticsearch版本不同,批量查询也不相同
    lucene源码分析(4)Similarity相似度算法
    lucene源码分析(3)facet实例
    lucene-solr源码编译导入eclipse--转
    lucene源码分析(2)读取过程实例
    lucene源码分析(1)基本要素
    javascript 的位操作符转换推断
    WinJS.Binding.List与kendo.data.ObservableArray
    迷你MVVM框架 avalonjs 0.84发布
    迷你MVVM框架 avalonjs 入门教程
  • 原文地址:https://www.cnblogs.com/smart-girl/p/10884984.html
Copyright © 2011-2022 走看看