Android: why is my OnKeyListener() not called?
I defined an EditText-field and I want to be informed when the user edits that fields. So I thought: simple - I add an OnKeyListener and so I did. But even though the text field gets edited (and even displays the entered/modified text) I don't get any callback, i.e. the LOG-output doesn't show up.
TextView text = new TextView(this);
text.setText(...);
...
text.setOnKeyListener(new OnKeyListener()
{
public boolean onKey(View v, int keyCode, KeyEvent event) {
TextView tv = (TextView)v;
CharSequence val = tv.getText();
Log.v(TAG, "valu开发者_运维百科e: " + val);
// ... rest omitted for brevity
}
});
Any idea, why that callback is never called?
Michael
PS.: Sigh! Android is really full of oddities! It seems that almost nothing I touched so far worked immediatly as one would expect. And - believe it or not - I have LOTS of experience with GUIs, esp. in Java (AWT, Swing, SWT, you name it...) But Android is a really tough beast!
Are you using the soft keyboard (ime) to type in the edit text? I believe that the onKeyListener only gets invoked with events from the hardware keyboard. You are better off using the TextWatcher if you can. onKeyListener not working with soft keyboard (Android)
I had the exact same problem, but on only 1 of my Android apps and I never did figure out what the difference was.
My solution though was to do what Mayra suggested and add a TextWatcher to handle the TextChanged events. So it works no matter how the text entry occurs.
editName.addTextChangedListener(new TextWatcher () {
public void afterTextChanged(Editable s) {
Button btnSave = (Button)findViewById(R.id.btnSaveToon);
if(s.length() > 0)
btnSave.setEnabled(true);
else
btnSave.setEnabled(false);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
});
Works like a charm in the emulator and on my HTC Inspire
You say that you're dealing with an EditText, but your code refers to a TextView. My guess is that you have an EditText in your layout XML files, but you're referring to this newly created TextView in your code, which is in fact not even in the app's UI at all.
If there is already an EditText in your layout XML file, then you need to get a pointer to it in your Java code, probably using the findViewById()
method. Then add your OnKeyListener to that EditText.
Defining your layout in XML actually makes a lot more sense (at least in many, if not most, cases) than defining it one component at a time and then adding each those components to the UI, like you do in Swing. But it takes some getting used to, no question.
I had the same problem. The goal of the EditText was to input an amount of a currency, so I only needed the KeyEvents because I wanted the amount to be written from back to front as in apps like PayPal. I ended up just generating my own soft keyboard at the bottom of a RelativeLayout using a Fragment that is toggled with its visibility. If anyone wants to use my code, here you go:
The Keyboard Fragment Class:
public class KeyboardFragment extends Fragment {
private LinearLayout keyboard1, keyboard2, keyboard3, keyboard4, keyboard5, keyboard6,
keyboard7, keyboard8, keyboard9, keyboard0, keyboardReturn, keyboardApply;
private KeyboardListener keyboardListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_keyboard, container, false);
keyboard0 = view.findViewById(R.id.keyboard0);
keyboard1 = view.findViewById(R.id.keyboard1);
//and so on...
keyboard0.setOnClickListener((View v) -> {
keyboardListener.keyPressed(0);
});
keyboard1.setOnClickListener((View v) -> {
keyboardListener.keyPressed(1);
});
//and so on...
return view;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
keyboardListener = (KeyboardListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + "must implement KeyboardListener");
}
}
public interface KeyboardListener {
public void keyPressed(int key);
}
}
The overlaying activity needs to implement the KeyboardListener and override the keyPressed function.
The XML of the Fragment looks like this:
Drawables:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/ui_keyboard_dark" />
<corners android:radius="5dp" />
</shape>
Then I inflated a container in the overlaying activity with the fragment and set its height to a moderate fraction of the screen's height:
KeyboardFragment fragment = new KeyboardFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.keyboardContainer, fragment);
fragmentTransaction.commit();
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,(int) ((double)displayMetrics.heightPixels / 2.8));
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
keyboardContainer.setLayoutParams(layoutParams);
Set a boolean that tracks the state of the keyboard in the activity. Then set the visibility according to actions like onBackPressed() or the click of the apply or ok button of the keyboard.
The amount of the currency is tracked using an int that would represent 10,95€ like this: amount = 1095
Then you just need to multiply the amount by 10 and add the pressed number. When pressing backspace just divide by 10.
I hope someone faces the same problem as me and finds this useful :).
精彩评论