尽管 React Native 曾经不在是以后热门的跨平台技术了,然而还是能够看到很多的公司和集体在用,Flutter 有 Flutter 好,RN 呢也有适宜本人的中央,至于到底哪个更好,咱们不做过多的比拟。
最近,我在降级之前的《React Native 挪动开发实战》一书,书中的我的项目有城市切换的性能,成果如下图所示。
能够看到,这个城市抉择页面是很惯例的,蕴含了以后定位城市和城市列表,右侧能够通过 SlideBar 进行快捷定位,除此之外,此组件还反对搜寻性能。
首先,咱们看一下城市列表,对于这一性能,咱们能够应用 SectionList 组件,因为咱们能够应用 SectionList 的 ListHeaderComponent 属性来实现以后定位布局,而左边的字母索引成果须要借助 SectionList 的 scrollToLocation() 函数,如下所示。
const _scrollTo = (index, letter) => {listViewRef?.current?.scrollToLocation({itemIndex: 0, sectionIndex: index});
};
而搜寻性能就更加简略了,应用 FlatList 组件展现即可,此处也能够应用 list.map 循环来开发列表性能。
CitySelectScreen.js
import React, {useState, useEffect} from 'react';
import {
View,
Text,
TextInput,
StyleSheet,
TouchableOpacity,
Keyboard,
} from 'react-native';
import PropTypes from 'prop-types';
import {CityList} from './components';
import apiRequest from '../../api';
import Header from '../../common/Header/Header';
const CitySelectScreen = ({location = '上海市', navigation}) => {
let inputRef = null;
const [cities, setCities] = useState([]);
const [currentCityList, setCurrentCityList] = useState({});
const [isFocused, setIsFocused] = useState(false);
const [result, setResult] = useState([]);
const [keyword, setKeyword] = useState('');
useEffect(() => {getCities();
}, []);
const onChangeText = e => {setKeyword(e);
};
const onSelectCity = city => {setTimeout(() => {
navigation.navigate('SelectCinemaScreen', {
title: city.CITY_NAME,
CITY_CD: city.CITY_CD,
});
}, 200);
setResult([]);
};
const searchSubmit = () => {if (isFocused) {inputRef.blur();
setIsFocused(false);
setResult([]);
Keyboard.dismiss();} else {setIsFocused(true);
inputRef.focus();}
};
const getCities = async () => {
let url = 'https://prd-api.cgv.com.cn/product/areas/that/group';
const res = await apiRequest.get(url);
setCities(res);
};
const searchCities = async () => {
let url = 'https://prd-api.cgv.com.cn/product/areas/that/group';
const params = {condition: keyword};
const res = await apiRequest.get(url, params);
console.log(res[0].data);
setResult(res[0].data);
};
const onCurrentPress = (name = '上海市') => {
cities.map(item =>
item.data.map(val => {if (val.CITY_NAME === name) {onSelectCity(val);
return null;
}
}),
);
};
const renderSearchView = () => {
return (<View style={styles.searchView}>
<TextInput
style={{flex: 1}}
assignRef={c => {inputRef = c;}}
onChangeText={onChangeText}
returnKeyType="search"
onSubmitEditing={() => {if (keyword) {searchCities();
}
}}
onFocus={() => setIsFocused(true)}
placeholder="输出城市名或拼音"
/>
<TouchableOpacity onPress={() => searchSubmit(isFocused)}>
<Text style={styles.searchTxt}>{!isFocused ? '搜寻' : '勾销'}</Text>
</TouchableOpacity>
</View>
);
};
return (<View style={styles.container}>
<Header title={'抉择城市'} />
{renderSearchView()}
<View style={{flex: 1}}>
{(!isFocused && !keyword && keyword.length < 1) || !isFocused ? (
<CityList
onCurrentCityPress={onCurrentPress}
onSelectCity={onSelectCity}
currentCity={location}
allCityList={cities}
currentCityList={currentCityList}
/>
) : (<SearchResult list={result} onSelectCity={onSelectCity} />
)}
</View>
</View>
);
};
const SearchResult = ({list, onSelectCity}) => {
return (<View style={{marginTop: 10}}>
{list.map((item, index) => (
<TouchableOpacity
activeOpacity={0.7}
key={index.toString()}
style={styles.rowView}
onPress={() => {onSelectCity(item);
}}>
<View style={styles.rowdata}>
<Text type="subheading">{item.CITY_NAME}</Text>
</View>
</TouchableOpacity>
))}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
searchView: {
height: 48,
flexDirection: 'row',
backgroundColor: '#fff',
alignItems: 'center',
paddingLeft: 10,
paddingRight: 10,
},
searchTxt: {
color: '#FC5869',
marginRight: 5,
fontSize: 16,
},
rowView: {
backgroundColor: '#fff',
height: 44,
paddingLeft: 13,
justifyContent: 'center',
},
leftIcon: {
width: 28,
height: 28,
paddingLeft: 13,
},
});
CitySelectScreen.propTypes = {
cities: PropTypes.array,
getCities: PropTypes.func,
};
export default CitySelectScreen;
CityList.js 代码如下:
import React, {useEffect, useRef} from 'react';
import {
View,
SectionList,
TouchableOpacity,
StyleSheet,
Text,
Image,
Dimensions,
} from 'react-native';
import PropTypes from 'prop-types';
import ItemSeparatorComponent from '../../../../common/ItemSeparator';
import location from '../../../../assets/images/home/location.png';
import refresh from '../../../../assets/images/home/refresh.png';
const {width} = Dimensions.get('window');
const propTypes = {
keyword: PropTypes.string,
onChangeTextKeyword: PropTypes.func,
};
const defaultProps = {};
const CityList = ({
onSelectCity,
allCityList = [],
currentCity,
onCurrentCityPress,
position: _position,
}) => {const listViewRef = useRef(null);
useEffect(() => {console.log(allCityList);
}, []);
const city =
currentCity && currentCity.city
? currentCity.city
: '定位失败,请手动抉择城市';
const _cityNameClick = cityJson => {onSelectCity(cityJson);
};
const getLocation = async () => {
// await PermissionsAndroid.request(
// PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
// );
// const res = await Geocode.reverse({
// latitude: '29.604451007313266',
// longitude: '106.52727499999997',
// });
// _position(res);
};
const CityHeader = props => {const {currentCity = '上海', onCurrentCityPress} = props;
return (
<View>
<View style={styles.sectionTitle}>
<Text style={{fontSize: 15}}> 以后城市 </Text>
</View>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => onCurrentCityPress(currentCity)}
style={styles.headerContainer}>
<View style={styles.headerLeft}>
<Image source={location} style={{width: 20, height: 20}} />
<Text type="subheading" style={{marginLeft: 2}}>
{currentCity}
</Text>
</View>
<TouchableOpacity activeOpacity={0.7} onPress={() => getLocation()}>
<Image source={refresh} style={{width: 20, height: 20}} />
</TouchableOpacity>
</TouchableOpacity>
</View>
);
};
const _renderListRow = (cityJson, rowId) => {
return (
<TouchableOpacity
activeOpacity={0.7}
key={`list_item_${cityJson.item.CITI_CD}`}
style={styles.rowView}
onPress={() => _cityNameClick(cityJson.item)}>
<View style={styles.rowData}>
<Text type="subheading">{cityJson.item.CITY_NAME}</Text>
</View>
</TouchableOpacity>
);
};
const _scrollTo = (index, letter) => {listViewRef?.current?.scrollToLocation({itemIndex: 0, sectionIndex: index});
};
const _renderRightLetters = (letter, index) => {
return (
<TouchableOpacity
key={`letter_idx_${index}`}
activeOpacity={0.6}
onPress={() => {_scrollTo(index, letter);
}}>
<View style={styles.letter}>
<Text>{letter}</Text>
</View>
</TouchableOpacity>
);
};
return (<View style={styles.container}>
<SectionList
getItemLayout={(param, index) => ({
length: 44,
offset: 44 * index,
index,
})}
ListHeaderComponent={
<CityHeader
currentCity={city}
onCurrentCityPress={onCurrentCityPress}
/>
}
ref={listViewRef}
sections={allCityList}
keyExtractor={(item, index) => index.toString()}
renderItem={_renderListRow}
ItemSeparatorComponent={() => <ItemSeparatorComponent />}
renderSectionHeader={({section: {name}}) => (<View style={styles.sectionTitle}>
<Text style={{fontSize: 15}}>{name}</Text>
</View>
)}
stickySectionHeadersEnabled={true}
/>
<View style={styles.letterSpace}>
{allCityList.map((item, index) =>
_renderRightLetters(item.name, index),
)}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F4F4F4',
},
sectionTitle: {
paddingVertical: 5,
paddingLeft: 12,
backgroundColor: '#F3F4F5',
},
iconContainer: {
height: 40,
justifyContent: 'center',
alignItems: 'center',
},
leftIconContainer: {marginEnd: 12,},
rightIconContainer: {marginStart: 8,},
headerView: {
width: width,
display: 'flex',
flexDirection: 'row',
position: 'relative',
alignItems: 'center',
backgroundColor: '#fff',
},
leftIcon: {
width: 15,
height: 13,
marginLeft: 15,
marginRight: 5,
},
rowView: {
paddingLeft: 12,
backgroundColor: '#fff',
},
rowData: {
width: width,
height: 44,
justifyContent: 'center',
},
headerContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: '#fff',
paddingHorizontal: 12,
height: 44,
},
headerLeft: {
flexDirection: 'row',
alignItems: 'center',
},
letter: {marginBottom: 3,},
letterSpace: {
position: 'absolute',
right: 4,
bottom: 0,
top: 0,
justifyContent: 'center',
},
});
CityList.propTypes = propTypes;
CityList.defaultProps = defaultProps;
export default CityList;
另外,咱们的网络申请应用的是 Axios,相干内容能够查看我之前文章的介绍:React Native 应用 axios 进行网络申请
源码:https://github.com/xiangzhihong/rn_city