Skip to content

Commit a31cfe3

Browse files
authored
feat: improve rendering (#151)
1 parent 3927d74 commit a31cfe3

File tree

2 files changed

+54
-43
lines changed

2 files changed

+54
-43
lines changed

example/components/ModalExample.tsx

+23-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, { memo, useState } from 'react'
2-
import { Button, Dimensions, Modal, SafeAreaView, View } from 'react-native'
2+
import { Button, Dimensions, KeyboardAvoidingView, Modal, Platform, SafeAreaView, ScrollView, View } from 'react-native'
33
import { AutocompleteDropdownContextProvider } from 'react-native-autocomplete-dropdown'
4-
import { RemoteDataSetExample } from './RemoteDataSetExample'
54
import { LocalDataSetExample } from './LocalDataSetExample'
65

76
export const ModalExample = memo(() => {
@@ -14,16 +13,28 @@ export const ModalExample = memo(() => {
1413
presentationStyle="formSheet"
1514
animationType="slide"
1615
onRequestClose={() => setOpened(false)}>
17-
<SafeAreaView style={{ flex: 1, backgroundColor: 'transparent' }}>
18-
<AutocompleteDropdownContextProvider>
19-
<View style={{ paddingHorizontal: 20, flex: 1, paddingTop: 20 }}>
20-
<LocalDataSetExample />
21-
<View style={{ height: Dimensions.get('screen').height - 300 }} />
22-
<RemoteDataSetExample />
23-
<Button onPress={() => setOpened(false)} title="Close modal" />
24-
</View>
25-
</AutocompleteDropdownContextProvider>
26-
</SafeAreaView>
16+
<AutocompleteDropdownContextProvider>
17+
<SafeAreaView style={{ flex: 1 }}>
18+
<KeyboardAvoidingView
19+
style={{ flex: 1 }}
20+
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
21+
keyboardVerticalOffset={Platform.select({ ios: 75, default: 0 })}>
22+
<ScrollView
23+
nestedScrollEnabled
24+
keyboardDismissMode="on-drag"
25+
keyboardShouldPersistTaps="handled"
26+
contentInsetAdjustmentBehavior="automatic"
27+
style={{ flex: 1 }}>
28+
<View style={{ paddingHorizontal: 20, flex: 1, paddingTop: 20 }}>
29+
<LocalDataSetExample />
30+
<View style={{ height: Dimensions.get('screen').height - 300 }} />
31+
<LocalDataSetExample />
32+
<Button onPress={() => setOpened(false)} title="Close modal" />
33+
</View>
34+
</ScrollView>
35+
</KeyboardAvoidingView>
36+
</SafeAreaView>
37+
</AutocompleteDropdownContextProvider>
2738
</Modal>
2839
</>
2940
)

src/AutocompleteDropdownContext.tsx

+31-31
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ export const AutocompleteDropdownContextProvider: FC<IAutocompleteDropdownContex
3838
const [show, setShow] = useState(false)
3939
const [dropdownHeight, setDropdownHeight] = useState(0)
4040
const [inputMeasurements, setInputMeasurements] = useState<
41-
{ x: number; y: number; width: number; height: number } | undefined
41+
{ x: number; topY: number; bottomY: number; width: number; height: number } | undefined
4242
>()
4343
const [opacity, setOpacity] = useState(0)
44-
const [contentStyles, setContentStyles] = useState<{ top: number; left: number; width?: number } | undefined>(
45-
undefined,
46-
)
44+
const [contentStyles, setContentStyles] = useState<
45+
{ top?: number; left: number; width?: number; bottom?: number } | undefined
46+
>(undefined)
4747
const activeInputContainerRef = useRef<View>(null)
4848
const wrapperRef = useRef<View>(null)
4949
const activeControllerRef = useRef<IAutocompleteDropdownRef | null>(null)
@@ -58,58 +58,58 @@ export const AutocompleteDropdownContextProvider: FC<IAutocompleteDropdownContex
5858

5959
if (dropdownHeight && direction === 'up') {
6060
setContentStyles({
61-
top: inputMeasurements.y - dropdownHeight - 10 - headerOffset,
61+
bottom: inputMeasurements.bottomY + 5 + headerOffset,
62+
top: undefined,
6263
left: inputMeasurements.x,
6364
width: inputMeasurements.width,
6465
})
6566
setOpacity(1)
6667
} else if (direction === 'down') {
6768
setContentStyles({
68-
top: inputMeasurements.y + inputMeasurements.height + 5 + headerOffset,
69+
top: inputMeasurements.topY + inputMeasurements.height + 5 + headerOffset,
70+
bottom: undefined,
6971
left: inputMeasurements.x,
7072
width: inputMeasurements.width,
7173
})
7274
setOpacity(1)
7375
}
74-
}, [
75-
direction,
76-
dropdownHeight,
77-
headerOffset,
78-
inputMeasurements?.height,
79-
inputMeasurements?.width,
80-
inputMeasurements?.x,
81-
inputMeasurements?.y,
82-
])
76+
}, [direction, dropdownHeight, headerOffset, inputMeasurements])
77+
78+
const recalculatePosition = useCallback((showAfterCalculation = false) => {
79+
activeInputContainerRef?.current?.measure((x, y, width, height, inputPageX, inputPageY) => {
80+
wrapperRef.current?.measure((wrapperX, wrapperY, wrapperW, wrapperH, wrapperPageX, wrapperPageY) => {
81+
const currentMeasurement = {
82+
width,
83+
height,
84+
x: inputPageX,
85+
topY: inputPageY - wrapperPageY,
86+
bottomY: wrapperH - inputPageY + wrapperPageY,
87+
}
88+
setInputMeasurements(prev =>
89+
JSON.stringify(prev) === JSON.stringify(currentMeasurement) ? prev : currentMeasurement,
90+
)
91+
showAfterCalculation && setShow(true)
92+
})
93+
})
94+
}, [])
8395

8496
useEffect(() => {
8597
if (content) {
86-
activeInputContainerRef?.current?.measure((x, y, width, height, pageX, pageY) => {
87-
wrapperRef.current?.measure((wrapperX, wrapperY, wrapperW, wrapperH, wrapperPageX, wrapperPageY) => {
88-
setInputMeasurements({ x: pageX, y: pageY - wrapperPageY, width, height })
89-
setShow(true)
90-
})
91-
})
98+
recalculatePosition(true)
9299
} else {
93100
setInputMeasurements(undefined)
94101
setDropdownHeight(0)
95102
setOpacity(0)
96103
setContentStyles(undefined)
97104
setShow(false)
98105
}
99-
}, [content])
106+
}, [content, recalculatePosition])
100107

101108
useEffect(() => {
102109
if (show && !!opacity) {
103110
positionTrackingIntervalRef.current = setInterval(() => {
104111
requestAnimationFrame(() => {
105-
activeInputContainerRef?.current?.measure((_x, _y, width, height, inputPageX, inputPageY) => {
106-
wrapperRef.current?.measure((wrapperX, wrapperY, wrapperW, wrapperH, wrapperPageX, wrapperPageY) => {
107-
const currentMeasurement = { x: inputPageX, y: inputPageY - wrapperPageY, width, height }
108-
setInputMeasurements(prev =>
109-
JSON.stringify(prev) === JSON.stringify(currentMeasurement) ? prev : currentMeasurement,
110-
)
111-
})
112-
})
112+
recalculatePosition()
113113
})
114114
}, 16)
115115
} else {
@@ -119,7 +119,7 @@ export const AutocompleteDropdownContextProvider: FC<IAutocompleteDropdownContex
119119
return () => {
120120
clearInterval(positionTrackingIntervalRef.current)
121121
}
122-
}, [opacity, show])
122+
}, [recalculatePosition, opacity, show])
123123

124124
const onLayout: ViewProps['onLayout'] = useCallback((e: LayoutChangeEvent) => {
125125
setDropdownHeight(e.nativeEvent.layout.height)

0 commit comments

Comments
 (0)