Skip to content
This repository has been archived by the owner on May 7, 2022. It is now read-only.

FlatList keeps scrolling while being dismissed #25

Closed
andreialecu opened this issue May 23, 2021 · 15 comments
Closed

FlatList keeps scrolling while being dismissed #25

andreialecu opened this issue May 23, 2021 · 15 comments
Labels
feature New feature or request help wanted Extra attention is needed

Comments

@andreialecu
Copy link

I wonder if this is expected or if I'm doing something wrong.

When dismissing via interactive mode in something like WhatsApp the scroll position gets pinned in place when the keyboard starts dismissing. With this library however, the FlatList keeps scrolling underneath the keyboard.

Recording attached:

Simulator.Screen.Recording.-.iPhone.11.-.2021-05-23.at.21.20.49.mp4
@demchenkoalex
Copy link
Member

Hi @andreialecu it is a known issue. It was not a case in a version 1, where this library didn't render any scrollable inside it, however it was resulting in a ton of unnecessary re-renders, that's why I have rewritten it to accept renderScrollable. But after this change I noticed this behavior and tried to fix that spending like a day with no luck. Feel free to suggest how this can be fixed if you have any ideas.

@demchenkoalex demchenkoalex added help wanted Extra attention is needed feature New feature or request labels May 24, 2021
@andreialecu
Copy link
Author

@demchenkoalex here's a very hacky diff that does work around it:

diff --git a/example/src/App.tsx b/example/src/App.tsx
index ab7f8e0..a3e3c19 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -1,6 +1,7 @@
 import { KeyboardAccessoryView } from '@flyerhq/react-native-keyboard-accessory-view'
 import React from 'react'
 import {
+  Animated,
   FlatList,
   GestureResponderHandlers,
   SafeAreaView,
@@ -27,17 +28,25 @@ const App = () => {
     <Text style={styles.text}>{item.message}</Text>
   )
 
-  const renderScrollable = (panHandlers: GestureResponderHandlers) => (
-    <FlatList
-      data={data}
-      inverted
-      keyboardDismissMode='interactive'
-      keyExtractor={keyExtractor}
-      renderItem={renderItem}
-      showsHorizontalScrollIndicator={false}
-      {...panHandlers}
-    />
-  )
+  const renderScrollable = (
+    panHandlers: GestureResponderHandlers,
+    paddingBottom: Animated.AnimatedInterpolation
+  ) => {
+    return (
+      <FlatList
+        data={data}
+        inverted
+        keyboardDismissMode='interactive'
+        keyExtractor={keyExtractor}
+        renderItem={renderItem}
+        showsHorizontalScrollIndicator={false}
+        {...panHandlers}
+        ListHeaderComponent={
+          <Animated.View style={{ height: paddingBottom }} />
+        }
+      />
+    )
+  }
 
   return (
     <SafeAreaProvider>
diff --git a/src/KeyboardAccessoryView.tsx b/src/KeyboardAccessoryView.tsx
index 0f313dd..32e1850 100644
--- a/src/KeyboardAccessoryView.tsx
+++ b/src/KeyboardAccessoryView.tsx
@@ -22,7 +22,10 @@ interface Props {
   contentOffsetKeyboardClosed?: number
   contentOffsetKeyboardOpened?: number
   renderBackground?: () => React.ReactNode
-  renderScrollable: (panHandlers: GestureResponderHandlers) => React.ReactNode
+  renderScrollable: (
+    panHandlers: GestureResponderHandlers,
+    paddingBottom: Animated.AnimatedInterpolation
+  ) => React.ReactNode
   spaceBetweenKeyboardAndAccessoryView?: number
   style?: StyleProp<ViewStyle>
   useListenersOnAndroid?: boolean
@@ -72,13 +75,7 @@ export const KeyboardAccessoryView = React.memo(
 
     return (
       <>
-        <Animated.View
-          style={{
-            paddingBottom: Animated.subtract(offset, deltaY),
-          }}
-        >
-          {renderScrollable(panHandlers)}
-        </Animated.View>
+        {renderScrollable(panHandlers, Animated.subtract(offset, 0))}
         <Animated.View
           style={StyleSheet.flatten([
             {

It works by using an animated view as the Header (because the list is inverted, otherwise it would need to be the footer) to add the padding.

In theory this would've been easier accomplished by animating contentContainerStyle, but it cannot be animated.

Maybe this gives you some ideas on how to handle this.

@demchenkoalex
Copy link
Member

Thanks! But what about ScrollView? it does not have headers or footers..

@andreialecu
Copy link
Author

In a ScrollView it would be easier. All that needs to be done is to wrap the inner content inside a View with a margin. See: https://stackoverflow.com/a/48097978/114732

@demchenkoalex
Copy link
Member

Okay, thank you. I don't think I can write different code based on a type of scrollable I receive, because there might be too many variations how this library should handle that and in the end probably something will break anyway. Plus I'll need to add props for every scrollable imaginable to do it. Quite a lot for a visual bug fix. I am updating this library ATM adding style to close another ticket, and I will come back to this feature when feeling to spend another day figuring out how to do it once and for all. Or maybe someone will open a PR.

@andreialecu
Copy link
Author

andreialecu commented May 24, 2021

My diff removes the wrapper view and passes the padding as a parameter to renderScrollable instead. This way the end user has a choice on how to handle this.

It would be a breaking change but it's something that would also fix the other issue I opened.

@demchenkoalex
Copy link
Member

For the other issue I will be setting flex: 1 as a default, since it is not breaking stuff for me, with an option to override that change.

Overlooked the fact that it will be the user who will decide how to render the padding but I am still not convinced because of 2 factors:

  1. What if user already has custom animated header/footer, how much additional work this new solution will require.
  2. What if somebody who doesn't read documentation ignores this value, or ignores to setup the code properly. Plus a couple of examples will need to be provided like in a case of ScrollView which should be handled differently, because not everyone will spend time searching how this padding should be used.

Let me know your thoughts.

@demchenkoalex
Copy link
Member

Or maybe I will just add two versions, I will try to add a prop which will disable the wrapper.

@demchenkoalex
Copy link
Member

Hmm after trying out animated header version I can see that when you dismiss a keyboard slowly to the very bottom, when a finger is released list scrolls anyway (probably because the height animates at that point). I guess this behavior will anyway require additional round of thinking.

@andreialecu
Copy link
Author

andreialecu commented May 24, 2021

I also noticed that glitch when dismissing the keyboard by releasing it. Not sure why it's caused by the interactive gesture, but not by simply dismissing it via tapping away.

An option to disable the built in Animated.View container would work as a quick fix for this, so users can tweak it on the app side.

I'd also assume there are probably other use cases where the container may need to be overridden.

@andreialecu
Copy link
Author

andreialecu commented May 24, 2021

This is a cleaner diff that works (besides the scroll glitch when dismissing the keyboard):

diff --git a/example/src/App.tsx b/example/src/App.tsx
index ab7f8e0..eed25ef 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -27,7 +27,10 @@ const App = () => {
     <Text style={styles.text}>{item.message}</Text>
   )
 
-  const renderScrollable = (panHandlers: GestureResponderHandlers) => (
+  const renderScrollable = (
+    panHandlers: GestureResponderHandlers,
+    offset: number
+  ) => (
     <FlatList
       data={data}
       inverted
@@ -35,6 +38,8 @@ const App = () => {
       keyExtractor={keyExtractor}
       renderItem={renderItem}
       showsHorizontalScrollIndicator={false}
+      contentContainerStyle={{ paddingTop: offset }}
+      scrollIndicatorInsets={{ top: offset }}
       {...panHandlers}
     />
   )
diff --git a/src/KeyboardAccessoryView.tsx b/src/KeyboardAccessoryView.tsx
index 0f313dd..a2c838c 100644
--- a/src/KeyboardAccessoryView.tsx
+++ b/src/KeyboardAccessoryView.tsx
@@ -22,7 +22,10 @@ interface Props {
   contentOffsetKeyboardClosed?: number
   contentOffsetKeyboardOpened?: number
   renderBackground?: () => React.ReactNode
-  renderScrollable: (panHandlers: GestureResponderHandlers) => React.ReactNode
+  renderScrollable: (
+    panHandlers: GestureResponderHandlers,
+    offset: number
+  ) => React.ReactNode
   spaceBetweenKeyboardAndAccessoryView?: number
   style?: StyleProp<ViewStyle>
   useListenersOnAndroid?: boolean
@@ -72,13 +75,7 @@ export const KeyboardAccessoryView = React.memo(
 
     return (
       <>
-        <Animated.View
-          style={{
-            paddingBottom: Animated.subtract(offset, deltaY),
-          }}
-        >
-          {renderScrollable(panHandlers)}
-        </Animated.View>
+        {renderScrollable(panHandlers, offset)}
         <Animated.View
           style={StyleSheet.flatten([
             {

Edit: It appears that sometimes there's a gap left at the top of the scroll view with this contentContainerStyle approach, but when using a HeaderComponent with a fixed height the glitch doesn't exist (like my previous diff in #25 (comment)). Example:

-      contentContainerStyle={{ paddingTop: offset }}
+      ListHeaderComponent={<View style={{ height: offset }} />}

@Fortidude
Copy link

With the above solution we have this:

  • dismiss with gesture quick = scroll view is moving a bit to top
  • dismiss gentle = jumping when the offset is changing from keyboard height to 0

I spend whole day trying to fix this but no luck. The main issue is inverted scroll list.

@andreialecu
Copy link
Author

This is now part of RN 0.68: facebook/react-native#31402

Together with InputAccessoryView it should provide native support for this behavior.

@demchenkoalex
Copy link
Member

Awesome! Will double check how this works and archive this repo with a sample code.

@demchenkoalex
Copy link
Member

Works perfectly, thanks for the heads up @andreialecu. Please refer to the link above for the detailed instructions for RN 0.68. This will be deprecated.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants