@@ -20,6 +20,7 @@ import {
2020 KeyboardAvoidingView ,
2121 Modal ,
2222 Pressable ,
23+ ScrollView ,
2324 StyleSheet ,
2425 Text ,
2526 TextInput ,
@@ -57,54 +58,56 @@ const CloseButton = (props: {setModalOpen: boolean => void}) => {
5758 ) ;
5859} ;
5960
61+ type KeyboardAvoidingBehavior = 'padding' | 'position' | 'height' ;
62+
63+ const BEHAVIORS : Array < KeyboardAvoidingBehavior > = [
64+ 'padding',
65+ 'position',
66+ 'height',
67+ ];
68+
69+ const BehaviorPicker = (props: {
70+ behavior : KeyboardAvoidingBehavior ,
71+ setBehavior : KeyboardAvoidingBehavior => void ,
72+ } ) => {
73+ return (
74+ < View
75+ style = { {
76+ flexDirection : 'row' ,
77+ justifyContent : 'center' ,
78+ } } >
79+ { BEHAVIORS . map ( behavior => {
80+ const selected = props . behavior === behavior ;
81+ return (
82+ < TouchableOpacity
83+ key = { behavior }
84+ onPress = { ( ) => props . setBehavior ( behavior ) }
85+ style = { [
86+ styles . pillStyle ,
87+ { backgroundColor : selected ? 'blue' : 'white' } ,
88+ ] } >
89+ < Text
90+ style = { {
91+ textTransform : 'capitalize' ,
92+ color : selected ? 'white' : 'blue' ,
93+ } } >
94+ { behavior }
95+ </ Text >
96+ </ TouchableOpacity >
97+ ) ;
98+ } ) }
99+ </ View >
100+ ) ;
101+ } ;
102+
60103const KeyboardAvoidingViewBehaviour = () => {
61104 const [ modalOpen , setModalOpen ] = useState ( false ) ;
62- const [ behavior , setBehavior ] = useState ( 'padding' ) ;
105+ const [ behavior , setBehavior ] = useState < KeyboardAvoidingBehavior > ( 'padding' ) ;
63106 return (
64107 < View style = { styles . outerContainer } >
65108 < Modal animationType = "fade" visible = { modalOpen } >
66- { /* $FlowFixMe[incompatible-type] Natural Inference rollout. See
67- * https://fburl.com/workplace/6291gfvu */ }
68109 < KeyboardAvoidingView behavior = { behavior } style = { styles . container } >
69- < View
70- style = { {
71- flexDirection : 'row' ,
72- justifyContent : 'center' ,
73- } } >
74- < TouchableOpacity
75- onPress = { ( ) => setBehavior ( 'padding' ) }
76- style = { [
77- styles . pillStyle ,
78- { backgroundColor : behavior === 'padding' ? 'blue' : 'white' } ,
79- ] } >
80- < Text style = { { color : behavior === 'padding' ? 'white' : 'blue' } } >
81- Padding
82- </ Text >
83- </ TouchableOpacity >
84- < TouchableOpacity
85- onPress = { ( ) => setBehavior ( 'position' ) }
86- style = { [
87- styles . pillStyle ,
88- { backgroundColor : behavior === 'position' ? 'blue' : 'white' } ,
89- ] } >
90- < Text style = { { color : behavior === 'position' ? 'white' : 'blue' } } >
91- Position
92- </ Text >
93- </ TouchableOpacity >
94- < TouchableOpacity
95- onPress = { ( ) => setBehavior ( 'height' ) }
96- style = { [
97- styles . pillStyle ,
98- { backgroundColor : behavior === 'height' ? 'blue' : 'white' } ,
99- ] } >
100- < Text
101- style = { {
102- color : behavior === 'height' ? 'white' : 'blue' ,
103- } } >
104- Height
105- </ Text >
106- </ TouchableOpacity >
107- </ View >
110+ < BehaviorPicker behavior = { behavior } setBehavior = { setBehavior } />
108111 < CloseButton setModalOpen = { setModalOpen } />
109112 < TextInputForm />
110113 </ KeyboardAvoidingView >
@@ -189,6 +192,46 @@ const KeyboardAvoidingContentContainerStyle = () => {
189192 ) ;
190193} ;
191194
195+ const KeyboardAvoidingScrollView = () => {
196+ const [ modalOpen , setModalOpen ] = useState ( false ) ;
197+ const [ behavior , setBehavior ] = useState < KeyboardAvoidingBehavior > ( 'padding' ) ;
198+ return (
199+ < View >
200+ < Modal animationType = "fade" visible = { modalOpen } >
201+ < KeyboardAvoidingView
202+ behavior = { behavior }
203+ style = { styles . scrollViewContainer }
204+ contentContainerStyle = { { flex : 1 } } >
205+ < View style = { { paddingHorizontal : 20 } } >
206+ < BehaviorPicker behavior = { behavior } setBehavior = { setBehavior } />
207+ < CloseButton setModalOpen = { setModalOpen } />
208+ </ View >
209+ < ScrollView
210+ style = { { flex : 1 } }
211+ contentContainerStyle = { styles . scrollViewContent } >
212+ { Array . from ( { length : 10 } , ( _ , index ) => (
213+ < View key = { index } style = { styles . fillerItem } >
214+ < Text style = { { fontSize : 16 } } > Item { index + 1 } </ Text >
215+ </ View >
216+ ) ) }
217+ < TextInput placeholder = "Name" style = { [ styles . textInput ] } />
218+ < TextInput
219+ placeholder = "Message"
220+ multiline
221+ style = { [ styles . textInput , styles . multilineTextInput ] }
222+ />
223+ </ ScrollView >
224+ </ KeyboardAvoidingView >
225+ </ Modal >
226+ < View >
227+ < Pressable onPress = { ( ) => setModalOpen ( true ) } >
228+ < Text style = { styles . touchableText } > Open Example</ Text >
229+ </ Pressable >
230+ </ View >
231+ </ View >
232+ ) ;
233+ } ;
234+
192235const styles = StyleSheet.create({
193236 outerContainer : {
194237 flex : 1 ,
@@ -204,13 +247,34 @@ const styles = StyleSheet.create({
204247 paddingTop : 20 ,
205248 backgroundColor : '#abdebf' ,
206249 } ,
250+ scrollViewContainer : {
251+ flex : 1 ,
252+ paddingTop : 100 ,
253+ } ,
254+ scrollViewContent : {
255+ paddingBottom : 60 ,
256+ paddingHorizontal : 20 ,
257+ } ,
258+ fillerItem : {
259+ backgroundColor : '#eeeeee' ,
260+ borderRadius : 8 ,
261+ paddingVertical : 16 ,
262+ paddingHorizontal : 12 ,
263+ marginBottom : 20 ,
264+ alignItems : 'center' ,
265+ } ,
207266 textInput : {
208267 borderRadius : 5 ,
209268 borderWidth : 1 ,
210- height : 44 ,
269+ minHeight : 44 ,
211270 marginBottom : 20 ,
212271 paddingHorizontal : 10 ,
213272 } ,
273+ multilineTextInput : {
274+ minHeight : 88 ,
275+ paddingVertical : 10 ,
276+ textAlignVertical : 'top' ,
277+ } ,
214278 pillStyle : {
215279 padding : 10 ,
216280 marginHorizontal : 5 ,
@@ -267,4 +331,13 @@ exports.examples = [
267331 return < KeyboardAvoidingContentContainerStyle / > ;
268332 } ,
269333 } ,
334+ {
335+ title : 'Keyboard Avoiding View with ScrollView' ,
336+ description :
337+ ( 'A ScrollView with filler content and TextInputs at the bottom inside the scrollable content. ' +
338+ 'TextInputs should still be visible when focused.' ) as string ,
339+ render ( ) : React . Node {
340+ return < KeyboardAvoidingScrollView / > ;
341+ } ,
342+ } ,
270343] as Array < RNTesterModuleExample > ;
0 commit comments