Dropdown.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. setChange(valueKey ? item[valueKey] : item, 0);
  51. } else {
  52. changeItem(true);
  53. }
  54. }
  55. }, [list]);
  56. const changeItem = (init) => {
  57. if (nameKey && valueKey) {
  58. for (var i = 0; i < list.length; i++) {
  59. let item = list[i];
  60. if (item[valueKey] == value) {
  61. changeValue(prefixText+item[nameKey]+suffixText);
  62. if (list.length > 20) {
  63. setCurrent(i > 5 ? i - 4 : 0);
  64. }
  65. return;
  66. }
  67. }
  68. if (init) {
  69. const item = list[0];
  70. setChange(item[valueKey], 0);
  71. }
  72. } else {
  73. if (init) {
  74. let _i = list.indexOf(value);
  75. if (_i >= 0) {
  76. setChange(list[_i], _i);
  77. } else {
  78. setChange(list[0], 0);
  79. }
  80. } else {
  81. changeValue(prefixText+value+suffixText);
  82. }
  83. }
  84. }
  85. const showList = () => {
  86. Keyboard.dismiss();
  87. showDialog(true);
  88. /*if (currentIndex > 0) {
  89. console.log(refFlat.current);
  90. setTimeout(() => {
  91. if (refFlat.current) {
  92. refFlat.current.scrollToIndex({
  93. animated: false,
  94. index: currentIndex,
  95. viewPosition: 0.5
  96. })
  97. }
  98. }, 100)
  99. }*/
  100. }
  101. const renderItem = ({ item, index, separators }) => {
  102. const _value = (valueKey ? item[valueKey] : item);
  103. if (customerItemView) {
  104. return customerItemView(item, index, () => {
  105. showDialog(false);
  106. setChange(_value, index);
  107. })
  108. } else {
  109. return (
  110. <Button
  111. text={prefixList + (nameKey ? item[nameKey] : item) + suffixList}
  112. style={styles.itemView}
  113. textStyle={styles.itemText}
  114. onClick={() => {
  115. showDialog(false);
  116. setChange(_value, index);
  117. }}
  118. iconRight={(_value == value) && <MaterialIcons name="radio-button-checked" color={colorAccent} size={22}/>}
  119. />
  120. )
  121. }
  122. }
  123. const setChange = (v, i) => {
  124. setTimeout(() => {
  125. if (onChange) {
  126. onChange(v, i)
  127. }
  128. }, 300);
  129. }
  130. return (
  131. <>
  132. <Pressable
  133. style={({pressed }) => [
  134. pressed && isIOS && {
  135. backgroundColor: rippleColor
  136. },
  137. style
  138. ]}
  139. android_ripple={rippleStyle}
  140. onPress={() => showList()}>
  141. { showText &&
  142. ( selected
  143. ? <Text style={[ui.flex1, textStyle]} numberOfLines={1}>{selected}</Text>
  144. : <Text style={[textStyle, placeholderStyle]} numberOfLines={1}>{placeholder}</Text>
  145. )
  146. }
  147. { showIcon &&
  148. <Entypo
  149. name={'chevron-thin-down'}
  150. size={14}
  151. color={iconColor}
  152. style={iconStyle}
  153. />
  154. }
  155. </Pressable>
  156. <Modal
  157. isVisible={visible}
  158. onTouchOutside={() => showDialog(false)}
  159. onBackdropPress={() => showDialog(false)}
  160. onBackButtonPress={() => showDialog(false)}
  161. {...Dialog.modalProps}
  162. >
  163. <View style={styles.dialog}>
  164. { title !== '' && <Text style={styles.title}>{title}</Text> }
  165. <FlatList
  166. data={list}
  167. ref={refFlat}
  168. renderItem={renderItem}
  169. initialScrollIndex={currentIndex}
  170. keyExtractor={(item, index) => index}
  171. style={{maxHeight: $vh(55)}}
  172. getItemLayout={(data, index) => (
  173. {length: itemHeight, offset: itemHeight * index, index}
  174. )}
  175. />
  176. </View>
  177. </Modal>
  178. </>
  179. );
  180. }
  181. const styles = StyleSheet.create({
  182. dialog: {
  183. width: getDialogWidth(),
  184. marginLeft: 'auto',
  185. marginRight: 'auto',
  186. paddingTop: isIOS ? 12 : 8,
  187. paddingBottom: isIOS ? 12 : 8,
  188. backgroundColor: colorLight,
  189. borderRadius: isIOS ? 10 : 3
  190. },
  191. title: {
  192. color: '#000',
  193. paddingTop: 8,
  194. paddingLeft: 16,
  195. paddingBottom: 16,
  196. fontSize: 17,
  197. fontWeight: 'bold'
  198. },
  199. valueView: {
  200. paddingLeft: 16,
  201. paddingRight: 32,
  202. alignItems: 'center',
  203. flexDirection: 'row'
  204. },
  205. valueText: {
  206. color: textPrimary,
  207. fontSize: 16
  208. },
  209. itemView: {
  210. borderRadius: 0,
  211. backgroundColor: colorLight
  212. },
  213. itemText: {
  214. flex: 1,
  215. color: textPrimary,
  216. fontSize: 14,
  217. textAlign: 'left',
  218. fontWeight: 'normal'
  219. },
  220. placeText: {
  221. flex: 1,
  222. color: textPlacehoder
  223. },
  224. iconStyle: {
  225. top: '50%',
  226. right: 16,
  227. marginTop: -7,
  228. position: 'absolute',
  229. }
  230. });