Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Phonegap Android Application not adjusting pan on keyboardshow

I'm developing a phonegap application with version 2.9.0;

The layout was fully tested in desktop browser using RWD Bookmarklet(http://responsive.victorcoulon.fr/) and worked fine. However, when tested in mobile devices or the emulator, the layout broke. After a little bit testing, I found out that the problem was the status bar height. Changed the application to fullscreen, problem solved.

But now, when i focus on an input field, the screen is not being adjusted, so, the keyboard covers the input field!

After looking all the questions and related problems, I found this one, that makes sense to me, but i wanted to know if there is a way to make the adjust pan work with fullscreen, so i don't need to adjust all my components height, calculate different status bar heights based on devices, etc.

Codes

form.html

<form id="login-form">
    <div class="form-group">
       <input type="text" name="login" class="form-control" id="login"
                        placeholder="[email protected]">
    </div>
    <div class="form-group">
      <input type="password" name="pass" class="form-control"
                        id="password" placeholder="*******">
    </div>
    <a class="pull-right login-btn" id="btn-login" href="#"><span
                    class="image-replacement"></span></a> 
    <a class="pull-right login-btn" id="btn-cadastro" href="#"><span class="image-replacement"></span></a>
</form>

Android Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
      package="com.com.app" android:versionName="1.0" android:versionCode="1" android:hardwareAccelerated="true">
    <supports-screens
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true"
        android:xlargeScreens="true"
        android:resizeable="true"
        android:anyDensity="true"
        />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />   
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />   
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />


<application android:icon="@drawable/icon" android:label="@string/app_name"
    android:hardwareAccelerated="true"
    android:debuggable="true">
    <activity android:name="App" android:label="@string/app_name"
            android:theme="@android:style/Theme.Black.NoTitleBar"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
            android:windowSoftInputMode="stateVisible|adjustPan">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="17"/>
</manifest> 

App.java

package com.com.app;

import org.apache.cordova.Config;
import org.apache.cordova.DroidGap;

import android.os.Bundle;
import android.view.WindowManager;

public class BDH extends DroidGap
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // Set by <content src="index.html" /> in config.xml

        getWindow().setFlags(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);

        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        super.loadUrl(Config.getStartUrl());
        //super.loadUrl("file:///android_asset/www/index.html")
    }
}
like image 664
Alexandre Wiechers Vaz Avatar asked Sep 03 '13 18:09

Alexandre Wiechers Vaz


1 Answers

UPDATE

Following up on my original answer, the below JavaScript will work on windowSoftInputMode="adjustResize", however, it will not work on "adjustPan" because the JavaScript resize() event will not be fired when the keyboard is shown.

However, as mentioned here, you can capture the keyboard shown event on the Java side by hooking a GlobalLayoutListener into the ViewTreeObserver:

package com.com.app;

import org.apache.cordova.Config;
import org.apache.cordova.DroidGap;

import android.os.Bundle;
import android.view.WindowManager;

public class BDH extends DroidGap
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // Set by <content src="index.html" /> in config.xml

        getWindow().setFlags(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);

        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        super.loadUrl(Config.getStartUrl());
        //super.loadUrl("file:///android_asset/www/index.html")

        final View activityRootView = ((ViewGroup) findViewById(android.R.id.content)).getChildAt(0);

        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() 
            {
                // r will be populated with the coordinates of your view that area still visible.
                Rect r = new Rect();

                activityRootView.getWindowVisibleDisplayFrame(r);

                int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);

                // If more than 100 pixels, its probably a keyboard...
                if (heightDiff > 100) 
                {
                                    // Fire off a function to the JavaScript.
                    this.sendJavascript("try { onKeyboardShowing(); } catch (e) {};");
                }
            }
        });
    }
}

So when the keyboard is shown, you can fire a function to the JavaScript, indicating the keyboard is being shown, then you can adjust the screen:

var fieldFocused = null;

function onKeyboardShowing()
{
    if(fieldFocused != null)
    {
        $('body').scrollTo(fieldFocused, 500, {offset:-50});
    }
}

$(document).on('focus', 'input, textarea', function() {
    fieldFocused = $(this);
});

$(document).on('blur', 'input, textarea', function() {
    fieldFocused = null;
});

ORIGINAL ANSWER

We had a horrible time trying to fix the Android soft keyboard covering the input fields. The solution I came up with is by no means 'nice', however it worked...

You will need jQuery and also another jQuery plugin called jQuery.ScrollTo by Ariel Flesher, found here.

Now add this to the JavaScript:

var fieldFocused = null;

$(window).resize(function(e) {
    if(fieldFocused != null)
    {
        $('body').scrollTo(fieldFocused, 500, {offset:-50});
    }
});

$(document).on('focus', 'input, textarea', function() {
    fieldFocused = $(this);
});

$(document).on('blur', 'input, textarea', function() {
    fieldFocused = null;
});

When a textarea/input is brought into focus, the DOM element is assigned to a variable. When the window is resized, the window is scrolled to bring the DOM element to the top.

We have used android:windowSoftInputMode="adjustResize" in the Android manifest.

As I have said this is not the most elegant of fixes, but we have implemented into our PhoneGap app and it works.

like image 63
kieranroneill Avatar answered Nov 14 '22 23:11

kieranroneill