Dropdown.js 5.1 KB

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