1. 程式人生 > >react-native城市列表元件

react-native城市列表元件

城市列表選擇是很多app共有的功能,比如典型的美圖app。那麼對於React Native怎麼實現呢?
這裡寫圖片描述

要實現上面的效果,首先需要對介面的組成簡單分析,介面的資料主要由當前城市,歷史訪問城市和熱門城市組成,所以我們在提供Json資料的時候就需要將資料分為至少3部分。

const ALL_CITY_LIST = DATA_JSON.allCityList;
const HOT_CITY_LIST = DATA_JSON.hotCityList;
const LAST_VISIT_CITY_LIST = DATA_JSON.lastVisitCityList;

而要實現字母索引功能,我們需要自定義一個控制元件,實現和資料的繫結關係,自定義元件程式碼如下:
CityIndexListView.js

'use strict';
import React, {Component} from 'react';
import {
    StyleSheet,
    View,
    Text,
    TouchableOpacity,
    ListView,
    Dimensions,
} from 'react-native';

import Toast, {DURATION} from './ToastUtil'

const SECTIONHEIGHT = 30;
const ROWHEIGHT = 40;
const ROWHEIGHT_BOX = 40;
var totalheight = []; //
每個字母對應的城市和字母的總高度 const {width, height} = Dimensions.get('window'); var that; const key_now = '當前'; const key_last_visit = '最近'; const key_hot = '熱門'; export default class CityIndexListView extends Component { constructor(props) { super(props); var getSectionData = (dataBlob, sectionID)
=>
{ return sectionID; }; var getRowData = (dataBlob, sectionID, rowID) => { return dataBlob[sectionID][rowID]; }; let ALL_CITY_LIST = this.props.allCityList; let CURRENT_CITY_LIST = this.props.nowCityList; let LAST_VISIT_CITY_LIST = this.props.lastVisitCityList; let HOT_CITY_LIST = this.props.hotCityList; let letterList = this._getSortLetters(ALL_CITY_LIST); let dataBlob = {}; dataBlob[key_now] = CURRENT_CITY_LIST; dataBlob[key_last_visit] = LAST_VISIT_CITY_LIST; dataBlob[key_hot] = HOT_CITY_LIST; ALL_CITY_LIST.map(cityJson => { let key = cityJson.sortLetters.toUpperCase(); if (dataBlob[key]) { let subList = dataBlob[key]; subList.push(cityJson); } else { let subList = []; subList.push(cityJson); dataBlob[key] = subList; } }); let sectionIDs = Object.keys(dataBlob); let rowIDs = sectionIDs.map(sectionID => { let thisRow = []; let count = dataBlob[sectionID].length; for (let ii = 0; ii < count; ii++) { thisRow.push(ii); } let eachheight = SECTIONHEIGHT + ROWHEIGHT * thisRow.length; if (sectionID === key_hot || sectionID === key_now || sectionID === key_last_visit) { let rowNum = (thisRow.length % 3 === 0) ? (thisRow.length / 3) : parseInt(thisRow.length / 3) + 1; console.log('sectionIDs===>' + sectionIDs + ", rowNum=====>" + rowNum); eachheight = SECTIONHEIGHT + ROWHEIGHT_BOX * rowNum; } totalheight.push(eachheight); return thisRow; }); let ds = new ListView.DataSource({ getRowData: getRowData, getSectionHeaderData: getSectionData, rowHasChanged: (row1, row2) => row1 !== row2, sectionHeaderHasChanged: (s1, s2) => s1 !== s2 }); this.state = { dataSource: ds.cloneWithRowsAndSections(dataBlob, sectionIDs, rowIDs), letters: sectionIDs }; that = this; } _getSortLetters(dataList) { let list = []; for (let j = 0; j < dataList.length; j++) { let sortLetters = dataList[j].sortLetters.toUpperCase(); let exist = false; for (let xx = 0; xx < list.length; xx++) { if (list[xx] === sortLetters) { exist = true; } if (exist) { break; } } if (!exist) { list.push(sortLetters); } } return list; } _cityNameClick(cityJson) { // alert('選擇了城市====》' + cityJson.id + '#####' + cityJson.name); this.props.onSelectCity(cityJson); } _scrollTo(index, letter) { this.refs.toast.close(); let position = 0; for (let i = 0; i < index; i++) { position += totalheight[i] } this._listView.scrollTo({y: position}); this.refs.toast.show(letter, DURATION.LENGTH_SHORT); } _renderRightLetters(letter, index) { return ( <TouchableOpacity key={'letter_idx_' + index} activeOpacity={0.6} onPress={() => { this._scrollTo(index, letter) }}> <View style={styles.letter}> <Text style={styles.letterText}>{letter}</Text> </View> </TouchableOpacity> ); } _renderListBox(cityJson, rowId) { return ( <TouchableOpacity key={'list_item_' + cityJson.id} style={styles.rowViewBox} onPress={() => { that._cityNameClick(cityJson) }}> <View style={styles.rowdataBox}> <Text style={styles.rowDataTextBox}>{cityJson.name}</Text> </View> </TouchableOpacity> ); } _renderListRow(cityJson, rowId) { console.log('rowId===>' + rowId + ", cityJson====>" + JSON.stringify(cityJson)); if (rowId === key_now || rowId === key_hot || rowId === key_last_visit) { return that._renderListBox(cityJson, rowId); } return ( <TouchableOpacity key={'list_item_' + cityJson.id} style={styles.rowView} onPress={() => { that._cityNameClick(cityJson) }}> <View style={styles.rowdata}> <Text style={styles.rowdatatext}>{cityJson.name}</Text> </View> </TouchableOpacity> ) } _renderListSectionHeader(sectionData, sectionID) { return ( <View style={styles.sectionView}> <Text style={styles.sectionText}> {sectionData} </Text> </View> ); } render() { return ( <View style={styles.container}> <View style={styles.listContainner}> <ListView ref={listView => this._listView = listView} contentContainerStyle={styles.contentContainer} dataSource={this.state.dataSource} renderRow={this._renderListRow} renderSectionHeader={this._renderListSectionHeader} enableEmptySections={true} initialListSize={500}/> <View style={styles.letters}> {this.state.letters.map((letter, index) => this._renderRightLetters(letter, index))} </View> </View> <Toast ref="toast" position='top' positionValue={200} fadeInDuration={750} fadeOutDuration={1000} opacity={0.8}/> </View> ) } } const styles = StyleSheet.create({ container: { // paddingTop: 50, flex: 1, flexDirection: 'column', backgroundColor: '#F4F4F4', }, listContainner: { height: Dimensions.get('window').height, marginBottom: 10 }, contentContainer: { flexDirection: 'row', width: width, backgroundColor: 'white', justifyContent: 'flex-start', flexWrap: 'wrap' }, letters: { position: 'absolute', height: height, top: 0, bottom: 0, right: 10, backgroundColor: 'transparent', // justifyContent: 'flex-start', // alignItems: 'flex-start' alignItems: 'center', justifyContent: 'center' }, letter: { height: height * 4 / 100, width: width * 4 / 50, justifyContent: 'center', alignItems: 'center' }, letterText: { textAlign: 'center', fontSize: height * 1.1 / 50, color: '#e75404' }, sectionView: { paddingTop: 5, paddingBottom: 5, height: 30, paddingLeft: 10, width: width, backgroundColor: '#F4F4F4' }, sectionText: { color: '#e75404', fontWeight: 'bold' }, rowView: { height: ROWHEIGHT, paddingLeft: 10, paddingRight: 10, borderBottomColor: '#F4F4F4', borderBottomWidth: 0.5 }, rowdata: { paddingTop: 10, paddingBottom: 2 }, rowdatatext: { color: 'gray', width: width }, rowViewBox: { height: ROWHEIGHT_BOX, width: (width - 30) / 3, flexDirection: 'row', backgroundColor: '#ffffff' }, rowdataBox: { borderWidth: 1, borderColor: '#DBDBDB', marginTop: 5, marginBottom: 5, paddingBottom: 2, marginLeft: 10, marginRight: 10, flex: 1, justifyContent: 'center', alignItems: 'center' }, rowDataTextBox: { marginTop: 5, flex: 1, height: 20 } });

然後在頭部還需要實現一個搜尋框。
SearchBox.js

'use strict';
import React, {Component} from 'react';
import {
    View,
    TextInput,
    StyleSheet,
    Platform,
} from 'react-native';

export default class SearchBox extends Component {
    constructor(props) {
        super(props);
        this.state = {
            value: ''
        };

    }

    onEndEditingKeyword(vv) {
        console.log(vv);
    }

    onChanegeTextKeyword(vv) {
        console.log('onChanegeTextKeyword', vv);

        this.setState({value: vv});
        this.props.onChanegeTextKeyword(vv);
    }

    render() {
        return (
            <View style={styles.container}>
                <View style={styles.inputBox}>
                    <View style={styles.inputIcon}>
                    </View>
                    <TextInput ref="keyword" autoCapitalize="none" value={this.props.keyword}
                               onChangeText={this.onChanegeTextKeyword.bind(this)} returnKeyType="search" maxLength={20}
                               style={styles.inputText} underlineColorAndroid="transparent"
                               placeholder={'輸入城市名或拼音查詢'}/>
                </View>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        marginTop: 5,
        marginBottom: 5,
        backgroundColor: '#ffffff',
        flexDirection: 'row',
        height: Platform.OS === 'ios'
            ? 35
            : 45,
        borderBottomWidth: StyleSheet.hairlineWidth,
        borderBottomColor: '#cdcdcd',
        paddingBottom: 5
    },
    inputBox: {
        height: Platform.OS === 'ios'
            ? 30
            : 40,
        marginLeft: 5,
        marginRight: 5,
        flex: 1,
        flexDirection: 'row',
        backgroundColor: '#E6E7E8'
    },
    inputIcon: {
        margin: Platform.OS === 'ios'
            ? 5
            : 10
    },
    inputText: {
        alignSelf: 'flex-end',
        marginTop: Platform.OS === 'ios'
            ? 0
            : 0,
        flex: 1,
        height: Platform.OS === 'ios'
            ? 30
            : 40,
        marginLeft: 2,
        marginRight: 5,
        fontSize: 12,
        lineHeight: 30,
        textAlignVertical: 'bottom',
        textDecorationLine: 'none'
    }
});

相關推薦

react-native城市列表元件

城市列表選擇是很多app共有的功能,比如典型的美圖app。那麼對於React Native怎麼實現呢? 要實現上面的效果,首先需要對介面的組成簡單分析,介面的資料主要由當前城市,歷史訪問城市和熱門城市組成,所以我們在提供Json資料的時候就需要將資料分為至

React-Native列表元件FlatList和SectionList學習 | | 聯動列表實現

React-Native在0.43推出了兩款新的列表元件:FlatList(高效能的簡單列表元件)和SectionList(高效能的分組列表元件). http://www.cnblogs.com/shaoting/p/7069312.html 從官方上它們都支援常用

React-Native列表SectionList學習

nat alert hit title set his ref out led 前言: 上一章我們學習了FlatList組件,本章我們來學習SectionList組件,當界面需要分區的顯示時候我們采用這個組件. 常用API: SectionList是高性能的分組列表組件

React-Native開發五 React Native 的Image元件

1 Image元件介紹 RN中Image元件主要用於載入圖片,可載入靜態圖片,網路圖片,以及原生圖片,本地檔案系統中圖片資源 官方參考https://facebook.github.io/react-native/docs/image#resizemode 2 Image元件功

React-Native開發四 React Native 的Touchable元件

1 Touchable元件簡介 Touchable元件是RN的按鈕元件,一共有四大類 TouchableWithoutFeedback:不帶任何反饋的可觸控元件 TouchableHighlight:在TouchableWithoutFeedback的基礎上添加了當按下時背景會變

React Native圖片快取元件

今天介紹一個React Native的圖片快取元件 react-native-rn-cacheimage ,純JS實現,所以相容性很好。 大家都知道,其實React Native 的 Image 元件在 iOS 端實現了快取,而android 端仍未實現,而且,就算實現了 iOS端 ,可能有些需求仍然比較難

React Native 筆記之元件

React Native的元件 什麼是React Native 元件? React Native 都有哪些元件? 建立元件的三種方式 [元件的生命週期](https://react.docschina.org/docs/react-compone

react native的Navigator元件示例

import React, {Component} from 'react';import {ScrollView, StyleSheet, Text, View, PixelRatio} from 'react-native';import { Navigator } from 'react-native-

react-native react-navigation的用法 react native 導航路由元件react-navigation的使用

  一、問題背景 react-navigation是react-native官方推薦的,基於Javascript的可擴充套件且使用簡單的導航,功能強大且完備   回顧一下,react-navigation包含以下功能來幫助我們建立導航器: StackN

React Native關於ScrollableTabView元件

最近工作中使用ScrollableTabView元件的問題,實現如下圖所示的效果: render方法中判斷state中狀態,進行佈局控制 render(){ if(this.state.error){ return(

React Native封裝原生元件釋出到npm

因為一個任務,要寫原生的獲取使用者手機資料夾,實現使用者自定義資料夾的功能,寫好了之後嘗試封裝成元件。1. 首先,有一個rn專案,用Adnroid Studio開啟 android -> app -> build.gradle如圖新建一個 Android Modu

react native 倒計時控制元件

1.npm install //in package.json "dependencies": { "react_native_countdowntimer":"1.0.2" } //in your js code import CountDownTimer fr

React Native 超長列表優化方案

在使用 React-Native 構建 APP 的過程中難免要使用到 FlatList。如果你的列表超級長,並且還包含圖片,你可能會遇到下面的問題:滑動白屏,快速滑動會遇到相當頻繁的白屏情況。閃退,一個無限載入形式的列表在不斷載入的過程中會突然閃退(安卓更常見)。重複載入,多

React Native常用第三方元件彙總--史上最全

快取管理https://github.com/reactnativecn/react-native-http-cacheListView的優化https://github.com/sghiassy/react-native-sglistview圖片和base64互轉https://github.com/xfu

React Native開發之——元件WebView

前言在開發Android的時候,一般我們會有一些載入網頁的需求,或者執行一些JavaScript,我們都知道在Android中實現這個功能的控制元件是WebView,在ReactNative中也有實現此類需求額的元件,它的名字也是WebView。那麼今天的這篇文章就來詳細說說

react-native播放視訊元件 react-native-video的用法

它的用法很簡單。 1.安裝 依次執行下面兩個命令, npm i -S react-native-video react-native link            (這一步是連線本地視訊庫) (

React Native之Modal元件實現遮罩層效果

React-Native中Modal的使用 /** * React Native App * dongtao 2017/04/22 * @flow */ import React, { Component } from 'react'; import { A

React Native 之Image 元件

1.載入網路圖片 render() { return ( <View style={styles.container} > <Image source={{uri: 'https://facebook.

react-native 的 TabBarIOS 元件(底部選擇器)

方法一 : 這是在 react-native 中文官網上的例子,親測功能效果很不錯,推薦使用 1. 建立一個  tabbar.js   檔案 'use strict'; var React = require('re

React Native懸浮效果元件

由於其他的原因,對於React Native相關的內容最近沒有投入太多的關注,從去年年底出版了《React Native移動開發實戰》後,對於React Native的關注就比較少了。最近由於公司之前的專案需要,所以React Native又重新回到我的世界,並