Skip to content

[W.I.P] KeyboardAwareScrollView Rework To work with multilines #901

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

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

Bowlerr
Copy link

@Bowlerr Bowlerr commented Apr 3, 2025

📜 Description

Will write up a proper description later and clean up the code.

current issue until done (Android):

  • The multiple line inputs always start the text cursor from the bottom on first focus

    • ideally I want it to start where I press

💡 Motivation and Context

📢 Changelog

JS

iOS

Android

🤔 How Has This Been Tested?

📸 Screenshots (if appropriate):

📝 Checklist

  • CI successfully passed
  • I added new mocks and corresponding unit-tests if library API was changed

@Bowlerr
Copy link
Author

Bowlerr commented Apr 4, 2025

Demo.mp4

@Bowlerr
Copy link
Author

Bowlerr commented Apr 4, 2025

@kirillzyusko lmk what you think

onLayout={onScrollViewLayout}
onScroll={scrollHandler}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not very trivial to pass handler in such way. We have to forward that event to external handlers. And it's tricky, because those handlers can be worklet/plain-js handlers. I'll link a chain of PR here in chronological order: #339 #408 #490 #500

Comment on lines +632 to +635
() => scrollY.value,
(current) => {
scrollTo(scrollViewAnimatedRef, 0, current, false);
},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it gives an effect of "keep strong distance between caret and keyboard"

I think default iOS/Android implementation perform scroll only if needed, i. e. here

image

When you move pointer higher:

image

It scrolls (but the expected behavior is that it shouldn't)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change this. I liked the effect for inputs that don't fit inside the visible area. Without this the user would need to scroll themselves or beginning to type for the move to happen.

I can change it so the scroll stops at the top of the input instead? and then follows from the caret at bottom until it reaches the bottom of the input where it will sit if it has a maxHeight?

Comment on lines +241 to +272
scrollY.value = spring
? withSpring(goal, { damping: 100, stiffness: 100 }, (finished) => {
log(
"Goal:",
goal,
"Current:",
scrollOffsetY.value,
"EndingPosition:",
scrollY.value,
"Distance From Goal:",
Math.abs(scrollOffsetY.value - goal),
"Finished:",
finished,
);
isScrolling.value = false;
})
: withTiming(goal, undefined, (finished) => {
log(
"Goal:",
goal,
"Current:",
scrollOffsetY.value,
"EndingPosition:",
scrollY.value,
"Distance From Goal:",
Math.abs(scrollOffsetY.value - goal),
"Finished:",
finished,
);
isScrolling.value = false;
});
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? We should perform scroll based on a keyboard position? So we should scroll from onMove handlers.

Plain scroll can happen when text input grows, but in this case scrollTo(..., true) with default animation works also pretty well 🤔

Comment on lines 92 to 96
{new Array(10).fill(0).map((_, i) => (
{new Array(5).fill(0).map((_, i) => (
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you modify code example in such way there is 100% guarantee that e2e tests will fail, because they expect to have certain amount of inputs.

I'd suggest to revert these changes (I understand that it's more convenient not scroll through entire form, but you can keep these changes locally and not commit them to the repository)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Planned to clean this up and wasn't suppose to commit the changes to the example.

@@ -13,6 +13,10 @@ import type { StackScreenProps } from "@react-navigation/stack";
type Props = StackScreenProps<ExamplesStackParamList>;
const snapToOffsets = [125, 225, 325, 425, 525, 625];

const BIG_TEXT_TWO = `Where does it come from?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe let's not repeat code and re-use variables?

But again, for playground code you can keep a local changes and not commit them to the repository.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Planned to clean this up and wasn't suppose to commit the changes to the example.

@kirillzyusko
Copy link
Owner

And feedback based on video:

  • 0:08-0:09 it feels a little bit wrong, that you see scroll and at certain point of time this scroll continues. Do we have selection coordinates before onStart-keyboard event? If not then it can be a bug in keyboard-controller and I think it should be fixed (basically before onStart you should have these coordinates, because we already have focused input)
  • 0:13-0:15 - I think we shouldn't scroll to follow cursor position. If scroll remains in a visible area then better not scroll, since user can still see the input.
  • 0:25-0:27 - feels like scroll is stuttering a little bit?
  • 0:50-0:51 - why we scrolled such a big distance? I thought we always rely on selection coordinates (not on layout anymore)?
  • 0:59-1:00 - animation feels desynchronized?
  • when back scroll turned off it looks like you add back scroll? And when it's enabled I don't see a back scroll?
  • not sure, but since you modified example it looks like snap points are broken now

Overall you did a great job 💪 But certain points must be addressed I don't think I can merge PR in a current state 🤔

But if you don't want to spend too much time on going back-and-forth with review, then you can use that modified version of KeyboardAwareScrollView in your project, since that component uses public API of the lib 🙂

Also if you want we can have a conversation in discord, it should significantly improve our communication process 😊

@Bowlerr
Copy link
Author

Bowlerr commented Apr 4, 2025

I'm going away this weekend so have not much time but would love to jump on discord next week if that works with you @kirillzyusko


0:08-0:09 - feels off

  • Agreed, I believe this is because of the withSpring. Will remove and find another solution to the issue it solved.
    the issue I was solving was: on iOS when you select the last input of the scrolllist, it is off by a few pixels ( if you remove the margin from the text input). My solution is hacky for such an edge case so happy to remove it.

0:13-0:15 - I think we shouldn't scroll to follow cursor position. If scroll remains in a visible area then better not scroll, since user can still see the input.

  • Can change to this, can always add a prop to follow cursor on long inputs?

0:25-0:27 - feels like scroll is stuttering a little bit?

  • need to work on animation timings or could be slow in debug mode on a simulator which i've experienced a lot in the past.

0:50-0:51 - why we scrolled such a big distance? I thought we always rely on selection coordinates (not on layout anymore)?

  • If the input fit within the viewable space in the scrollview -> Scroll input to fill view
  • if it doesn't -> follow selection coordinates

0:59-1:00 - animation feels desynchronized?

  • agree, I'll look into this.

when back scroll turned off it looks like you add back scroll? And when it's enabled I don't see a back scroll?

  • On the example, when toggle is enabled, it disables the back scroll. its enabling the disabling.

not sure, but since you modified example it looks like snap points are broken now

  • How are they supposed to work?
  • It looks correct to me as they are snapping the points to the top of the scroll?

@Bowlerr
Copy link
Author

Bowlerr commented Apr 4, 2025

you can use that modified version of KeyboardAwareScrollView in your project, since that component uses public API of the lib 🙂

Already on it 😎. Thanks for the great api

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants