Skip to content
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

The keyboard in floating mode is having problem. #29473

Closed
000xuandu opened this issue Jul 23, 2020 · 13 comments
Closed

The keyboard in floating mode is having problem. #29473

000xuandu opened this issue Jul 23, 2020 · 13 comments
Labels
Component: KeyboardAvoidingView Needs: Attention Issues where the author has responded to feedback. Needs: Issue Manager Attention Needs: Repro This issue could be improved with a clear list of steps to reproduce the issue. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@000xuandu
Copy link

000xuandu commented Jul 23, 2020

Description

My app has been rejected by apple due to interface issues.
After half a day I queried the problem, I finally realized the problem was at the floating keyboard of iPadOS 13.
When the keyboard went into floating mode, KeyboardAvoidingView worked incorrectly and destroyed my interface structure.

React Native version:

System:
    OS: macOS 10.15.3
    CPU: (4) x64 Intel(R) Core(TM) i3-8100B CPU @ 3.60GHz
    Memory: 400.56 MB / 8.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 14.5.0 - /usr/local/bin/node
    npm: 6.14.5 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.6, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6514223
    Xcode: 11.6/11E708 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0 
    react-native: 0.61.5 => 0.61.5 
  npmGlobalPackages:
    react-native-cli: 2.0.1
    react-native-rename: 2.4.1

Expected Results

What I want now to be able to recognize a certain event is to notify the keyboard to switch to floating mode, from which I will handle my UI.

Snack, code example, screenshot, or link to a repository:

Screen capture when keyboard is in anchor mode.
image

Screen capture when the keyboard is in floating mode.
image

Code:
image

@safaiyeh safaiyeh added Component: KeyboardAvoidingView Needs: Repro This issue could be improved with a clear list of steps to reproduce the issue. and removed API: Keyboard Needs: Triage 🔍 labels Aug 5, 2020
@github-actions
Copy link

github-actions bot commented Aug 5, 2020

⚠️ Missing Reproducible Example
ℹ️ It looks like your issue is missing a reproducible example. Please provide a Snack or a repository that demonstrates the issue you are reporting in a minimal, complete, and reproducible manner.

@safaiyeh
Copy link
Contributor

safaiyeh commented Aug 5, 2020

Hi @000xuandu thanks for the issue. Since this affects iPad, could you provide a repo that demonstrates this issue?

@Gyran
Copy link
Contributor

Gyran commented Sep 22, 2020

We experienced a similar problem, when a floating keyboard was dismissed the height calculation was off so we ended up with a blank screen (because everything was pushed off the screen).

When the floating keyboard is dismissed we get the following when calculating the relativeKeyboardHeight

keyboardFrame = {screenY: 0, width: 0, screenX: 0, height: 0}
frame = {y: 0, width: 1024, height: 1366, x: 0}
// which gives:
relativeKeyboardHeight 1366
// And therefore pushes all the content all the way to top because the screen height is 1366 on my iPad Pro

We did a workaround to just disable the KeyboardAvoidingView when the keyboard was floating by checking if the keyboard width is the same as the screen width

import { useState, useEffect } from 'react';
import { Keyboard, Dimensions } from 'react-native';

const useIsFloatingKeyboard = () => {
  const windowWidth = Dimensions.get('window').width;

  const [floating, setFloating] = useState(false);

  useEffect(() => {
    const onKeyboardWillChangeFrame = (event: KeyboardEvent) => {
      setFloating(event.endCoordinates.width !== windowWidth);
    };

    Keyboard.addListener('keyboardWillChangeFrame', onKeyboardWillChangeFrame);
    return () => {
      Keyboard.removeListener('keyboardWillChangeFrame', onKeyboardWillChangeFrame);
    };
  }, [windowWidth]);

  return floating;
};

Then in your component

const floating = useIsFloatingKeyboard();
<KeyboardAvoidingView enabled={!floating}>...</KeyboardAvoidingView>

Don't know if the appropriate solution is to disable keyboard avoiding view when the keyboard is floating (as the user can move it wherever) or how to make the component avoid the keyboard when it's moving around.

@torcoste
Copy link

torcoste commented Oct 3, 2020

@Gyran thanks for your workaround!

You probably wanted to removeListener in the return function of useEffect

I refactored it a bit, and designed it as a HOC to replace the original KeyboardAvoidingView

I gonna share the code

import React, { useState, useEffect } from 'react'
import {
    Keyboard,
    KeyboardAvoidingView as OriginalKeyboardAvoidingView,
    Dimensions,
    Platform,
} from 'react-native'

export const isIOS = Platform.OS === 'ios'

const useIsFloatingKeyboard = () => {
    const [isFloating, setFloating] = useState(false)
    const windowWidth = Dimensions.get('window').width
    const onKeyboardWillChangeFrame = event => {
        setFloating(event.endCoordinates.width !== windowWidth)
    }

    useEffect(() => {
        Keyboard.addListener('keyboardWillChangeFrame', onKeyboardWillChangeFrame)
        return () => {
            Keyboard.removeListener('keyboardWillChangeFrame', onKeyboardWillChangeFrame)
        }
    }, [])

    return isFloating
}

const KeyboardAvoidingView = ({ children, ...props }) => {
    const isFloatingKeyboard = useIsFloatingKeyboard()
    return (
        <OriginalKeyboardAvoidingView
            behavior={isIOS ? 'padding' : 'height'}
            enabled={!isFloatingKeyboard}
            {...props}
        >
            {children}
        </OriginalKeyboardAvoidingView>
    )
}

export default KeyboardAvoidingView

@000xuandu
Copy link
Author

My problem was solved temporarily when I used the library: react-native-keyboard-aware-scroll-view.
Hope to temporarily resolve for you who are experiencing similar errors and wait until the official patch.

image

@github-actions github-actions bot added Needs: Attention Issues where the author has responded to feedback. and removed Needs: Author Feedback labels Oct 6, 2020
@Gyran
Copy link
Contributor

Gyran commented Oct 6, 2020

@torcoste of course, updated the example with removeListener. Thanks!

@mym0404
Copy link
Contributor

mym0404 commented Jan 21, 2021

Yes KeyboardAvoidingView should be disabled when the keyboard is floating in tablet(iPad)

@Gyran
Copy link
Contributor

Gyran commented Mar 4, 2021

Created a minimal reproducible example here: https://github.com/Gyran/RNFloatingKeyboardIssue

Would an acceptable solution be to just disable the keyboard avoiding view when a user has a floating keyboard? If so, I could try to implement that in the React Native repo.

@luism3861
Copy link
Contributor

We experienced a similar problem, when a floating keyboard was dismissed the height calculation was off so we ended up with a blank screen (because everything was pushed off the screen).

When the floating keyboard is dismissed we get the following when calculating the relativeKeyboardHeight

keyboardFrame = {screenY: 0, width: 0, screenX: 0, height: 0}
frame = {y: 0, width: 1024, height: 1366, x: 0}
// which gives:
relativeKeyboardHeight 1366
// And therefore pushes all the content all the way to top because the screen height is 1366 on my iPad Pro

We did a workaround to just disable the KeyboardAvoidingView when the keyboard was floating by checking if the keyboard width is the same as the screen width

import { useState, useEffect } from 'react';
import { Keyboard, Dimensions } from 'react-native';

const useIsFloatingKeyboard = () => {
  const windowWidth = Dimensions.get('window').width;

  const [floating, setFloating] = useState(false);

  useEffect(() => {
    const onKeyboardWillChangeFrame = (event: KeyboardEvent) => {
      setFloating(event.endCoordinates.width !== windowWidth);
    };

    Keyboard.addListener('keyboardWillChangeFrame', onKeyboardWillChangeFrame);
    return () => {
      Keyboard.removeListener('keyboardWillChangeFrame', onKeyboardWillChangeFrame);
    };
  }, [windowWidth]);

  return floating;
};

Then in your component

const floating = useIsFloatingKeyboard();
<KeyboardAvoidingView enabled={!floating}>...</KeyboardAvoidingView>

Don't know if the appropriate solution is to disable keyboard avoiding view when the keyboard is floating (as the user can move it wherever) or how to make the component avoid the keyboard when it's moving around.

thanks a lot it works for me!

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jun 15, 2023
@github-actions
Copy link

This issue was closed because it has been stalled for 7 days with no activity.

@mattaningram
Copy link

Are there any plans to fix this in the built in KeyboardAvoidingView component or do we need to add the suggested logic above ourselves?

@gkasireddy202
Copy link

Is this issue fixed?
We have a problem implementing the suggested logic to all screens in my project.

facebook-github-bot pushed a commit that referenced this issue Sep 23, 2024
Summary:
On iPadOS, users can change the kind of keyboard displayed onscreen, going from normal keyboard, to split keyboard (one half on the left of the screen, one half on the right), or a floating keyboard that you can move around the screen.

When a non-normal kind of keyboard is used, `<KeyboardAvoidingView>` calculations are all wrong and, depending on the `behavior` prop, can make your screen completely hidden.

This PR attempts to detect that the keyboard is not the "normal displayed-at-bottom-of-screen" keyboard, and forces `enable={false}` if this happens.

The approach of comparing the keyboard width with the window width comes from this comment: #29473 (comment)

A better fix might be to detect the kind of keyboard used, but this involves native code changes and I do not know iOS enough to do that. In addition, I have not found an easy way to do it using iOS APIs after a quick search.

I also chose to cache the window width as a class attribute. Maybe this is not needed as `Dimensions.get('window').width` is very fast and can be called on every keyboard event?

This fixes #44068 and #29473

## Changelog:

[IOS] [FIXED] - Fix `<KeyboardAvoidingView>` with floating keyboard on iPadOS

Pull Request resolved: #44859

Test Plan:
Tested using RNTester and the "Keyboard Avoiding View with different behaviors" example.

Before:

https://github.com/facebook/react-native/assets/42070/111598a3-286c-464d-8db8-73afb35cd7f9

After:

https://github.com/facebook/react-native/assets/42070/0b3bc94f-8b67-4f42-8a83-e11555080268

Reviewed By: cortinico

Differential Revision: D62844854

Pulled By: cipolleschi

fbshipit-source-id: 577444be50019572955a013969d78178914b5b8d
blakef pushed a commit that referenced this issue Sep 30, 2024
Summary:
On iPadOS, users can change the kind of keyboard displayed onscreen, going from normal keyboard, to split keyboard (one half on the left of the screen, one half on the right), or a floating keyboard that you can move around the screen.

When a non-normal kind of keyboard is used, `<KeyboardAvoidingView>` calculations are all wrong and, depending on the `behavior` prop, can make your screen completely hidden.

This PR attempts to detect that the keyboard is not the "normal displayed-at-bottom-of-screen" keyboard, and forces `enable={false}` if this happens.

The approach of comparing the keyboard width with the window width comes from this comment: #29473 (comment)

A better fix might be to detect the kind of keyboard used, but this involves native code changes and I do not know iOS enough to do that. In addition, I have not found an easy way to do it using iOS APIs after a quick search.

I also chose to cache the window width as a class attribute. Maybe this is not needed as `Dimensions.get('window').width` is very fast and can be called on every keyboard event?

This fixes #44068 and #29473

## Changelog:

[IOS] [FIXED] - Fix `<KeyboardAvoidingView>` with floating keyboard on iPadOS

Pull Request resolved: #44859

Test Plan:
Tested using RNTester and the "Keyboard Avoiding View with different behaviors" example.

Before:

https://github.com/facebook/react-native/assets/42070/111598a3-286c-464d-8db8-73afb35cd7f9

After:

https://github.com/facebook/react-native/assets/42070/0b3bc94f-8b67-4f42-8a83-e11555080268

Reviewed By: cortinico

Differential Revision: D62844854

Pulled By: cipolleschi

fbshipit-source-id: 577444be50019572955a013969d78178914b5b8d
cipolleschi pushed a commit that referenced this issue Oct 7, 2024
Summary:
On iPadOS, users can change the kind of keyboard displayed onscreen, going from normal keyboard, to split keyboard (one half on the left of the screen, one half on the right), or a floating keyboard that you can move around the screen.

When a non-normal kind of keyboard is used, `<KeyboardAvoidingView>` calculations are all wrong and, depending on the `behavior` prop, can make your screen completely hidden.

This PR attempts to detect that the keyboard is not the "normal displayed-at-bottom-of-screen" keyboard, and forces `enable={false}` if this happens.

The approach of comparing the keyboard width with the window width comes from this comment: #29473 (comment)

A better fix might be to detect the kind of keyboard used, but this involves native code changes and I do not know iOS enough to do that. In addition, I have not found an easy way to do it using iOS APIs after a quick search.

I also chose to cache the window width as a class attribute. Maybe this is not needed as `Dimensions.get('window').width` is very fast and can be called on every keyboard event?

This fixes #44068 and #29473

[IOS] [FIXED] - Fix `<KeyboardAvoidingView>` with floating keyboard on iPadOS

Pull Request resolved: #44859

Test Plan:
Tested using RNTester and the "Keyboard Avoiding View with different behaviors" example.

Before:

https://github.com/facebook/react-native/assets/42070/111598a3-286c-464d-8db8-73afb35cd7f9

After:

https://github.com/facebook/react-native/assets/42070/0b3bc94f-8b67-4f42-8a83-e11555080268

Reviewed By: cortinico

Differential Revision: D62844854

Pulled By: cipolleschi

fbshipit-source-id: 577444be50019572955a013969d78178914b5b8d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: KeyboardAvoidingView Needs: Attention Issues where the author has responded to feedback. Needs: Issue Manager Attention Needs: Repro This issue could be improved with a clear list of steps to reproduce the issue. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests

9 participants