Stop keyboard overlay when interacting with TextField in a NativeScript application
Asked Answered
B

3

9

When working with a NativeScript application view where a user can enter input, the native application Keyboard Input overlays the TextField component. While this doesn't stop the user from entering text, it disrupts the UX flow and looks bad from a UI perspective.

How can I get the Keyboard to not overlay the input, but instead appear underneath it like other native applications can do?

Update 2

Now that it no longer overlays, I've noticed that when I leave the application to switch to another one or suspend the NativeScript app, when I come back to it the problem reappears. What can I do to persist the original behavior?

Baca answered 30/12, 2018 at 19:50 Comment(0)
B
7

After stumbling around a few other discussions and resources:

There were a few takeaways from these resources which I'll review below.

Template Flow

First off, you'll need to ensure your page layout mirrors something like below:

ScrollView
  > StackLayout
    > GridLayout
      > SomeElement
    > GridLayout
      > TextField

Android Soft Input Mode

This relates to the on-screen keyboard that displays when a text field in the UI receives focus. One trick to ensure the keyboard does not overlay your textfield is to ensure you have the property windowSoftInputMode set in your AndroidManifest.xml. You can either use adjustResize or adjustPan. I'm not entirely sure of the differences, but some users have reported either or both working so you might need to play around with which works for your case. You can read more about these two flags here.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="__PACKAGE__"
  android:versionCode="10000"
  android:versionName="1.0">

  ...

  <application
    ...
    android:windowSoftInputMode="stateHidden | adjustPan">

Update 2

I believe there is something getting reset within NativeScript which is causing the flag set by android:windowSoftInputMode to be reset when the application is suspended and resumed. To get around this, you'll need to make some adjustments in the controller of the view itself to watch for these events to happen in your app's lifecycle and then retroactively enable the flags again.

some-view.component.ts (TypeScript)

import { Component, OnInit } from '@angular/core';
import * as app from "application";
import {
  resumeEvent,
  suspendEvent,
  ApplicationEventData,
  on as applicationOn,
  run as applicationRun } from "tns-core-modules/application";

declare var android: any; // <- important! avoids namespace issues

@Component({
  moduleId: module.id,
  selector: 'some-view',
  templateUrl: './some-view.component.html',
  styleUrls: ['./some-view.component.css']
})
export class SomeViewComponent implements OnInit {

  constructor() {
    applicationOn(suspendEvent, (args: ApplicationEventData) => {
      // args.android is an android activity
      if (args.android) {
        console.log("SUSPEND Activity: " + args.android);
      }
    });

    applicationOn(resumeEvent, (args: ApplicationEventData) => {
      if (args.android) {
        console.log("RESUME Activity: " + args.android);
        let window = app.android.startActivity.getWindow();
        window.setSoftInputMode(
          android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
        );
        // This can be SOFT_INPUT_ADJUST_PAN
        // Or SOFT_INPUT_ADJUST_RESIZE
      }
    });
  }
}
Baca answered 30/12, 2018 at 19:50 Comment(2)
I'd also like to point out that after testing locally; I am confirming that I only needed to add Application Lifecycle event handlers to manually re-enable this IF I was suspending the app and resuming the app within the same view. If I came back to the app and navigated back to the view this issue happens on it would be working just fine.Baca
By default soft input mode is unspecified. According to Android API reference > the system will try to pick one or the other depending on the contents of the window That explains the necessity to set it explicitly. However, I don't deny there are NativeScript quirks. Also, adjustResize is now deprecated.Enterogastrone
L
9

I also had the same issue,

TNS Version: 6.3.0
Android Version: 9
Using RadSideDrawer with nativescript angular

Adding the following didn't work for me

 <application
    ...
    android:windowSoftInputMode="stateHidden | adjustPan">

Instead of adding android:windowSoftInputMode in application, add it in activity, check the following.

<activity
    ...
    android:windowSoftInputMode="adjustResize">

Also need to update the style.xml, add the following in LaunchScreenThemeBase

    <item name="android:fitsSystemWindows">true</item>

This will fix the keyboard overlay issue but it will create another issue, causing the Status bar / Action Bar to change height when the keyboard is displayed. to resolve that, put the following in style.xml in AppThemeBase (To correct the color of status bar)

    <item name="android:windowBackground">@color/ns_primary</item>

In _app-common.scss (To get rid of extra space)

    .action-bar {
      margin-top:-22;  
    }
Laurenlaurena answered 9/4, 2020 at 8:51 Comment(0)
B
7

After stumbling around a few other discussions and resources:

There were a few takeaways from these resources which I'll review below.

Template Flow

First off, you'll need to ensure your page layout mirrors something like below:

ScrollView
  > StackLayout
    > GridLayout
      > SomeElement
    > GridLayout
      > TextField

Android Soft Input Mode

This relates to the on-screen keyboard that displays when a text field in the UI receives focus. One trick to ensure the keyboard does not overlay your textfield is to ensure you have the property windowSoftInputMode set in your AndroidManifest.xml. You can either use adjustResize or adjustPan. I'm not entirely sure of the differences, but some users have reported either or both working so you might need to play around with which works for your case. You can read more about these two flags here.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="__PACKAGE__"
  android:versionCode="10000"
  android:versionName="1.0">

  ...

  <application
    ...
    android:windowSoftInputMode="stateHidden | adjustPan">

Update 2

I believe there is something getting reset within NativeScript which is causing the flag set by android:windowSoftInputMode to be reset when the application is suspended and resumed. To get around this, you'll need to make some adjustments in the controller of the view itself to watch for these events to happen in your app's lifecycle and then retroactively enable the flags again.

some-view.component.ts (TypeScript)

import { Component, OnInit } from '@angular/core';
import * as app from "application";
import {
  resumeEvent,
  suspendEvent,
  ApplicationEventData,
  on as applicationOn,
  run as applicationRun } from "tns-core-modules/application";

declare var android: any; // <- important! avoids namespace issues

@Component({
  moduleId: module.id,
  selector: 'some-view',
  templateUrl: './some-view.component.html',
  styleUrls: ['./some-view.component.css']
})
export class SomeViewComponent implements OnInit {

  constructor() {
    applicationOn(suspendEvent, (args: ApplicationEventData) => {
      // args.android is an android activity
      if (args.android) {
        console.log("SUSPEND Activity: " + args.android);
      }
    });

    applicationOn(resumeEvent, (args: ApplicationEventData) => {
      if (args.android) {
        console.log("RESUME Activity: " + args.android);
        let window = app.android.startActivity.getWindow();
        window.setSoftInputMode(
          android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
        );
        // This can be SOFT_INPUT_ADJUST_PAN
        // Or SOFT_INPUT_ADJUST_RESIZE
      }
    });
  }
}
Baca answered 30/12, 2018 at 19:50 Comment(2)
I'd also like to point out that after testing locally; I am confirming that I only needed to add Application Lifecycle event handlers to manually re-enable this IF I was suspending the app and resuming the app within the same view. If I came back to the app and navigated back to the view this issue happens on it would be working just fine.Baca
By default soft input mode is unspecified. According to Android API reference > the system will try to pick one or the other depending on the contents of the window That explains the necessity to set it explicitly. However, I don't deny there are NativeScript quirks. Also, adjustResize is now deprecated.Enterogastrone
Q
1

I'm using {N} 6.5.0 and got it working for Android with this setup.

This example combines PreviousNextView that solves the issue on iOS.

html

<PreviousNextView>
  <DockLayout stretchLastChild="true">
    <StackLayout dock="bottom">      <-- this is a bottom bar with a TextField
    <StackLayout dock="top">
  </DockLayout>
</PreviousNextView>

AndroidManifest.xml

<activity
    ...
    android:windowSoftInputMode="adjustPan">
Quade answered 28/8, 2020 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.