28

我有一个Activity在配置更改(需要)时重新创建的。我有一个在其布局中使用单个DialogFragment调用的哪个。setRetainInstance(true)EditText

在 DialogFragment 中,onActivityCreated我调用:

getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);

A)如果我打开键盘,那么当我将应用程序放入后台然后将其带到前台时,我希望键盘仍然显示

B)如果我关闭键盘(EditText 仍然具有焦点并显示所需行为的光标),那么如果我将应用程序置于后台然后将其置于前台,我希望键盘仍然关闭。

我似乎无法同时实现 A) 和 B)。当我将应用程序带到前台时,键盘总是关闭。我试过 .SOFT_INPUT_STATE_ALWAYS_VISIBLE 但是键盘总是打开的。

提前感谢您对我如何实现这一目标的任何建议。我也希望在旋转过程中保持这种键盘状态,但我将把它留到另一天。彼得。

编辑 请注意,我不想阻止在配置更改时重新创建活动。

我还尝试了WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED在手机旋转期间保持键盘打开/关闭状态(单窗格布局)但 a) 不适用于双窗格布局 b) 将应用程序置于前台时不保持键盘状态。

4

6 回答 6

12

您好首先感谢您提出一个有趣的问题。它让我尝试了代码。在这里,我正在描述我的解决方案。

为了找到解决方案,我必须知道两件事

1.如何检测软键盘是否可见

2.如何设置软键盘可见或隐藏。

经过一番搜索后,我在以下步骤中得到了解决方案, 我意识到检测softkeyboardstate(可见/隐藏)的最佳解决方案是使用ViewTreeObserver。如果您不知道,我直接指向一个如此答案以了解它。这是链接

并设置softkeyboardstate我刚刚使用的Window.setSoftInputMode方法。

并了解用户交互我覆盖onUserInteraction方法

保留了两个标志。一个标志是保存keyboardstate另一个是知道应用程序是否进入后台

代码:

1. 变量声明

int lastDiff = 0;
volatile boolean flag = false;
volatile int flag2 = 0;

2.ViewTreeObserver

activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
    new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Rect r = new Rect();
            activityRootView.getWindowVisibleDisplayFrame(r);

            int heightDiff = activityRootView.getRootView()
                    .getHeight() - (r.bottom - r.top);
            if (lastDiff == heightDiff)
                return;
            lastDiff = heightDiff;
            Log.i("aerfin","arefin "+lastDiff);
            if (heightDiff > 100) { // if more than 100 pixels, its
                                    // probably a keyboard...
                flag2 = 0;
            } else {
                if (flag == false)
                    flag2 = 1;
            }
        }
    });

3.处理用户交互

 @Override
 public void onUserInteraction() {
     super.onUserInteraction();
     flag = true;
 }

4. 最后onPauseonResume

@Override
protected void onPause() {
    super.onPause();
    flag = true;
}

@Override
protected void onResume() {
    flag = false;

    switch (flag2) {
    case 0:
        getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        break;
    case 1:
        getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

        break;
    default:
        break;
    }

    super.onResume();
}

解释:

这里我使用了两个标志(flag2flag)。flag2保留keyboardstateflag保留应用程序是否进入后台或是否有任何用户交互。flag之所以使用,是因为当应用程序进入后台时,首先它会隐藏键盘。从上面的代码中可以很容易地理解其他事情。

测试:

在 s2(ics)、desire s (ics)、galaxy y (2.3.6) 中测试

最后评论:

我写的代码很快,所以可能会错过一些其他的优化。也有可能出现特殊情况。如果屏幕因键盘以外的其他原因发生变化,则可能无法检测到键盘状态。

于 2013-03-13T10:05:16.097 回答
6

您应该使用一个标志(boolean kbShowing)来保持当前的键盘状态,例如kbShowing = true在键盘显示时设置,否则设置kbShowing = false

onCreate

    showKB(); // if keyboard is not showed automatically. 

onRestart

    if(kbShowing)
        showKb(); // if keyboard is not showed automatically. 
    else 
        hideKb(); // if keyboard is showed automatically.

如果您不知道如何检测键盘何时显示或隐藏,请查看 Stefan 对此主题的回答How to capture the "virtual keyboard show/hide" event in Android?

于 2013-03-07T10:58:13.003 回答
2

I'd extend Wayne's approach by overwriting and creating your own EditText widget that you should use throughout your whole app.

public class PJLsEditText extends EditText 
{
    public PJLsEditText(Context context) {
        super(context);
        saveKbState();
    }

    public PJLsEditText(Context context, AttributeSet attrs) 
    {
        super(context, attrs);
        saveKbState();
    }

    private void saveKbState() 
    {
        //get keyboard state and set a flag either in a static class or as SharedPreference
    }

    // I'm not sure if EditText objects get destroyed on configuration change. 
    // If so, you might need to overwrite the onConfigurationChanged method here, 
    // as well...
} 

I assume this should help you to always know the last state of the keyboard, even if changed through Dialogs. You can hide or show the keyboard then according to this flag in your onResume and onPause methods.

于 2013-03-14T06:44:21.207 回答
2

您是否尝试在活动的清单文件中添加键盘状态:

 android:windowSoftInputMode="stateAlwaysVisible|adjustPan">

这将处理您问题的轮换部分,并且也应该在 onResume 上工作。stateAlwaysVisible 将在 onCrate 上启动键盘,而 adjustPan 将处理旋转。

这是我的清单文件中的一项活动的示例:

<activity
        android:name=".GMax3Main"
        android:label="@string/app_name" 
        android:windowSoftInputMode="stateAlwaysVisible|adjustPan">
        <intent-filter>
            <action android:name="com.medeasy.GMax3.MAIN" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

希望这可以帮助。

在我的活动类中,我在类的 onCreate 方法上打开我的软键盘,如下所示:

 @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    new UserSync().execute();
    setContentView(R.layout.main);

    InputMethodManager imm = (InputMethodManager)
            GMax3Main.this.getSystemService(Context.INPUT_METHOD_SERVICE);

        if (imm != null){
            imm.toggleSoftInput(InputMethodManager.RESULT_SHOWN, 0);
        }

然后我android:windowSoftInputMode="stateAlwaysVisible|adjustPan">在我的清单文件中调用我上面显示的内容。

于 2013-03-12T16:36:34.000 回答
2

类级别声明您的EditText ...

EditText editText;

现在覆盖活动的onResume()onPause()方法...

    @Override
    protected void onResume() 
    {
        // TODO Auto-generated method stub
        super.onResume();
        editText.requestFocus();

        editText.postDelayed(new Runnable() {
            @Override
            public void run() {
                InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED);
            }   
        }, 100);
    }

    @Override
    protected void onPause() 
    {
        // TODO Auto-generated method stub
        super.onPause();
        editText.postDelayed(new Runnable() {
            @Override
            public void run() {
                InputMethodManager imm = (InputMethodManager)getSystemService(
                          Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
            }   
        }, 200);
    }

这段代码非常适合我。

享受 - :D

于 2013-03-07T13:31:13.817 回答
2

如果键盘打开并设置一个标志,我可能会检查 onPause (我认为只有像下面的示例这样的骇人听闻的方法):

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
    int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
    if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
        ... do something here
    }
 }
});

根据这里的答案: 如何检查Android中软件键盘的可见性?

在 onResume() 中设置:

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

或者:

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
于 2013-03-07T15:20:55.897 回答