Skip to content

KeyboardAwareScrollView with multiline scrolls to bottom #897

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Bowlerr opened this issue Apr 1, 2025 · 12 comments
Open

KeyboardAwareScrollView with multiline scrolls to bottom #897

Bowlerr opened this issue Apr 1, 2025 · 12 comments
Assignees
Labels
🐛 bug Something isn't working KeyboardAwareScrollView 📜 Anything related to KeyboardAwareScrollView component

Comments

@Bowlerr
Copy link

Bowlerr commented Apr 1, 2025

Describe the bug
When using KeyboardAwareScrollView with a multiline text input that has no max height, when trying to make changes, it will scroll / jump to the bottom of the screen.

Repo for reproducing
https://github.com/Bowlerr/ExampleKeyboard

To Reproduce

  1. Go to 'open example'
  2. Click on 'input'
  3. try add new line to the top
  4. try to edit the textinput
  5. See error

Expected behaviour

  • to scroll to caret

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Desktop OS: McOS 15.4
  • Device: iPhone SE 2nd Gen / any iOS device
  • RN version: 0.75.4
  • RN architecture: old
  • JS engine: hermes
  • Library version: latest
@Bowlerr
Copy link
Author

Bowlerr commented Apr 1, 2025

<!-- Failed to upload "Screen Recording 2025-04-01 at 19.08.29.mov" -->

can't seem to upload any footage

@Bowlerr
Copy link
Author

Bowlerr commented Apr 1, 2025

had to compress, ignore the watermark

screen-recording-2025-04-01-at-192134_IIKXokJK.mp4

@Bowlerr
Copy link
Author

Bowlerr commented Apr 1, 2025

screen-recording-2025-04-01-at-192826_yUHFWnnr.mp4

tried my own approach but had it's own issues but this is my expected behaviour at least in the video

import React from 'react';
import { ScrollViewProps, StyleProp, ViewStyle } from 'react-native';
import { useFocusedInputHandler, useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller';
import Animated, {
  cancelAnimation,
  scrollTo,
  useAnimatedReaction,
  useAnimatedRef,
  useAnimatedScrollHandler,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';

interface KeyboardAwareScrollViewProps extends ScrollViewProps {
  children: React.ReactNode;
  contentContainerStyle?: StyleProp<ViewStyle>;}

const KeyboardAwareScrollView: React.FC<KeyboardAwareScrollViewProps> = ({
  children,
  contentContainerStyle,
  ...props
}) => {
  const scrollViewRef = useAnimatedRef<Animated.ScrollView>();

  const scrollToY = useSharedValue(0);
  const scrollOffsetY = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler((event) => {
    scrollOffsetY.value = event.contentOffset.y;
  });

  const { height } = useReanimatedKeyboardAnimation();

  const keyboardHeight = useSharedValue(400);

  useFocusedInputHandler(
    {
      onSelectionChange: ({ selection }) => {
        'worklet';
        console.log('selection', selection, height.value, keyboardHeight.value, scrollOffsetY.value);
        if (height.value !== 0) {
          keyboardHeight.value = height.value;
        }
        if (keyboardHeight.value === 0) {return;}
        // The caret's position.
        const caretY = selection.start.y;

          cancelAnimation(scrollToY);
          scrollToY.value = scrollOffsetY.value;
          scrollToY.value = withTiming(caretY);

      },
    },
    []
  );

  useAnimatedReaction(
    () => {
      return scrollToY.value;
    },
    (current) => {
      if (current) {
        scrollTo(scrollViewRef, 0, scrollToY.value, false);
      }
    },
    []
  );

  return (
    <Animated.ScrollView
      ref={scrollViewRef}
      contentContainerStyle={contentContainerStyle}
      onScroll={scrollHandler}
      scrollEventThrottle={16}
      keyboardShouldPersistTaps="handled"
      {...props}
    >
      {children}
    </Animated.ScrollView>
  );
};

export default KeyboardAwareScrollView;

@Bowlerr
Copy link
Author

Bowlerr commented Apr 1, 2025

Related to #512 (comment)

@kirillzyusko
Copy link
Owner

Yeah, I was trying to fix it in #546

I re-wrote onTextChanged handler. The last thing to solve is to re-work "layout" watcher. Seems like I have to allocate some time and finally fix it 😅

@Bowlerr
Copy link
Author

Bowlerr commented Apr 1, 2025

Ah I tried that PR but was still having issue but seems like you are already on it!
Much appreciate the work you are putting in for this package.

If you are curious about the other issue (scroll to bottom on new line) I was facing with that PR, I got the logs in a video for you:
https://github.com/user-attachments/assets/9ec2018a-56c2-40ad-bb08-2847a5ad8fe1

I hope that is helpful :)

@Bowlerr
Copy link
Author

Bowlerr commented Apr 1, 2025

Issues:

  • When you create a new line, it scrolls to bottom of scroll view
  • When you enter the input (with keyboard), it scrolls to bottom of text input

Expected:

  • Scroll to the new line you created.
  • Scroll to where you pressed / text cursor if textbox is larger than visible screen view

I see the pain here as this is an edge case.

@Bowlerr
Copy link
Author

Bowlerr commented Apr 2, 2025

One of the issues with the new line at the beginning of the textinput is fixed by facebook/react-native@f6badca in https://github.com/facebook/react-native/releases/tag/v0.76.2 and was due to my react native version

@kirillzyusko
Copy link
Owner

@Bowlerr I've seen you forked the package. Just wanted to say that if you are going to fix this problem, then there is e2e tests that starts automatically if you open PR to main, so you can use them to verify implementation.

However, since you change the logic (depending on the cursor position instead of layout) most likely you will have to take new screenshots (I can help here if needed)).

Last time when I tried to reproduce the problem in my PR I realized, that we shouldn't rely on height changes at all (we can remove useAnimatedReaction) and we should rely only on onSelectionChange event.

However there were some desynchronization issues (like onLayout event got triggered later and I had invalid coordinates to scroll into), so I postponed work here...

Just wanted to share that info because I think it can be helpful 👀

@Bowlerr
Copy link
Author

Bowlerr commented Apr 2, 2025

@kirillzyusko thanks, I thought I would play around with the example page and see if I can find a solution

@Bowlerr
Copy link
Author

Bowlerr commented Apr 3, 2025

@kirillzyusko I think I've got a working solution but two issues on android.

One is that the multiple line inputs always start the text cursor from the bottom

The other is the keyboard opening on android causes a jump

I'll open a PR so you can check it out

@Bowlerr
Copy link
Author

Bowlerr commented Apr 3, 2025

#901

@kirillzyusko kirillzyusko added 🐛 bug Something isn't working KeyboardAwareScrollView 📜 Anything related to KeyboardAwareScrollView component labels Apr 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working KeyboardAwareScrollView 📜 Anything related to KeyboardAwareScrollView component
Projects
None yet
Development

No branches or pull requests

2 participants