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又重新回到我的世界,並