Dropdown.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import React, { useEffect, useRef, useState } from 'react';
  2. import { FlatList, Keyboard, Pressable, StyleSheet, Text, View } from 'react-native';
  3. import Modal from 'react-native-modal';
  4. import Button from './Button';
  5. import Dialog, { getDialogWidth } from './Dialog';
  6. //const DialogMaxWidth = $vw(85) > 500 ? 500 : $vw(85);
  7. //const DialogIOSWidth = $vw(75) > 450 ? 450 : $vw(75);
  8. export default Dropdown = ({
  9. list = [],
  10. title = '',
  11. value,
  12. onChange,
  13. nameKey,
  14. valueKey,
  15. prefixText='',//前缀
  16. suffixText='',//后缀
  17. itemHeight=50,
  18. prefixList='',//列表前缀
  19. suffixList='',//列表后缀
  20. rippleStyle=ripple,
  21. style = styles.valueView,
  22. textStyle = styles.valueText,
  23. placeholderStyle=styles.placeText,
  24. placeholder='',
  25. showText = true,
  26. showIcon = true,
  27. iconColor = '#888',
  28. iconStyle = styles.iconStyle,
  29. autoSelect = true,
  30. customerItemView
  31. }) => {
  32. const refFlat = useRef();
  33. const [visible, showDialog] = useState(false);
  34. const [selected, changeValue] = useState('');
  35. const [currentIndex, setCurrent] = useState(0);
  36. useEffect(() => {
  37. if (value !== selected) {
  38. changeItem();
  39. }
  40. }, [value, []]);
  41. useEffect(() => {
  42. if (autoSelect && list.length > 0) {
  43. if (value == undefined) {
  44. const item = list[0];
  45. /*if (nameKey) {
  46. changeValue(item[nameKey]);
  47. } else {
  48. changeValue(item);
  49. }*/
  50. if (onChange) {
  51. onChange(valueKey ? item[valueKey] : item, 0)
  52. }
  53. } else {
  54. changeItem();
  55. }
  56. }
  57. }, [list]);
  58. const changeItem = () => {
  59. if (nameKey && valueKey) {
  60. for (var i = 0; i < list.length; i++) {
  61. let item = list[i];
  62. if (item[valueKey] == value) {
  63. changeValue(prefixText+item[nameKey]+suffixText);
  64. if (list.length > 20) {
  65. setCurrent(i > 5 ? i - 4 : 0);
  66. }
  67. break;
  68. }
  69. }
  70. } else {
  71. changeValue(prefixText+value+suffixText);
  72. }
  73. }
  74. const showList = () => {
  75. Keyboard.dismiss();
  76. showDialog(true);
  77. /*if (currentIndex > 0) {
  78. console.log(refFlat.current);
  79. setTimeout(() => {
  80. if (refFlat.current) {
  81. refFlat.current.scrollToIndex({
  82. animated: false,
  83. index: currentIndex,
  84. viewPosition: 0.5
  85. })
  86. }
  87. }, 100)
  88. }*/
  89. }
  90. const renderItem = ({ item, index, separators }) => {
  91. if (customerItemView) {
  92. return customerItemView(item, index, () => {
  93. showDialog(false);
  94. if (onChange) {
  95. onChange(valueKey ? item[valueKey] : item, index)
  96. }
  97. })
  98. } else {
  99. return (
  100. <Button
  101. text={prefixList + (nameKey ? item[nameKey] : item) + suffixList}
  102. style={styles.itemView}
  103. textStyle={styles.itemText}
  104. onClick={() => {
  105. showDialog(false);
  106. if (onChange) {
  107. onChange(valueKey ? item[valueKey] : item, index)
  108. }
  109. }
  110. }/>
  111. )
  112. }
  113. }
  114. return (
  115. <>
  116. <Pressable
  117. style={({pressed }) => [
  118. pressed && isIOS && {
  119. backgroundColor: rippleColor
  120. },
  121. style
  122. ]}
  123. android_ripple={rippleStyle}
  124. onPress={() => showList()}>
  125. { showText &&
  126. ( selected
  127. ? <Text style={[ui.flex1, textStyle]} numberOfLines={1}>{selected}</Text>
  128. : <Text style={[textStyle, placeholderStyle]} numberOfLines={1}>{placeholder}</Text>
  129. )
  130. }
  131. { showIcon &&
  132. <Entypo
  133. name={'chevron-thin-down'}
  134. size={14}
  135. color={iconColor}
  136. style={iconStyle}
  137. />
  138. }
  139. </Pressable>
  140. <Modal
  141. isVisible={visible}
  142. onTouchOutside={() => showDialog(false)}
  143. onBackdropPress={() => showDialog(false)}
  144. onBackButtonPress={() => showDialog(false)}
  145. {...Dialog.modalProps}
  146. >
  147. <View style={styles.dialog}>
  148. { title !== '' && <Text style={styles.title}>{title}</Text> }
  149. <FlatList
  150. data={list}
  151. ref={refFlat}
  152. renderItem={renderItem}
  153. initialScrollIndex={currentIndex}
  154. keyExtractor={(item, index) => index}
  155. style={{maxHeight: $vh(55)}}
  156. getItemLayout={(data, index) => (
  157. {length: itemHeight, offset: itemHeight * index, index}
  158. )}
  159. />
  160. </View>
  161. </Modal>
  162. </>
  163. );
  164. }
  165. const styles = StyleSheet.create({
  166. dialog: {
  167. width: getDialogWidth(),
  168. marginLeft: 'auto',
  169. marginRight: 'auto',
  170. paddingTop: isIOS ? 12 : 8,
  171. paddingBottom: isIOS ? 12 : 8,
  172. backgroundColor: colorLight,
  173. borderRadius: isIOS ? 10 : 3
  174. },
  175. title: {
  176. color: '#000',
  177. paddingTop: 8,
  178. paddingLeft: 16,
  179. paddingBottom: 16,
  180. fontSize: 17,
  181. fontWeight: 'bold'
  182. },
  183. valueView: {
  184. paddingLeft: 16,
  185. paddingRight: 32,
  186. alignItems: 'center',
  187. flexDirection: 'row'
  188. },
  189. valueText: {
  190. color: '#000',
  191. fontSize: 16
  192. },
  193. itemView: {
  194. borderRadius: 0,
  195. backgroundColor: colorLight
  196. },
  197. itemText: {
  198. flex: 1,
  199. color: textPrimary,
  200. fontSize: 14,
  201. textAlign: 'left',
  202. fontWeight: 'normal'
  203. },
  204. placeText: {
  205. flex: 1,
  206. color: textPlacehoder
  207. },
  208. iconStyle: {
  209. top: '50%',
  210. right: 16,
  211. marginTop: -7,
  212. position: 'absolute',
  213. }
  214. });