如何默认显示符号模式的Android键盘?

MC *_*ror 13 android android-keypad android-softkeyboard android-inputtype

我有一个EditText组件,当然,如果你点击它,会显示Android键盘,允许用户输入文本.据我所知,所有Android软件键盘都有(至少)字母模式(ABC)和符号模式(?123).他们的默认视图是字母模式.

现在,当EditText单击组件时显示键盘时,我希望默认显示符号模式.用户仍然可以切换到字母模式.

在此输入图像描述

有没有办法实现这一目标?如果有,怎么样?

Vik*_*ram 14

我发布这个是因为我不认为任何答案实际上解决了这个问题.问题中的屏幕截图与特定InputType的默认状态不对应.因此,切换InputTypes不会为您提供截屏的布局.

(根据我的研究......)

对符号输入的支持不受任何合同的约束.在创建自己的符号时,可以很好地留下符号InputMethod.或者,他们可以添加分页支持,以提供对100个符号的访问.这可以受合同约束吗?也许.但是,目前还没有.

输入法框架不允许客户端和IME之间的直接通信.所有通信都通过InputMethodManager或通过InputConnection- 单向通道进行.?123但是,切换到符号是内部事件 - 而不是已定义的状态/操作.客户端应用程序无法切换到它.没有公共(或隐藏)API来实现这一目标.

InputType表示与IME完全不同的东西.不确定为什么每个人都推荐使用它.您当然可以发现某个特定InputType提供了大多数所需的密钥.但那不一样show[ing] Android keyboard with symbols mode by default.

可能的解决方法:

我们将创建一个自定义EditText.我们没有.它只会将所有内容保存在一个地方,并将我们从复制粘贴噩梦中解救出来.

public class CusEditText extends EditText {

    private final int mDefinedActionId;

    public CusEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        // Corresponds to 'android:imeActionId' value
        mDefinedActionId = getResources().getInteger(R.integer.definedActionId);

        setOnEditorActionListener(new OnEditorActionListener() {

            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                Log.i("CusEditText", "onEditorAction, actionId = " + actionId);

                // Only bother if (...)
                if (actionId == mDefinedActionId) {

                    // Check if current InputType is NUMBER
                    if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
                        // Toggle
                        setImeActionLabel("NUM", mDefinedActionId);
                        setInputType(InputType.TYPE_CLASS_TEXT);
                    } else {
                        // Current InputType is TEXT // Toggle
                        setImeActionLabel("ABC", mDefinedActionId);
                        setInputType(InputType.TYPE_CLASS_NUMBER);
                    }

                    // We've handled this
                    return true;
                }

                // Let someone else worry about this
                return false;
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来,我们需要定义definedActionId.打开或创建res/values/integers.xml并添加:

<integer name="definedActionId">-100</integer>
Run Code Online (Sandbox Code Playgroud)

-100是一个任意值.我查了一下EditorInfo,actionIds(IME_ACTION_XXXX)> = 0. -100看起来像个好人.

在xml中,您的布局将如下所示:

<com.your.packagename.CusEditText
    android:layout_width="blah"
    android:layout_height="blah"
    android:inputType="number"
    android:imeActionId="@integer/definedActionId"
    android:imeActionLabel="ABC"/>

<!-- Probably use @string resource in place of ABC -->
Run Code Online (Sandbox Code Playgroud)

没有太多可解释的.IME将以NUMBER模式启动.它将显示,而不是一个复选标记图标ABC.点击后,我们拦截actionId并在NUMBER和TEXT输入之间切换.我们正在使用setInputType(...)InputType,因为它不仅更新了它,而且还通过更改重新启动IME.setRawInputType(...)只更新了InputType.

问题:

如您所知,这不是一个真正的解决方案.如果用户back在TEXT模式下关闭键盘(使用按钮),键盘将在再次打开时保持TEXT模式.要进入NUMBER模式,用户必须单击NUM.此外,在TEXT模式下,用户将看到NUM操作以及?123选项.这不会破坏任何东西,但确实会从UX中消失.

?123由于上面列出的原因,我们无法在TEXT模式下显示任何内容.但是,我们可以尝试确保键盘始终以NUMBER模式打开.我将提供一个粗略的草图,说明我们将如何做到这一点.它不直接,因为我们(开发人员)不知道键盘关闭或打开等事件.更新CusEditText:

public class CusEditText extends EditText {

    private final int mDefinedActionId;
    private long mLastEditorActionTime = 0L;

    public CusEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        // Corresponds to 'android:imeActionId' value
        mDefinedActionId = getResources().getInteger(R.integer.definedActionId);

        setOnEditorActionListener(new OnEditorActionListener() {

            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                Log.i("CusEditText", "onEditorAction, actionId = " + actionId);

                // Only bother if (...)
                if (actionId == mDefinedActionId) {

                    // setInputType(...) will restart the IME
                    // and call finishComposingText() 
                    // see below
                    mLastEditorActionTime = SystemClock.elapsedRealtime();

                    // Check if current InputType is NUMBER
                    if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
                        // Toggle
                        setImeActionLabel("NUM", mDefinedActionId);
                        setInputType(InputType.TYPE_CLASS_TEXT);
                    } else {
                        // Current InputType is TEXT // Toggle
                        setImeActionLabel("ABC", mDefinedActionId);
                        setInputType(InputType.TYPE_CLASS_NUMBER);
                    }

                    // We've handled this
                    return true;
                }

                // Let someone else worry about this
                return false;
            }
        });
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        InputConnection inputConnection = super.onCreateInputConnection(outAttrs);

        return new CusInputConnectionWrapper(inputConnection, false);
    }

    private class CusInputConnectionWrapper extends InputConnectionWrapper {
        private CusInputConnectionWrapper(InputConnection target, boolean mutable) {
            super(target, mutable);
        }

        @Override
        public boolean finishComposingText() {
            Log.i("CICW", "finishComposingText");

            // Ignore finishComposingText for 1 second (1000L)
            if (SystemClock.elapsedRealtime() - mLastEditorActionTime > 1000L) {
                if ((getInputType() & InputType.TYPE_CLASS_NUMBER) == 0) {
                    // InputConnection is no longer valid.
                    // Switch back to NUMBER iff required
                    setImeActionLabel("ABC", mDefinedActionId);
                    setInputType(InputType.TYPE_CLASS_NUMBER);
                }
            }

            return super.finishComposingText();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

同样,代码是不言自明的.我们创建InputConnectionWrapper并监听finishComposingText()回调.如果我们在TEXT和之间手动切换NUMBER,我们会使用一个标志,因为它finishComposingText()会被自动调用.否则,我们检查输入类型是否设置为TEXT并将其更改为NUMBER.我不确定是否finishComposingText()是解释键盘关闭/打开的正确方法.测试API 21,香草android,这似乎工作.将需要更多测试.

我真的希望有人可以提出一个比这更好,更强大的解决方案 - 或者修改我的解决方法,使它看起来不像一个.

摘要

手头的任务是提供围绕现有输入法引擎(IME)在NUMBER和TEXT输入模式之间切换的功能.第一种方法是imeActionLabel & imeActionId在切换机制中使用.这种方法适用于谷歌的键盘(这是imeActionLabel),但三星的imeActionLabel失败 - 未能以肖像显示(没有提取).可能的解决方法是在应用程序自己的UI中包含切换按钮.

即使使用Google的键盘,在输入字母后模式切换回NUMBER时,字母(文本)也无法显示.通过使用标志flagNoExtractUi来修复此问题(至少在测试的设备上),该标志阻止IME以横向方向进入全屏模式.

最终解决方案(待执行和测试)

  • IME以NUMBER输入模式启动(95%用例涉及数字输入)
  • 一个按钮被添加到应用程序的UI(旁边EditText),用于在NUMBER和TEXT模式之间切换
  • 用户可以不受任何限制地从NUMBER切换到TEXT.从TEXT切换回NUMBER要求不添加任何字母.
  • 在键盘关闭和重新打开之间保留InputType.示例:如果用户切换到TEXT模式并关闭键盘,它将以TEXT模式打开.InputType 重置.

有关所尝试方法的更多信息,请参阅此讨论主题.

截图

默认(NUMBER):

在此输入图像描述

切换到TEXT:

在此输入图像描述

录制的视频链接

  • @Vikram这个答案中提供的详细信息比文档提供的更多.真的很神奇,你挖掘得到所有这些信息的深度.真的很酷的东西. (2认同)