react-native icon indicating copy to clipboard operation
react-native copied to clipboard

Feature: Improvements to `automaticallyAdjustKeyboardInsets`

Open isidoro98 opened this issue 3 years ago • 5 comments

Summary

This PR builds on top of #31402, which introduced the automaticallyAdjustsScrollIndicatorInsets functionality. It aims to fix one of RN's longstanding pain point regarding the keyboard.

The changes provide a better way of handling the ScrollView offset when a keyboard opens. Currently, when a keyboard opens we apply an offset to the Scrollview that matches the size of the keyboard. This approach is great if we are using an InputAccessoryView but if we have multiple TextInputs in a ScrollView; offsetting the content by the size of the keyboard doesn't yield the best user experience.

Changelog

[General] [Changed] - Changes offset behaviour when keyboard opens in ScrollView with automaticallyAdjustsScrollIndicatorInsets

Test Plan

The videos below compare the current and proposed behaviors for the following code:

<ScrollView
  automaticallyAdjustKeyboardInsets
  keyboardDismissMode="interactive">
  {[...Array(10).keys()].map(item => (
    <CustomTextInput placeholder={item.toString()} key={item} />
  ))}
</ScrollView>
Current behavior Proposal

As can be seen in the video, the current behavior applies an offset to the ScrollView content regardless of where the TextInput sits on the screen.

The proposal checks if the TextInput will be covered by the keyboard, and only then applies an offset. The offset applied is not the full size of the keyboard but instead only the required amount so that the TextInput is a specific distance above the top of the keyboard. This achieves a less "jumpy" experience for the user.

Open question: Should the distance between the top of the keyboard and the bottom of the TextInput be customizable with a prop?

CGFloat textFieldBottom = textFieldFrame.origin.y + textFieldFrame.size.height + 32; // What should be the default? Should we allow a prop to be passed?
CGFloat contentDiff = textFieldBottom - endFrame.origin.y;

The proposal doesn't change the behavior of the ScrollView offset when an InputAccessory view is used, since it checks if the TextField that triggered the keyboard is a descendant of the ScrollView or not.

Why not use other existing solutions?

RN ecosystem offers other alternatives for dealing with a keyboard inside a ScrollView, such as a KeyboardAvoidingView or using third party libraries like react-native-keyboard-aware-scroll-view. But as shown in the recordings below, these solutions don't provide the smoothness or behavior that can be achieved with automaticallyAdjustsScrollIndicatorInsets.

KeyboardAvoidingView rn-keyboard-aware-scroll-view

As shown in the videos, the TextInput is hidden by the keyboard for a split second before becoming visible.

Code for the videos above:

// KeyboardAvoidingView
<KeyboardAvoidingView
  style={{flex: 1, flexDirection: 'column', justifyContent: 'center'}}
  behavior="padding"
  enabled>
  <ScrollView>
    {[...Array(10).keys()].map(item => (
      <CustomTextInput placeholder={item.toString()} key={item} />
    ))}
  </ScrollView>
</KeyboardAvoidingView>
// rn-keyboard-aware-scroll-view
<KeyboardAwareScrollView>
  {[...Array(10).keys()].map(item => (
    <CustomTextInput placeholder={item.toString()} key={item} />
  ))}
</KeyboardAwareScrollView>

isidoro98 avatar Nov 06 '22 21:11 isidoro98

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 6,995,258 -107,005
android hermes armeabi-v7a 6,372,106 -99,338
android hermes x86 7,408,196 -111,403
android hermes x86_64 7,272,145 -105,881
android jsc arm64-v8a 8,861,159 -105,874
android jsc armeabi-v7a 7,599,671 -98,206
android jsc x86 8,918,904 -110,291
android jsc x86_64 9,402,268 -104,742

Base commit: 04c286c3c203ffeca414ecbc5f3e1d017520aefa Branch: main

analysis-bot avatar Nov 06 '22 21:11 analysis-bot

Platform Engine Arch Size (bytes) Diff
ios - universal n/a --

Base commit: 04c286c3c203ffeca414ecbc5f3e1d017520aefa Branch: main

analysis-bot avatar Nov 06 '22 22:11 analysis-bot

PR build artifact for 6cd100a99bf97c3b1a4c7dc008236f5af34123dd is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 06 '22 22:11 pull-bot

PR build artifact for 6cd100a99bf97c3b1a4c7dc008236f5af34123dd is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 06 '22 22:11 pull-bot

For android (Java/Kotlin) we can use; WindowInsets api to get the height of the soft. keyboard

UIKit seems to have api's like view.keyboardLayoutGuide and, UIKeyboardLayoutGuide

PS: Providing prop to adjust it manually seems nice customization but, using native api's to calculate the height would be more appropriate in this case.

  • hardcoding the height will impact the UX

Pranav-yadav avatar Nov 08 '22 06:11 Pranav-yadav

For android (Java/Kotlin) we can use; WindowInsets api to get the height of the soft. keyboard

UIKit seems to have api's like view.keyboardLayoutGuide and, UIKeyboardLayoutGuide

PS: Providing prop to adjust it manually seems nice customization but, using native api's to calculate the height would be more appropriate in this case.

  • hardcoding the height will impact the UX

Hi, the hardcoded value represents the distance between the bottom of the TextInput and the top of the Keyboard. Not the size of the keyboard

Please see the screenshot below for reference. IMO the default value should be 0 and we should allow the user to customize this distance.

isidoro98 avatar Nov 08 '22 20:11 isidoro98

Hi, the hardcoded value represents the distance between the bottom of the TextInput and the top of the Keyboard. Not the size of the keyboard

Got it.. Thanks. 😄

Then adding a prop for it and keeping its default value resonable; makes sense..

Pranav-yadav avatar Nov 09 '22 03:11 Pranav-yadav

I've just patched it into 0.68.5, works as a charm. I had to hard code the distance between the input and the keyboard because I was using an absolute positioned element at the bottom of the screen so I believe a prop would be great to adjust it.

efstathiosntonas avatar Nov 09 '22 10:11 efstathiosntonas

I've just patched it into 0.68.5, works as a charm. I had to hard code the distance between the input and the keyboard because I was using an absolute positioned element at the bottom of the screen so I believe a prop would be great to adjust it.

Hey, glad to hear it worked! Do you have any suggestions regarding what this prop should be called? Looking for ideas :)

isidoro98 avatar Nov 09 '22 21:11 isidoro98

bottomOffset, bottomKeyboardOffset , bottomOffsetPadding 🤔

efstathiosntonas avatar Nov 11 '22 05:11 efstathiosntonas

PR build artifact for 24ce8b590789805679632d474ed59b1b821862ce is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 17 '22 12:11 pull-bot

PR build artifact for 24ce8b590789805679632d474ed59b1b821862ce is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 17 '22 12:11 pull-bot

bottomOffset, bottomKeyboardOffset , bottomOffsetPadding 🤔

Added the prop and named it bottomKeyboardOffset. Thank you for the suggestions! @efstathiosntonas

isidoro98 avatar Nov 17 '22 14:11 isidoro98

PR build artifact for 42088b6e7c7b74f292ee35df1c24642b711006dd is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 17 '22 15:11 pull-bot

PR build artifact for 42088b6e7c7b74f292ee35df1c24642b711006dd is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 17 '22 15:11 pull-bot

PR build artifact for e2891a7eafe4ba4d447322ca0cca19814a6a0d18 is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 17 '22 19:11 pull-bot

PR build artifact for e2891a7eafe4ba4d447322ca0cca19814a6a0d18 is ready. To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

pull-bot avatar Nov 17 '22 19:11 pull-bot

@isidoro98 why did you close this ?

aliraza-noon avatar Dec 08 '22 19:12 aliraza-noon

This is super! Why is this closed?

casperstr avatar Mar 08 '23 11:03 casperstr