Creating soft-keys that work with text watchers in Android

Recently, I created a screen with soft keys that could be used for number input.  Scroll down for some source. Everything was working perfectly.  Each number key called field.append(“1”), passing in the correct number.  Then, a text watcher would be notified of the change and reformat the field.  The problem arose when I wrote the backspace method.  TextView doesn’t have a convenience method for removing characters from a field, so I used setText, passing in the number with the last character removed.  Unfortunately, when I did that, the text wacher wasn’t notified of the change!  Ugh…  Android is very well designed, but some implementation details are really not written well.  I decided it was time to look in the Android source.  If the append method caused a notification to the text watcher, I would write a method that worked the same way.

Supporting number keys

This was really simple.

private class CharacterButtonListener implements
      View.OnClickListener {
    private TextView field;
    private String character;
 
    public CharacterButtonListener(TextView field,
        String character) {
      this.field = field;
      this.character = character;
    }
 
    @Override
    public void onClick(View v) {
      this.field.append(this.character);
    }
  }

Supporting the backspace key

Since the setText method wasn’t notifying the TextWatcher, I looked into Android’s source to find this solution.  It’s ugly, but it works.

this.buttonBack.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        TextView number = numberText;
        CharSequence text = number.getText();
        // This is annoyingly ugly, but is from the Android source
        if (!(text instanceof Editable)) {
          number.setText(text, BufferType.EDITABLE);
        }
        Editable editable = (Editable)number.getText();
        // Now that we have the editable, edit it.
        // This line is not from the Android source.
        if (text.length() > 0) {
          editable.delete(text.length() - 1, text.length());
        }
      }
    });

That’s it!   I tried another solution, having each soft-key fire a key event in the field.  It worked, but since the field is automatically formatted, it didn’t feel right.  Also, Android doesn’t let the application set the position of the cursor (caret) in the text view, so if the user re-opened the number input dialog to edit the number, the cursor appeared at the left side of the field, which meant that the user had to re-position the cursor before pressing any keys, which was a pain.


  1. Choongsan Ro says:

    I think you can manipulate cursor(caret) with Selection class method :
    moveDown, moveLeft, moveRight, moveToLeftEdge, moveToRightEdge, moveUp.
    I tested out with this method and it works fine.
    I had no luck to find absolute position of caret yet. But i think you can make function out of these methods.

Leave a Reply