React-Native 之 項目實戰(四)

前言


  • 本文有配套視頻,能夠酌情觀看。
  • 文中內容因各人理解不一樣,可能會有所誤差,歡迎朋友們聯繫我。
  • 文中全部內容僅供學習交流之用,不可用於商業用途,如所以引發的相關法律法規責任,與我無關。
  • 如文中內容對您形成不便,煩請聯繫 277511806@qq.com 處理,謝謝。
  • 轉載麻煩註明出處,謝謝。
  • 本篇資源:連接: https://pan.baidu.com/s/1pKActHh 密碼: n6eephp

  • 源碼託管到 github 上,須要源碼的 點我下載,喜歡的話記得 Star,謝謝!node

數據持久化


  • 數據持久化是移動端的一個重要部分,剛發現 Realm 原來已經支持 React-Native 了,那麼這邊另起一篇專門介紹兩種經常使用的存儲方式 ———— React-Native 之 數據持久化react

  • 這邊沒有發現 官方 有將 商品數據 作本地緩存的功能,爲了讓你們知道怎麼作,咱們就簡單地來實驗一下,具體邏輯在每一個產品中都或多或少有些差別,這個朋友們就根據所學的靈活變通一下就能夠了!ios

  • 首先,在爲了方便使用,也爲了減小第三方框架對工程的 「污染」,咱們須要對框架進行一次 基礎 的封裝。git

    var RealmBase = {};
    
        import Realm from 'realm';
    
        const HomeSchame = {
            name:'HomeData',
            properties:{
                id:'int',
                title:'string',
                image:'string',
                mall:'string',
                pubtime:'string',
                fromsite:'string',
            }
        };
    
        const HTSchame = {
            name:'HTData',
            properties:{
                id:'int',
                title:'string',
                image:'string',
                mall:'string',
                pubtime:'string',
                fromsite:'string',
            }
        };
    
        // 初始化realm
        let realm = new Realm({schema:[HomeSchame, HTSchame]});
    
        // 增長
        RealmBase.create = function (schame, data) {
            realm.write(() => {
                for (let i = 0; i<data.length; i++) {
                    let temp = data[i];
                    realm.create(schame, {id:temp.id, title:temp.title, image:temp.image, mall:temp.mall, pubtime:temp.pubtime, fromsite:temp.fromsite});
                }
            })
        }
    
        // 查詢所有數據
        RealmBase.loadAll = function (schame) {
            return realm.objects(schame);
        }
    
        // 條件查詢
        RealmBase.filtered = function (schame, filtered) {
            // 獲取對象
            let objects = realm.objects(schame);
            // 篩選
            let object = objects.filtered(filtered);
    
            if (object) {   // 有對象
                return object;
            }else {
                return '未找到數據';
            }
        }
    
        // 刪除全部數據
        RealmBase.removeAllData = function (schame) {
            realm.write(() => {
                // 獲取對象
                let objects = realm.objects(schame);
                // 刪除表
                realm.delete(objects);
            })
        }
    
        global.RealmBase = RealmBase;
  • 通過簡單封裝後,咱們還須要引用一下框架,引用框架,咱們就放到 main 文件內,這樣咱們就能夠確保 全局變量 是在咱們使用它以前就被調用過,避免找不到對象的錯誤(咱們也同時將 HTTPBase 修改成全局,方便使用)。github

    import RealmStorage from '../storage/realmStorage';
  • 如今咱們就來作下 本地持久化 實驗,這邊咱們的邏輯就是,當網絡出現問題的時候,每次都會進到 catch 中返回錯誤 code 告訴咱們,出現了什麼問題(既然進到這裏了,是否是數據不管如何都不會加載成功?),那麼咱們就能夠在這裏 取出 本地數據,而後展現出來,那麼數據的應該在哪裏保存呢?這個咱們只須要在每次 刷新 完成而且渲染完成後,保存一下數據就能夠了。npm

    // 加載最新數據網絡請求
        loadData(resolve) {
    
            let params = {"count" : 10 };
    
            HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
                .then((responseData) => {
    
                    // 清空數組
                    this.data = [];
    
                    // 拼接數據
                    this.data = this.data.concat(responseData.data);
    
                    // 從新渲染
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(this.data),
                        loaded:true,
                    });
    
                    // 關閉刷新動畫
                    if (resolve !== undefined){
                        setTimeout(() => {
                            resolve();
                        }, 1000);
                    }
    
                    // 存儲數組中最後一個元素的id
                    let cnlastID = responseData.data[responseData.data.length - 1].id;
                    AsyncStorage.setItem('cnlastID', cnlastID.toString());
    
                    // 存儲數組中第一個元素的id
                    let cnfirstID = responseData.data[0].id;
                    AsyncStorage.setItem('cnfirstID', cnfirstID.toString());
    
                    // 清楚本地存儲的數據
                    RealmBase.removeAllData('HomeData');
    
                    // 存儲數據到本地
                    RealmBase.create('HomeData', responseData.data);
                })
                .catch((error) => {
                    // 拿到本地存儲的數據,展現出來,若是沒有存儲,那就顯示無數據頁面
                    this.data = RealmBase.loadAll('HomeData');
    
                    // 從新渲染
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(this.data),
                        loaded:true,
                    });
                })
        }
  • 到這裏,咱們就完成了 數據本地持久化 而且成功將數據取出,這邊數據持久化的實驗就完成了。react-native

數據持久化.gif

譯註:api

  • 有關 realm 的配置,可轉到 React-Native 之 數據持久化 查看,這邊很少贅述。數組

  • 當咱們徹底配置完 realm 後,會發現整個工程 多出將近500M+,不用擔憂,這些只不過是 realm 的依賴庫,等咱們後面 打包 後就不會有這麼多東西了。

  • 咱們已經使用了 git 進行對代碼進行託管,那麼,若是從倉庫拉取最新數據時,是否是仍是要從新配置 node_modules 文件夾,這個就很麻煩了,咱們能夠備份一下 node_modules 文件夾,將它 拷貝 進工程就可使用了。

.gitignore 語法


  • gitignore 文件內包含了須要忽略或保留的文件的一些配置,靈活使用能夠減小咱們的工做量,可是裏面的內容是什麼意思呢?這邊也給你們說下:
    • /:表示目錄
    • *:爲通配多個字符
    • ?:通配單個字符
    • []:包含單個字符的匹配列表
    • !:表示不忽略匹配到的文件和目錄
    • // 示例
    • // 忽略ios文件夾下的全部內容
  • 知道語法後,咱們是否是就能看懂 工程中 gitignore 文件的內容了,舉個栗子:

    # Xcode                 // 註釋,說明這是 Xcode 配置
        #
        build/                  // 忽略 build 文件夾下全部內容
        *.pbxuser               // 忽略以 .pbxuser 爲後綴的文件
        !default.pbxuser        // 除 default.pbxuser 文件外
        *.mode1v3               // 忽略以 .mode1v3  爲後綴的文件
        !default.mode1v3        // 除 default.mode1v3     文件外
    
        # node.js               // 註釋,說明這是 node 配置
        #
        node_modules/           // 忽略 node_modules 文件夾內全部內容
        npm-debug.log           // 忽略 npm-debug.log 
        yarn-error.log          // 忽略 yarn-error.log
  • 好了,就介紹到這裏,但願能夠幫到有須要的朋友,須要學習更多關於 git 的內容,能夠到 git介紹與使用 查看學習。

自定義詳情cell


  • 到這邊可能有人會想,前面不是已經自定義了 cell 了,爲何不直接在前面自定義的 cell 裏面再添加一些操做,使全部的 cell 共用同一套組件?其實考慮到下面幾點緣由:
    • 能夠看到 半小時熱門的cell三大模塊的cell 區別在於少了 優惠平臺和數據提供平臺 這一欄的2個控件,其餘地方是同樣的,若是咱們作到一塊兒那也是能夠的,可是這樣會形成一個組件裏面擔負過多業務邏輯,在 數據量少 是不要緊,可是 數據量一多 那麼須要渲染的成本就會增長,也就會嚴重影響到性能。

    • 若是咱們分開使用,那麼只是增長了組件,並且組件內部處理的業務邏輯變少了,這樣也減小了咱們後期的維護成本。

    • 從結構上來講,這樣也更爲的清晰,減小開發人員之間的溝通成本。

  • 首先,仍是同樣,咱們先來建立 GDCommunalCell 文件,而且咱們將前面 自定義cell 裏面的內容 copy 一下,放到這個文件中,並進行相應修改:

    export default class GDCommunalCell extends Component {
    
            static propTypes = {
                image:PropTypes.string,
                title:PropTypes.string,
                mall:PropTypes.string,
                pubTime:PropTypes.string,
                fromSite:PropTypes.string,
            };
    
            renderDate(pubTime, fromSite) {
    
                // 時間差的計算
                let minute = 1000 * 60;     // 1分鐘
                let hour = minute * 60;     // 1小時
                let day = hour * 24;        // 1天
                let week = day * 7;         // 1周
                let month = day * 30;       // 1個月
    
                // 計算時間差
                let now = new Date().getTime();     // 獲取當前時間
                let diffValue = now - Date.parse(pubTime.replace(/-/gi, "/"));
    
                if (diffValue < 0) return;
    
                let monthC = diffValue/month;   // 相差了幾個月
                let weekC = diffValue/week;     // 相差幾周
                let dayC = diffValue/day;       // 相差幾天
                let hourC = diffValue/hour      // 相差幾小時
                let minuteC = diffValue/minute; // 相差幾分鐘
    
                let result;
    
                if (monthC >= 1) {
                    result = parseInt(monthC) + "月前";
                }else if (weekC >= 1) {
                    result = parseInt(weekC) + "周前";
                }else if (dayC >= 1) {
                    result = parseInt(dayC) + "天前";
                }else if (hourC >= 1) {
                    result = parseInt(hourC) + "小時前";
                }else if (minuteC >= 1) {
                    result = parseInt(minuteC) + "分鐘前";
                }else result = "剛剛";
    
                return result + ' · ' + fromSite;
    
            }
    
            render() {
                return (
                    <View style={styles.container}>
                        {/* 左邊圖片 */}
                        <Image source={{uri:this.props.image === '' ? 'defaullt_thumb_83x83' : this.props.image}} style={styles.imageStyle} />
                        {/* 中間 */}
                        <View style={styles.centerViewStyle}>
                            {/* 標題 */}
                            <View>
                                <Text numberOfLines={3} style={styles.titleStyle}>{this.props.title}</Text>
                            </View>
                            {/* 詳情 */}
                            <View style={styles.detailViewStyle}>
                                {/* 平臺 */}
                                <Text style={styles.detailMallStyle}>{this.props.mall}</Text>
                                {/* 時間 + 來源 */}
                                <Text style={styles.timeStyle}>{this.renderDate(this.props.pubTime, this.props.fromSite)}</Text>
                            </View>
    
                        </View>
                        {/* 右邊的箭頭 */}
                        <Image source={{uri:'icon_cell_rightArrow'}} style={styles.arrowStyle} />
                    </View>
                );
            }
        }
    
        const styles = StyleSheet.create({
            container: {
                flexDirection:'row',
                alignItems:'center',
                justifyContent:'space-between',
                backgroundColor:'white',
                height:100,
                width:width,
                borderBottomWidth:0.5,
                borderBottomColor:'gray',
                marginLeft:15
    
            },
    
            imageStyle: {
                width:70,
                height:70,
            },
    
            centerViewStyle: {
                height:70,
                justifyContent:'space-around',
            },
    
            titleStyle: {
                width:width * 0.65,
            },
    
            detailViewStyle: {
                flexDirection:'row',
                justifyContent:'space-between',
                alignItems:'center'
            },
            detailMallStyle: {
                fontSize:12,
                color:'green',
            },
            timeStyle: {
                fontSize:12,
                color:'gray',
            },
    
            arrowStyle: {
                width:10,
                height:10,
                marginRight:30,
            }
        });
  • OK,這邊完成了,咱們到首頁中試一下是否是好使的。

詳情頁.gif

譯註:

  • 這邊須要注意的是時間的轉化,方式有不少,這邊就以最直接的方式來計算。

  • 還有須要注意的是在 JAVA 中,獲取到的月份是和咱們如今的月份少 1個月的,這是由於 JAVA 的月份是從 0 開始,Javascript 也是同樣的。

小時風雲榜


  • 這個模塊和首頁、海淘請求數據方面是相似的,不一樣在於這裏須要咱們根據不一樣的時間段來進行相對應的請求,這邊參考視頻吧,直接上完整代碼。

  • 仍是 copy 首頁或者海淘的代碼,修改請求這部分代碼:

export default class GDHourList extends Component {
    
        // 構造
        constructor(props) {
            super(props);
            // 初始狀態
            this.state = {
                dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}),
                loaded:false,
                prompt:'',
            };
    
            this.nexthourhour = '';
            this.nexthourdate = '';
            this.lasthourhour = '';
            this.lasthourdate = '';
            this.loadData = this.loadData.bind(this);
        }
    
        // 加載最新數據網絡請求
        loadData(resolve, date, hour) {
            let params = {};
    
            if (date) {
                params = {
                    "date" : date,
                    "hour" : hour
                }
            }
    
            HTTPBase.get('http://guangdiu.com/api/getranklist.php', params)
                .then((responseData) => {
    
                    // 從新渲染
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(responseData.data),
                        loaded:true,
                        prompt:responseData.displaydate + responseData.rankhour + '點檔' + '(' + responseData.rankduring + ')'
                    });
    
                    // 關閉刷新動畫
                    if (resolve !== undefined){
                        setTimeout(() => {
                            resolve();
                        }, 1000);
                    }
    
                    // 暫時保留一些數據
                    this.nexthourhour = responseData.nexthourhour;
                    this.nexthourdate = responseData.nexthourdate;
                    this.lasthourhour = responseData.lasthourhour;
                    this.lasthourdate = responseData.lasthourdate;
                })
                .catch((error) => {
    
                })
        }
    
        // 跳轉到設置
        pushToSettings() {
            this.props.navigator.push({
                component:Settings,
            })
        }
    
        // 返回中間標題
        renderTitleItem() {
            return(
                <Image source={{uri:'navtitle_rank_106x20'}} style={styles.navbarTitleItemStyle} />
            );
        }
    
        // 返回右邊按鈕
        renderRightItem() {
            return(
                <TouchableOpacity
                    onPress={()=>{this.pushToSettings()}}
                >
                    <Text style={styles.navbarRightItemStyle}>設置</Text>
                </TouchableOpacity>
            );
        }
    
        // 根據網絡狀態決定是否渲染 listview
        renderListView() {
            if (this.state.loaded === false) {
                return(
                    <NoDataView />
                );
            }else {
                return(
                    <PullList
                        onPullRelease={(resolve) => this.loadData(resolve)}
                        dataSource={this.state.dataSource}
                        renderRow={this.renderRow.bind(this)}
                        showsHorizontalScrollIndicator={false}
                        style={styles.listViewStyle}
                        initialListSize={5}
                    />
                );
            }
        }
    
        // 跳轉到詳情頁
        pushToDetail(value) {
            this.props.navigator.push({
                component:CommunalDetail,
                params: {
                    url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value
                }
            })
        }
    
        // 返回每一行cell的樣式
        renderRow(rowData) {
            return(
                <TouchableOpacity
                    onPress={() => this.pushToDetail(rowData.id)}
                >
                    <CommunalCell
                        image={rowData.image}
                        title={rowData.title}
                        mall={rowData.mall}
                        pubTime={rowData.pubtime}
                        fromSite={rowData.fromsite}
                    />
                </TouchableOpacity>
            );
        }
    
        componentDidMount() {
            this.loadData();
        }
    
        lastHour() {
            this.loadData(undefined, this.lasthourdate, this.lasthourhour);
        }
    
        nextHour() {
            this.loadData(undefined, this.nexthourdate, this.nexthourhour);
        }
    
        render() {
            return (
                <View style={styles.container}>
                    {/* 導航欄樣式 */}
                    <CommunalNavBar
                        titleItem = {() => this.renderTitleItem()}
                        rightItem = {() => this.renderRightItem()}
                    />
    
                    {/* 提醒欄 */}
                    <View style={styles.promptViewStyle}>
                        <Text>{this.state.prompt}</Text>
                    </View>
    
                    {/* 根據網絡狀態決定是否渲染 listview */}
                    {this.renderListView()}
    
                    {/* 操做欄 */}
                    <View style={styles.operationViewStyle}>
                        <TouchableOpacity
                            onPress={() => this.lastHour()}
                        >
                            <Text style={{marginRight:10, fontSize:17, color:'green'}}>{"< " + "上1小時"}</Text>
                        </TouchableOpacity>
    
                        <TouchableOpacity
                            onPress={() => this.nextHour()}
                        >
                            <Text style={{marginLeft:10, fontSize:17, color:'green'}}>{"下1小時" + " >"}</Text>
                        </TouchableOpacity>
                    </View>
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            alignItems: 'center',
            backgroundColor: 'white',
        },
    
        navbarTitleItemStyle: {
            width:106,
            height:20,
            marginLeft:50
        },
        navbarRightItemStyle: {
            fontSize:17,
            color:'rgba(123,178,114,1.0)',
            marginRight:15,
        },
    
        promptViewStyle: {
            width:width,
            height:44,
            alignItems:'center',
            justifyContent:'center',
            backgroundColor:'rgba(251,251,251,1.0)',
        },
    
        operationViewStyle: {
            width:width,
            height:44,
            flexDirection:'row',
            justifyContent:'center',
            alignItems:'center',
        },
    });

小時風雲榜.gif

首頁篩選功能


  • 從圖中,咱們能夠看出篩選的下拉菜單相似 九宮格,這個咱們在 React-Native 之 ListView使用 中有這樣的案例,不清楚的能夠再回去看一下,因此這邊咱們也使用 ListView 實現。

  • 在作以前,咱們須要先配置一下,將壓縮包內的 HomeSiftData文件HTSiftData 文件放到工程內。

  • 接着咱們就要來完成這個篩選組件,代碼以下:

export default class GDCommunalSiftMenu extends Component {
    
        static defaultProps = {
            removeModal:{},
            loadSiftData:{}
        };
    
        static propTypes = {
            data:PropTypes.array,
        };
    
        // 構造
          constructor(props) {
            super(props);
            // 初始狀態
            this.state = {
                dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2})
            };
          }
    
        // 退出
        popToHome(data) {
            this.props.removeModal(data);
        }
    
        // 點擊事件
        siftData(mall, cate) {
            this.props.loadSiftData(mall, cate);
            this.popToHome(false);
        }
    
        // 處理數據
        loadData() {
            let data = [];
    
            for (let i = 0; i<this.props.data.length; i++) {
                data.push(this.props.data[i]);
            }
    
            // 從新渲染
            this.setState({
                dataSource: this.state.dataSource.cloneWithRows(data),
            })
        }
    
        renderRow(rowData) {
            return(
                <View style={styles.itemViewStyle}>
                    <TouchableOpacity
                        onPress={() => this.siftData(rowData.mall, rowData.cate)}
                    >
                        <View style={styles.itemViewStyle}>
                            <Image source={{uri:rowData.image}} style={styles.itemImageStyle} />
                            <Text>{rowData.title}</Text>
                        </View>
                    </TouchableOpacity>
                </View>
            )
        }
    
        componentDidMount() {
            this.loadData();
        }
    
        render() {
            return(
                <TouchableOpacity
                    onPress={() => this.popToHome(false)}
                    activeOpacity={1}
                >
                    <View style={styles.container}>
                        {/* 菜單內容 */}
                        <ListView
                            dataSource={this.state.dataSource}
                            renderRow={this.renderRow.bind(this)}
                            contentContainerStyle={styles.contentViewStyle}
                            initialListSize={16}
                        />
                    </View>
                </TouchableOpacity>
            )
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            width:width,
            height:height
        },
    
        contentViewStyle: {
            flexDirection:'row',
            flexWrap:'wrap',
            width: width,
            top:Platform.OS === 'ios' ? 64 : 44,
        },
    
        itemViewStyle: {
            width:width * 0.25,
            height:70,
            backgroundColor:'rgba(249,249,249,1.0)',
            justifyContent:'center',
            alignItems:'center'
        },
    
        itemImageStyle: {
            width:40,
            height:40
        }
    });
  • 咱們點擊某個平臺,就要進行相應的請求,而後從新渲染 首頁的ListView ,方式以下:
// 加載最新數據網絡請求
    loadSiftData(mall, cate) {

        let params = {};

        if (mall === "" && cate === "") {   // 所有
            this.loadData(undefined);
            return;
        }

        if (mall === "") {  // cate 有值
            params = {
                "cate" : cate
            };
        }else {
            params = {
                "mall" : mall
            };
        }


        HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
            .then((responseData) => {

                // 清空數組
                this.data = [];

                // 拼接數據
                this.data = this.data.concat(responseData.data);

                // 從新渲染
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(this.data),
                    loaded:true,
                });

                // 存儲數組中最後一個元素的id
                let cnlastID = responseData.data[responseData.data.length - 1].id;
                AsyncStorage.setItem('cnlastID', cnlastID.toString());

            })
            .catch((error) => {

            })
    }
  • 至此,首頁的篩選功能也完成了,在 海淘模塊 內也使用一下就能夠了。

篩選功能.gif

搜索模塊


  • 點擊 首頁或者海淘 右側按鈕,咱們跳轉到搜索模塊,解析圖奉上:

  • 根據解析圖咱們添加相應子組件。

    export default class GDHome extends Component {
    
            // 構造
            constructor(props) {
                super(props);
                // 初始狀態
                this.state = {
                    dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}),
                    loaded:false,
                    isModal:false
                };
    
                this.data = [];
                this.changeText = '';
                this.loadData = this.loadData.bind(this);
                this.loadMore = this.loadMore.bind(this);
            }
    
            // 加載最新數據網絡請求
            loadData(resolve) {
    
                if (!this.changeText) return;
    
                let params = {
                    "q" : this.changeText
                };
    
                HTTPBase.get('http://guangdiu.com/api/getresult.php', params)
                    .then((responseData) => {
    
                        // 清空數組
                        this.data = [];
    
                        // 拼接數據
                        this.data = this.data.concat(responseData.data);
    
                        // 從新渲染
                        this.setState({
                            dataSource: this.state.dataSource.cloneWithRows(this.data),
                            loaded:true,
                        });
    
                        // 關閉刷新動畫
                        if (resolve !== undefined){
                            setTimeout(() => {
                                resolve();
                            }, 1000);
                        }
    
                        // 存儲數組中最後一個元素的id
                        let searchLastID = responseData.data[responseData.data.length - 1].id;
                        AsyncStorage.setItem('searchLastID', searchLastID.toString());
    
                    })
                    .catch((error) => {
    
                    })
            }
    
            // 加載更多數據的網絡請求
            loadMoreData(value) {
    
                let params = {
                    "q" : this.changeText,
                    "sinceid" : value
                };
    
                HTTPBase.get('http://guangdiu.com/api/getresult.php', params)
                    .then((responseData) => {
    
                        // 拼接數據
                        this.data = this.data.concat(responseData.data);
    
                        this.setState({
                            dataSource: this.state.dataSource.cloneWithRows(this.data),
                            loaded:true,
                        });
    
                        // 存儲數組中最後一個元素的id
                        let searchLastID = responseData.data[responseData.data.length - 1].id;
                        AsyncStorage.setItem('searchLastID', searchLastID.toString());
                    })
                    .catch((error) => {
    
                    })
            }
    
            // 加載更多數據操做
            loadMore() {
                // 讀取id
                AsyncStorage.getItem('searchLastID')
                    .then((value) => {
                        // 數據加載操做
                        this.loadMoreData(value);
                    })
    
            }
    
            // 返回
            pop() {
                // 回收鍵盤
                dismissKeyboard();
    
                this.props.navigator.pop();
            }
    
            // 返回左邊按鈕
            renderLeftItem() {
                return(
                    <TouchableOpacity
                        onPress={() => {this.pop()}}
                    >
                        <View style={{flexDirection:'row', alignItems:'center'}}>
                            <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} />
                            <Text>返回</Text>
                        </View>
    
                    </TouchableOpacity>
                );
            }
    
            // 返回中間按鈕
            renderTitleItem() {
                return(
                    <Text style={styles.navbarTitleItemStyle}>搜索全網折扣</Text>
                );
            }
    
            // ListView尾部
            renderFooter() {
                return (
                    <View style={{height: 100}}>
                        <ActivityIndicator />
                    </View>
                );
            }
    
            // 根據網絡狀態決定是否渲染 listview
            renderListView() {
                if (this.state.loaded === false) {
                    return(
                        <NoDataView />
                    );
                }else {
                    return(
                        <PullList
                            onPullRelease={(resolve) => this.loadData(resolve)}
                            dataSource={this.state.dataSource}
                            renderRow={this.renderRow.bind(this)}
                            showsHorizontalScrollIndicator={false}
                            style={styles.listViewStyle}
                            initialListSize={5}
                            renderHeader={this.renderHeader}
                            onEndReached={this.loadMore}
                            onEndReachedThreshold={60}
                            renderFooter={this.renderFooter}
                        />
                    );
                }
            }
    
            // 跳轉到詳情頁
            pushToDetail(value) {
                this.props.navigator.push({
                    component:CommunalDetail,
                    params: {
                        url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value
                    }
                })
            }
    
            // 返回每一行cell的樣式
            renderRow(rowData) {
                return(
                    <TouchableOpacity
                        onPress={() => this.pushToDetail(rowData.id)}
                    >
                        <CommunalCell
                            image={rowData.image}
                            title={rowData.title}
                            mall={rowData.mall}
                            pubTime={rowData.pubtime}
                            fromSite={rowData.fromsite}
                        />
                    </TouchableOpacity>
                );
            }
    
            render() {
                return (
                    <View style={styles.container}>
                        {/* 導航欄樣式 */}
                        <CommunalNavBar
                            leftItem = {() => this.renderLeftItem()}
                            titleItem = {() => this.renderTitleItem()}
                        />
    
                        {/* 頂部工具欄 */}
                        <View style={styles.toolsViewStyle} >
                            {/* 左邊 */}
                            <View style={styles.inputViewStyle} >
                                <Image source={{uri:'search_icon_20x20'}} style={styles.searchImageStyle} />
                                <TextInput
                                    style={styles.textInputStyle}
                                    keyboardType="default"
                                    placeholder="請輸入搜索商品關鍵字"
                                    placeholderTextColor='gray'
                                    autoFocus={true}
                                    clearButtonMode="while-editing"
                                    onChangeText={(text) => {this.changeText = text}}
                                    onEndEditing={() => this.loadData()}
                                />
                            </View>
    
                            {/* 右邊 */}
                            <View style={{marginRight:10}}>
                                <TouchableOpacity
                                    onPress={() => this.pop()}
                                >
                                    <Text style={{color:'green'}}>取消</Text>
                                </TouchableOpacity>
                            </View>
                        </View>
    
                        {/* 根據網絡狀態決定是否渲染 listview */}
                        {this.renderListView()}
                    </View>
                );
            }
        }
    
        const styles = StyleSheet.create({
            container: {
                flex: 1,
                alignItems: 'center',
                backgroundColor: 'white',
            },
    
            navbarLeftItemStyle: {
                width:20,
                height:20,
                marginLeft:15,
            },
            navbarTitleItemStyle: {
                fontSize:17,
                color:'black',
                marginRight:50
            },
            navbarRightItemStyle: {
                width:20,
                height:20,
                marginRight:15,
            },
    
            toolsViewStyle: {
                width:width,
                height:44,
                flexDirection:'row',
                alignItems:'center',
                justifyContent:'space-between',
            },
    
            inputViewStyle: {
                height:35,
                flexDirection:'row',
                alignItems:'center',
                justifyContent:'center',
                backgroundColor:'rgba(239,239,241,1.0)',
                marginLeft:10,
                borderRadius:5
            },
            searchImageStyle: {
                width:15,
                height:15,
                marginLeft:8
            },
            textInputStyle: {
                width:width * 0.75,
                height:35,
                marginLeft:8
            },
    
            listViewStyle: {
            width:width,
            },
        });

搜索頁面.gif

設置


  • 小時風雲榜 模塊,咱們還有設置模塊沒有作,這邊也快速來作一下

  • 從圖中能夠看出,這又是不同的 cell樣式 ,不過經過前面的經驗,知道怎麼來自定義了吧:

    export default class GDSettingsCell extends Component {
    
            static propTypes = {
                leftTitle:PropTypes.string,
                isShowSwitch:PropTypes.bool,
            };
    
            // 構造
              constructor(props) {
                super(props);
                // 初始狀態
                this.state = {
                    isOn:false,
                };
              }
    
            // 返回須要的組件
            renderRightContent() {
                let component;
    
                if (this.props.isShowSwitch) {  // 顯示 Switch 按鈕
    
                    component = <Switch value={this.state.isOn} onValueChange={() => {this.setState({isOn: !this.state.isOn})}} />
                }else {
                    component = <Image source={{uri:'icon_cell_rightArrow'}} style={styles.arrowStyle} />
                }
    
                return(
                    component
                )
            }
    
            render() {
                return(
                    <View style={styles.container}>
                        {/* 左邊 */}
                        <View>
                            <Text>{this.props.leftTitle}</Text>
                        </View>
    
                        {/* 右邊 */}
                        <View style={styles.rightViewStyle}>
                            {this.renderRightContent()}
                        </View>
                    </View>
                )
            }
        }
    
        const styles = StyleSheet.create({
            container: {
                flex:1,
                flexDirection:'row',
                height:Platform.OS === 'ios' ? 44 : 36,
                justifyContent:'space-between',
                alignItems:'center',
                borderBottomColor:'gray',
                borderBottomWidth:0.5,
                marginLeft:15,
            },
    
            rightViewStyle:{
                marginRight:15,
            },
    
            arrowStyle: {
                width:10,
                height:10,
            }
        });
  • 自定義完成,來試下好很差用:

    export default class GDSettings extends Component {
            // 返回
            pop() {
                this.props.navigator.pop();
            }
    
            // 返回左邊按鈕
            renderLeftItem() {
                return(
                    <TouchableOpacity
                        onPress={() => {this.pop()}}
                    >
                        <View style={{flexDirection:'row', alignItems:'center'}}>
                            <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} />
                            <Text>返回</Text>
                        </View>
    
                    </TouchableOpacity>
                );
            }
    
            // 返回中間按鈕
            renderTitleItem() {
                return(
                    <Text style={styles.navbarTitleItemStyle}>設置</Text>
                );
            }
    
            render() {
                return(
                    <View style={styles.container}>
                        {/* 導航欄樣式 */}
                        <CommunalNavBar
                            leftItem = {() => this.renderLeftItem()}
                            titleItem = {() => this.renderTitleItem()}
                        />
    
                        {/* 內容 */}
                        <ScrollView
                            style={styles.scollViewStyle}
                        >
                            {/* 第一個cell */}
                            <SettingsCell
                                leftTitle="淘寶天貓快捷下單"
                                isShowSwitch={true}
                            />
    
                            {/* 第二個cell */}
                            <SettingsCell
                                leftTitle="清理圖片緩存"
                                isShowSwitch={false}
                            />
                        </ScrollView>
                    </View>
                )
            }
        }
    
        const styles = StyleSheet.create({
            container: {
                flex:1
            },
    
            navbarLeftItemStyle: {
                width:20,
                height:20,
                marginLeft:15,
            },
    
            navbarTitleItemStyle: {
                fontSize:17,
                color:'black',
                marginRight:50
            },
    
            scollViewStyle: {
                backgroundColor:'white',
            },
        });

設置.gif

相關文章
相關標籤/搜索