在Fragment中实现onKeyPreIme(int keyCode, KeyEvent event)方法

20

我不知道如何在Fragment中实现onKeyPreIme(int keyCode, KeyEvent event)

@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && 
        event.getAction() == KeyEvent.ACTION_UP) {
            // do your stuff
            return false;
    }
    return super.dispatchKeyEvent(event);
}

我尝试了很多但都不起作用。同时,我在Google或Stack Overflow上也找不到任何答案。我想在按下返回键且软键盘出现时执行某个操作。在我的EditText上设置onKeyListener并没有起作用,因为在软键盘出现时不会调用KeyEvent.KEYCODE_BACK。非常感谢任何帮助和源代码。


感谢您的代码,它对我理解返回“super.dispatchKeyEvent(event);”活动的后退按钮非常有帮助! - Gibberish
4个回答

23

通过对与键盘输入相关的EditText视图进行子类化,我能够实现onKeyPreIme。目标是创建一个自定义锁屏,用户必须输入密码或离开应用程序。当用户点击“键盘下”按钮时,键盘不会消失。

请确保为子类化的EditText创建一个单独的.java文件。此外,请确保在下面的代码中使用构造函数(必须传递AttrubuteSet)。

我意识到我的onKeyPreIme的实现可能与你的不同,但它确实演示了如何在InputMethodManager执行其操作之前拦截键盘事件。

希望这有所帮助。

用户锁定活动的屏幕截图: enter image description here

EditText子类

public class LockEditText extends EditText {
    /* Must use this constructor in order for the layout files to instantiate the class properly */
    public LockEditText(Context context, AttributeSet attrs) 
    {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean onKeyPreIme (int keyCode, KeyEvent event)
    {
        // Return true if I handle the event:
            // In my case i want the keyboard to not be dismissible so i simply return true
            // Other people might want to handle the event differently
        System.out.println("onKeyPreIme " +event);
        return true;
    }

}

UserLockActivity.java

public class UserLockActivity extends Activity 
{
    private LockEditText editText1;
    private LockEditText editText2;
    private LockEditText editText3;
    private LockEditText editText4;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_lock);
        editText1 = (LockEditText) findViewById(R.id.lock_text_1);
        editText2 = (LockEditText) findViewById(R.id.lock_text_2);
        editText3 = (LockEditText) findViewById(R.id.lock_text_3);
        editText4 = (LockEditText) findViewById(R.id.lock_text_4);
        setupTextChangedListener(editText1);
        setupTextChangedListener(editText2);
        setupTextChangedListener(editText3);
        setupTextChangedListener(editText4);
        // A method to bring out the keyboard when the view appears
        setFocusOnEditText(editText1);
    }

    public void setFocusOnEditText(LockEditText editText)
    {
        editText.clearFocus();
        editText.requestFocus();
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
    }
    public void setupTextChangedListener(LockEditText editText)
    {
        editText.addTextChangedListener(new TextWatcher() 
        {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) 
            {

            }

            @Override
            public void afterTextChanged(Editable arg0) 
            {
                // TODO Auto-generated method stub
            }

            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1,int arg2, int arg3) 
            {
                // TODO Auto-generated method stub
            }
        });
    }
}

activity_user_lock.xml布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".UserLockActivity" >

    <TextView
        android:id="@+id/main_lock_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentTop="true"
        android:paddingTop="60dp"
        android:paddingBottom="20dp"
        android:text="@string/enter_passcode"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <LinearLayout
        android:id="@+id/lock_input_layout"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_below="@+id/main_lock_text"
        android:orientation="horizontal" >

        <com.yourpackage.yourappname.LockEditText
            android:id="@+id/lock_text_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="numberPassword"
            android:textSize="30sp"
            android:gravity="center_horizontal"
            android:textStyle="bold" >
        </com.yourpackage.yourappname.LockEditText>
        <com.yourpackage.yourappname.LockEditText
            android:id="@+id/lock_text_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="numberPassword"
            android:textSize="30sp"
            android:gravity="center_horizontal"
            android:textStyle="bold" >
        </com.yourpackage.yourappname.LockEditText>
        <com.yourpackage.yourappname.LockEditText
            android:id="@+id/lock_text_3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="numberPassword"
            android:textSize="30sp" 
            android:gravity="center_horizontal"
            android:textStyle="bold">
        </com.yourpackage.yourappname.LockEditText>
        <com.yourpackage.yourappname.LockEditText
            android:id="@+id/lock_text_4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="numberPassword"
            android:textSize="30sp"
            android:gravity="center_horizontal"
            android:textStyle="bold" >
        </com.yourpackage.yourappname.LockEditText>
    </LinearLayout>

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/lock_input_layout"
        android:layout_centerHorizontal="true"
        android:text="text" />

</RelativeLayout>

它并不完全符合我的意图,但你的想法很有创意,所以我会接受你的答案。 - Max
1
太棒了@i2097i。谢谢伙计 :) - Perry
我想在Fragment中使用inflater来实现“LockEditText”,但是在这种情况下我遇到了异常。您能否请解释一下如何将LockEditText作为Edittext的子类使用,并将其与inflater添加到Fragment中? - anand krish
@AnandKrish 我会研究一下重写方法来扩展 EditText 的子类。你可能需要实现一个特定的方法来初始化它以获得所需的行为。 - i2097i
1
这个解决方案效果很好,但是它是用于一个 activity 的。如果要添加到 fragment 中,需要在实例化 InputMethodManager 时获取 activity。 因此,在这一行代码中:InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 需要在 getSystemService 前添加 getActivity()。所以它会变成这样:InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - Bourne
显示剩余3条评论

23

这是我的解决方案,对我来说非常有效,但每个人的需求都有所不同。

首先,我创建了EditText的子类并连接了一个监听器(谷歌应该将其设置为默认值)。

public class ListenerEditText extends EditText {

    private KeyImeChange keyImeChangeListener;

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

    public void setKeyImeChangeListener(KeyImeChange listener){
        keyImeChangeListener = listener;
    }

    public interface KeyImeChange {
        public void onKeyIme(int keyCode, KeyEvent event);
    }

    @Override
    public boolean onKeyPreIme (int keyCode, KeyEvent event){
        if(keyImeChangeListener != null){
            keyImeChangeListener.onKeyIme(keyCode, event);
        }        
        return false;
    }
}

然后,您可以像这样从任何地方附加监听器:

myListenerEditText.setKeyImeChangeListener(new KeyImeChange() {

    @Override
    public void onKeyIme(int keyCode, KeyEvent event) {
        // All keypresses with the keyboard open will come through here!
        // You could also bubble up the true/false if you wanted 
        // to disable propagation.
    }
});

1
这看起来是最好的答案,因为它实际上启用了onKeyPreIme的覆盖。我很不想问,但我在让它工作方面遇到了问题。我扩展了AutoCompleteTextView,并在我的活动中的onKeyIme(...)中添加了一个return语句(您的第二个代码块)。除此之外,我完全复制了您的代码,并在新类中的“return”语句和每个方法上设置了断点。setKeyImeChangeListener被调用并初始化keyImeChangeListener,但是当按下键时,onKeyIme()从未被调用。有什么想法可以开始故障排除吗? - John Ward
好的,我想我明白了。这些键盘事件是针对物理键盘而不是软键盘的。有人可以确认一下吗?谢谢。 - John Ward
1
顺便说一下,我仍然是一个关于Android的学生,所以感谢您提供这段代码。我能够使用它来覆盖onFilterComplete方法。似乎有点傻,Android没有为这些事件提供监听器。 - John Ward
1
我也没有看到我的onKeyIme方法被调用。这对软键盘有效吗? - B T

1

我无法弄清如何实现onKeyPreIME,但是我能够使用以下代码在键盘消失后执行操作:

您可能需要更改比较的heightDiff > 200。这个比较对我有效,因为我有一个滚动视图。

fragmentView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            if(getView() != null){
                int heightDiff = getView().getRootView().getHeight() - getView().getHeight();
                if (heightDiff < 200) { 
                    rlupdate.setVisibility(RelativeLayout.VISIBLE);
                }
                else {
                    rlupdate.setVisibility(RelativeLayout.GONE);
                }   
            }
        }
    });

1
这是 Deminetix 的完整代码答案。
我使用了 Deminetix 的答案来在 Android 上过滤手持条码阅读器并获得结果。
为了在仅有按钮的屏幕上使用它,我添加了一个EditText,其中包含android:textColor="#FF000000" android:background="#00FFFFFF" android:enabled="false",禁用EditText仍然可以获取键盘事件。
可选地,我可以使用以下代码隐藏软键盘,但在禁用EditText之后不再需要它。
//InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
//imm.showSoftInput(textPatientId, InputMethodManager.HIDE_IMPLICIT_ONLY);

MainActivity.java:

package com.doodkin.keyboardtest;

import com.doodkin.keyboardtest.ListenerEditText.KeyImeChange;

import android.os.Bundle;
import android.app.Activity;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.KeyListener;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;

public class MainActivity extends Activity {
    private static final String TAG = "keyboard test";
    //private EditText editText1;

    ListenerEditText editText1=null;
    public String barcodebuffer="";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText1 = (ListenerEditText) findViewById(R.id.editText1);

        editText1.setKeyImeChangeListener(new KeyImeChange() {

            @Override
            public boolean onKeyIme(int keyCode, KeyEvent event) {
                String deviceName=event.getDevice().getName();
                int keyboardType=event.getDevice().getKeyboardType();
                int indexof=deviceName.indexOf("USB");
                if(indexof!=-1 && keyboardType==InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC)
                {
                    if(event.getKeyCode()==KeyEvent.KEYCODE_ENTER)
                     {
                         if(barcodebuffer!="")
                         {
                             Log.d(TAG, "filterBarcodeKeys Chars Flush: " + barcodebuffer );
                             barcodebuffer="";
                         }
                     }
                     else
                     {

                         barcodebuffer+=Character.toString((char)event.getUnicodeChar());
                         //Log.d(TAG, "filterBarcodeKeys Char: " + Character.toString((char)event.getUnicodeChar()) );
                     }
                     return true;
                }
                return false;
            }
        });


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


}

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <com.doodkin.keyboardtest.ListenerEditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/textView1"
        android:ems="10" >

        <requestFocus />
    </com.doodkin.keyboardtest.ListenerEditText>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/editText1"
        android:layout_below="@+id/editText1"
        android:layout_marginTop="69dp"
        android:text="Button" />

</RelativeLayout>

ListenerEditText.java:

package com.doodkin.keyboardtest;

import android.content.Context;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.EditText;

/*
 * example: 

 myListenerEditText.setKeyImeChangeListener(new KeyImeChange() {

    @Override
    public boolean onKeyIme(int keyCode, KeyEvent event) {
        // All keypresses with the keyboard open will come through here!
        // You could also bubble up the true/false if you wanted 
        // to disable propagation.
    }
});

 */

public class ListenerEditText extends EditText {

    private KeyImeChange keyImeChangeListener;

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

    public void setKeyImeChangeListener(KeyImeChange listener){
        keyImeChangeListener = listener;
    }

    public interface KeyImeChange {
        public boolean onKeyIme(int keyCode, KeyEvent event);
    }

    @Override
    public boolean onKeyPreIme (int keyCode, KeyEvent event){
        if(keyImeChangeListener != null){
            return keyImeChangeListener.onKeyIme(keyCode, event);
        }        
        return false;
    }
}

我找不到setKeyImeChangeListener方法。 - Marian Paździoch
这是一个公共类ListenerEditText,它继承了EditText类。这是我开发的类,你可以在上面看到它。老实说,这是很久以前的事了,我不确定如何帮助你。我记不起来这个了。 - Shimon Doodkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接