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")
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With