【问题标题】:How to show Android keyboard with symbols mode by default?如何在默认情况下以符号模式显示 Android 键盘?
【发布时间】:2014-08-09 15:03:30
【问题描述】:

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

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

有没有办法做到这一点?如果是,怎么做?

【问题讨论】:

  • 我开始了赏金,我的附加要求是:这是一个患者 ID 字段,在所有情况下 95% 都包含数字,但有时也可以使用字母。最好的解决方法是什么?
  • stackoverflow.com/questions/4929040/… 几乎相同的问题。但是,这里的要求是输入数学方程,这实际上需要符号而不仅仅是数字。

标签: android android-softkeyboard android-keypad android-inputtype


【解决方案1】:

我发布这个是因为我认为任何答案都没有真正解决这个问题。问题中的屏幕截图与特定 InputType 的默认状态不对应。因此,切换 InputTypes 不会为您提供屏幕截图中的布局。

(根据我的研究...)

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

输入法框架不允许客户端和 IME 之间直接通信。所有通信都通过InputMethodManagerInputConnection 进行——一种单向通道。然而,使用?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;
            }
        });
    }
}

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

<integer name="definedActionId">-100</integer>

-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 -->

没什么好解释的。 IME 将以 NUMBER 模式启动。它将显示ABC,而不是复选标记图标。单击时,我们拦截 actionId 并在 NUMBER 和 TEXT 输入之间切换。我们使用setInputType(...),因为它不仅更新了InputType,还通过更改重新启动了IME。 setRawInputType(...) 只更新InputType

问题

如您所知,这并不是真正的解决方案。如果用户在 TEXT 模式下关闭键盘(使用back 按钮),当他们再次打开键盘时,键盘将保持在 TEXT 模式。要进入数字模式,用户必须单击NUM。此外,在 TEXT 模式下,用户将看到 NUM 作为操作,以及 ?123 选项。这不会破坏任何东西,但确实会影响用户体验。

由于上述原因,我们无法对在 TEXT 模式下显示的 ?123 做任何事情。但是,我们可以尝试确保键盘始终以数字模式打开。我将提供一个粗略的草图,说明我们将如何做到这一点。它不是直截了当的,因为我们(开发人员)不知道诸如键盘关闭或打开之类的事件。更新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();
        }
    }
}

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

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

总结

当前的任务是提供围绕现有输入法引擎 (IME) 在 NUMBER 和 TEXT 输入模式之间切换的功能。第一种方法是在切换机制中使用imeActionLabel &amp; imeActionId。这种方法适用于 Google 的键盘 (this is the imeActionLabel),但不适用于三星的键盘 - imeActionLabel failed to show up in portrait(没有 extract)。可能的解决方法是在应用自己的 UI 中包含切换按钮。

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

最终解决方案(待实施和测试)

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

有关尝试的方法的更多信息,请参阅this discussion thread

截图

默认(数字)

切换到 TEXT

Recorded video link

【讨论】:

  • 在这一点上我应该分享我的实际需求:这是一个患者 ID 字段,在所有情况下,95% 都包含数字,但有时也可以使用字母。在这种情况下,最好的解决方法是什么?顺便说一句,第一个复杂的答案!谢谢!
  • @OneWorld 95 / 5 的分布使这令人沮丧 :)) 所有这一切都是为了 5%!好吧,我想出了一个使用自定义编辑器操作的解决方法。如果您对上面列出的问题没有意见,请放弃 CusEditText(第二个 Java 代码块)的第二个实现。我对第二个因为我只在一个设备和 API 级别上测试过它不是很有信心。你当然可以试一试,看看它的表现如何。
  • 到目前为止看起来很有希望。您能否提供一些解决方案的屏幕截图。这样一来,无需阅读所有代码行即可轻松识别解决方法及其改进和缺陷?
  • 我看到你覆盖了通常用于跳转到下一个 EditText 的按钮(如果有的话)。在实施您的解决方案时必须知道这一点,对吗?
  • @Vikram 此答案中提供的详细信息远远超过文档提供的内容。真的很神奇,你挖掘的深度来获得所有这些信息。真的很酷的东西。
【解决方案2】:

我同意它是一个 InputType。如果您只想向您的用户显示数字,那么您可以将以下内容添加到您的 xml 文档中以用于编辑文本:

        android:inputType="number"

但是,如果您将其设置为数字,则用户必须输入一个数字。但是您可以添加其他类型以及数字和电子邮件地址,例如:

        android:inputType="number|textEmailAddress"

查看http://developer.android.com/reference/android/text/InputType.html 了解更多选项。您还可以查看 eclipse 或 android studio 在“inputType”下显示的内容

【讨论】:

  • 投反对票,因为答案并不容易。如果您将数字注册为 inputType,则键盘将始终锁定为数字键盘 (12_KEY) - 无论您向 inputType 添加什么附加标志,例如示例中的“textEmailAddress”。
【解决方案3】:

我相信您正在寻找设置编辑文本的 InputType。

http://developer.android.com/reference/android/text/InputType.html

我不确定你会使用哪个,尽管你可能需要玩一会儿。

【讨论】:

    【解决方案4】:

    唯一的方法是设置EditTextinputType

    如果你想在onCreate()(或自定义View的构造函数中)设置这个属性,你可以使用setRawInputType()方法:

    mEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
    

    否则,如果需要在onCreate()(或自定义View的构造函数之后)设置该属性,可以使用setInputType()的方法:

    mEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
    

    显然您也可以在 XML 级别指定属性:

    android:inputType="number|numberDecimal"
    

    您可以尝试使用不同的标志来找到最佳组合过滤器。

    【讨论】:

    • 看不出与 Deans 和 Ian 的回答有什么不同,这还不够。
    • @OneWorld 我认为你不能做更多的事情,输入类型是欺骗键盘的唯一方法(我的解决方案使用不同的标志,应该匹配你的大部分输入)
    • @bonnys 如果我像您一样向他们解释问题,我的客户不会明白这一点。这里需要更多的创造力。如果 Ian 和 Dean 的回答是足够的,我就不会开始赏金,如果没有直接的解决方案,我就不会开始明确要求解决方法。
    【解决方案5】:

    以编程方式,可以对通常的流程稍加调整。首先你必须将editText设置为:

    editText.setInputType(InputType.TYPE_CLASS_NUMBER);

    然后你必须监听keyevent。按下磅时,再次将 InputType 设置为 InputType.TYPE_CLASS_TEXT。这应该对我有用。

    editText.setOnKeyListener(new View.OnKeyListener() 
            {
             @Override
             public boolean onKey(View v, int keyCode, KeyEvent event) {
                                    // TODO Auto-generated method stub
                                    Log.d("KeyBoard", "Keyboard Test Key Hit");
    
             switch (keyCode) {
             KeyEvent.KEYCODE_POUND:
                                                                                          if(editText.setInputType(InputType.TYPE_CLASS_TEXT);
             {
    
             editText.setInputType(InputType.TYPE_CLASS_TEXT);
             return true;
    
         }
    

    我已经回答了同样的问题:EditText with number keypad by default, but allowing alphabetic characters

    【讨论】:

    • Vikram 的解决方案也会像你一样改变inputType。我也可以另外使用井号键。但真正的问题出在其他地方:检查 my chat with Vikram 。最大的问题是处理输入类型类“数字”的三星设备。设置此inputType 时,所有字母都对EditText 隐藏。感谢您指向另一个线程。
    • @OneWorld 在保留了几个小时后,我关闭了聊天窗口。有机会时给我发消息,
    • 它仍然在我对您的回答的第一条评论中链接
    • @OneWorld 我知道。如果您想进一步讨论,我认为您会在这里给我留言。
    • 这种方法很可能行不通。软键盘不(或至少不鼓励)发送按键事件。我不确定KEYCODE_POUND 是否是一个例外(我知道有些键是)。但是,KEYCODE_POUND 与此有什么关系?附带说明一下,按键事件是由硬件键盘发送的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多