Phonegap Android应用程序不调整平移在键盘上 [英] Phonegap Android Application not adjusting pan on keyboardshow

查看:125
本文介绍了Phonegap Android应用程序不调整平移在键盘上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个版本为2.9.0的phonegap应用程序;



在桌面浏览器中使用RWD Bookmarklet( http://responsive.victorcoulon.fr/ )和工作正常。然而,当在移动设备或仿真器中测试时,布局破裂。经过一点点测试,我发现问题是状态栏的高度。将应用程序更改为全屏,问题解决。



但现在,当我专注于输入字段时,屏幕未被调整,因此,键盘覆盖输入字段!



查看所有问题和相关问题后,我发现这个,这对我有意义,但我想知道是否有一个方法使调整泛工作与全屏,所以我不需要调整我所有的组件高度,根据设备等计算不同的状态栏高度等。



代码



form.html

 < form id =login-form > 
< div class =form-group>
< input type =textname =loginclass =form-controlid =login
placeholder =xxxxxxx@example.com>
< / div>
< div class =form-group>
< input type =passwordname =passclass =form-control
id =passwordplaceholder =*******>
< / div>
< a class =pull-right login-btnid =btn-loginhref =#>< span
class =image-replacement> span>< / a>
< a class =pull-right login-btnid =btn-cadastrohref =#>< span class =image-replacement>< / span> / a>
< / form>

Android Manifest.xml

 <?xml version =1.0encoding =utf-8?> 
< manifest xmlns:android =http://schemas.android.com/apk/res/androidandroid:windowSoftInputMode =adjustPan
package =com.com.appandroid: versionName =1.0android:versionCode =1android: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 / iconandroid:label =@ string / app_name
android:hardwareAccelerated =true
android:debuggable =true>
< activity android:name =Appandroid: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 =7android: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) ;
//由< content src =index.html/>设置在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)
}
}


解决方案

虽然这可能不是更好的方法来解决它,我找到了一个解决方案。检测事件和沟通到JS是不是为我工作,既不与window.scrollTo也不与jQuery插件。不幸的是,我的时间很短,我喜欢在Java直接做。至于我有时间,我会重构它,并开发一个基于这个解决方案的插件。随着代码更新,我会在这里更新它。这里:

  / ** 
*
*由于Phonegap¹上的一个众所周知的错误, android softKeyboard adjustPan功能没有工作
*如预期当一个输入字段接收焦点。然而,由于Android bug2在adjustResize模式下导致全屏应用崩溃,所以常见的解决方法(更改为adjustResize和)
*不适用。
*这是一个解决方法,以检测softKeyboard何时被激活,然后在需要时编程滚动
*
*
*在开发过程中,我发现了一个恼人的行为在Android上,这使得
*输入字段dispatch onFocusChange两次时焦点被清除,当它应该只分派一次。
*第一个,没有焦点(预期行为),第二个有焦点(Dafuq?),导致
*不向后滚动模糊。我的解决方法是只让它设置一个标志(lostFocus参数),
*只允许该方法计算滚动大小如果元素没有失去它的焦点;
*
*¹ - http://stackoverflow.com/questions/11968420/softkeyboard-in-phonegap-covers-input-elements
*² - http://stackoverflow.com/问题/ 7417123 / android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
** /

final查看activityRootView = ViewGroup)findViewById(android.R.id.content))。getChildAt(0);

activityRootView.getViewTreeObserver()。addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout(){

View focused = appView。 findFocus();
activityRootView.getWindowVisibleDisplayFrame(r);

if(focused instanceof TextView){

if(focused.getOnFocusChangeListener()== null){
focused.setOnFocusChangeListener(new OnFocusChangeListener(){

@Override
public void onFocusChange(View v,boolean hasFocus){
if(!hasFocus){
activityRootView.scrollTo(0,0);
lostFocus = true;
showKeyBoard = false;
} else {
showKeyBoard = true;
}
}

});
}

/ **
*
*真的很棘手的一个找到,这是我发现侦测此监听器调用来自
*越野车输入聚焦增益。如果元素失去了焦点,r(Rect代表屏幕可见区域)
*将是总高度,这意味着没有键盘可以显示,直到屏幕
*完全可见。
*
** /
if(showKeyBoard || r.top!= activityRootView.getHeight()){

int heightDiff = 0;
int keyBoardSize = 0;
int scrollTo = 0;


heightDiff = activityRootView.getRootView()。getHeight() - focused.getTop();
keyBoardSize = activityRootView.getRootView()。getHeight() - r.bottom;

if((keyBoardSize< focused.getBottom()&& keyBoardSize> 0)&&!lostFocus){
scrollTo = focused.getBottom() - keyBoardSize;
}


if(scrollTo == 0){
activityRootView.scrollTo(0,scrollTo);
lostFocus = false;
showKeyBoard = true;
} else if(heightDiff< r.bottom){
activityRootView.scrollTo(0,scrollTo);
lostFocus = false;
showKeyBoard = false;
}
}
}
}
});

详细说明r,lostFocus和showKeyboard b

r 是一个Rect对象,由方法 getWindowVisibleDisplayFrame(Rect r)



文档:


检索此
视图所附的窗口位于的整个可见显示大小。在窗口之上考虑
屏幕装饰,对于其中窗口
本身位于它们内部或窗口被放置在
下面的两种情况,并且被覆盖的插图被用于窗口以定位其
内容。 实际上,这会告诉您可以放置​​
内容并让用户保持可见的可用区域。


因此,如果显示键盘,r.bottom 将与rootView高度不同。



showKeyboard lostFocus 是两种解决方法,可靠地获得正确的对焦/模糊行为。 showKeyboard 很简单,只有一个标志告诉应用程序是否应该或不应该滚动。理论上,它会工作,但是,我遇到一个恼人的错误,导致输入字段被聚焦后,他失去了焦点,在软键盘隐藏之前(只在应用程序内部,在设备上,元素不' t增益焦距和键盘已经隐藏)。为了解决它,我使用lostFocus告诉应用程序,当它真的失去了焦点,只允许它计算在哪里滚动,如果元素没有失去焦点。


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="xxxxxxx@example.com">
    </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")
    }
}

解决方案

Although it may be not the better way to fix it, i've found a solution. Detect the events and communicate to JS was not working for me, neither with window.scrollTo nor with the jQuery plugin. Unfortunately, my time is short and i preferred to do it in Java directly. As far as i have time, i'll refactor it and develop a plugin based on this solution. As the code gets updated, i'll update it here too. Here it goes:

    /**
     * 
     *  Due to a well known bug on Phonegap¹, android softKeyboard adjustPan functionality wasn't working
     *  as expected when an input field recieved focus. The common workaround(Change to adjustResize and),
     *  however, was not applicable, due to an Android bug² that crashes fullscreen apps when in adjustResize mode.
     *  This is an workaround, to detect when the softKeyboard is activated and then programatically scroll 
     *  whenever it needs;
     *
     *  During the development proccess i came across an annoying behavior on android, that were making the
     *  input field dispatch onFocusChange twice when focus was cleared, when it should dispatch only once.
     *  The first one, without focus(Expected behavior), the second one WITH focus(Dafuq?), causing it to
     *  not scroll back on blur. My workaround was to only enable it to set a flag(lostFocus parameter), and
     *  only allow the method to calculate the scroll size IF the element had not lost it's focus;
     * 
     *  ¹ - http://stackoverflow.com/questions/11968420/softkeyboard-in-phonegap-covers-input-elements
     *  ² - http://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
     **/

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

    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout(){

            View focused = appView.findFocus();
            activityRootView.getWindowVisibleDisplayFrame(r);

            if(focused instanceof TextView){

                if(focused.getOnFocusChangeListener() == null){
                    focused.setOnFocusChangeListener(new OnFocusChangeListener() {

                        @Override
                        public void onFocusChange(View v, boolean hasFocus) {
                            if(!hasFocus){
                                activityRootView.scrollTo(0,0);
                                lostFocus = true;
                                showKeyBoard = false;
                            }else{
                                showKeyBoard = true;
                            }
                        }

                    });
                }

                /**
                 * 
                 *  Really tricky one to find, that was the only way i found to detect when this listener call came from
                 *  the buggy input focus gain. If the element had lost its focus, r(A Rect representing the screen visible area)
                 *  would be the total height, what means that there would be no keyboard to be shown, as far as the screen
                 *  was completely visible.
                 * 
                 **/
                if(showKeyBoard || r.top != activityRootView.getHeight()){

                    int heightDiff = 0;
                    int keyBoardSize = 0;
                    int scrollTo = 0;


                    heightDiff = activityRootView.getRootView().getHeight() - focused.getTop();
                    keyBoardSize = activityRootView.getRootView().getHeight() - r.bottom;

                    if((keyBoardSize < focused.getBottom() && keyBoardSize > 0) && !lostFocus){
                        scrollTo = focused.getBottom() - keyBoardSize;
                    }


                    if(scrollTo == 0){
                        activityRootView.scrollTo(0,scrollTo);
                        lostFocus = false;
                        showKeyBoard = true;
                    }else if(heightDiff < r.bottom){
                        activityRootView.scrollTo(0, scrollTo);
                        lostFocus = false;
                        showKeyBoard = false;
                    }
                }
            }
        }
    });

Elaboration on r, lostFocus and showKeyboard

r is a Rect object, that gets filled by the method getWindowVisibleDisplayFrame(Rect r)

From the Docs:

Retrieve the overall visible display size in which the window this view is attached to has been positioned in. This takes into account screen decorations above the window, for both cases where the window itself is being position inside of them or the window is being placed under then and covered insets are used for the window to position its content inside. In effect, this tells you the available area where content can be placed and remain visible to users.

So, if the keyboard is shown, r.bottom would be different from the rootView height.

showKeyboard and lostFocus are two workarounds to get reliably the correct focus/blur behavior. showKeyboard is simple, only a flag to tell the application if it should or should not scroll. Theoretically, it'd work, however, i came across an annoying bug, that caused the input field to be focused immediately after his lost of focus, before the soft keyboard hide (Only internally in the application, on device, the element didn't gain focus and the keyboard was already hidden). To solve it, i've used lostFocus to tell the application when it really has lost focus and only allow it to calculate where to scroll if the element hadn't lost its focus.

这篇关于Phonegap Android应用程序不调整平移在键盘上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆