Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to change a soft keyboard's height at run-time?

I'm designing a soft keyboard and I want to change its height at run-time as the user choose between landscape and portrait mode. I know how to change key's height in xml, but I need to do it dynamically.

The only thing that came to my mind was to subclass from Keyboard and override its setKeysHeight (int height), but it seems useless as the whole keyboard stopped responding to my clicks and the height (though different from previously) didn't care about 'height' in the aforementioned function.

Any idea/workaround?

like image 247
Joseph_Marzbani Avatar asked Nov 19 '13 23:11

Joseph_Marzbani


1 Answers

Original solution posted at https://stackoverflow.com/a/9695482/1241783 but it doesn't come with explanation so here I extend it a bit.

1) Create a new class that extends the Keyboard class that overrides the getHeight() method.

@Override
public int getHeight() {
   return getKeyHeight() * 3;
}

Note: the number 3 here is your total number of rows, if your keyboard has 5 rows, put 5.

If your keyboard row height is different for each row, here you need to calculate yourself and return the total height (unit is in pixels, took me a while to figure out that it is not dp so need to convert dp to pixel for all calculations) for example:

@Override
public int getHeight() {
   return row1Height + row2Height + row3Height + row4Height + row5Height;
}

2) Create a new public function in the same class.

public void changeKeyHeight(double height_modifier)
{
   int height = 0;
   for(Keyboard.Key key : getKeys()) {
      key.height *= height_modifier;
      key.y *= height_modifier;
      height = key.height;
   }
   setKeyHeight(height);
   getNearestKeys(0, 0); //somehow adding this fixed a weird bug where bottom row keys could not be pressed if keyboard height is too tall.. from the Keyboard source code seems like calling this will recalculate some values used in keypress detection calculation
}

If you're not using height_modifier but set to specific height instead, you'll need to calculate key.y position yourself.

If your keyboard row height is different for each row, you may need to check the keys, determine the row it belongs and set the height to correct value if not the keys will overlap each other. Also store the row heights in private variable to be used in getHeight() above. PS: On certain configuration I couldn't press the bottom row keys after changing keyboard height, and I found that calling getNearestKeys() fixes that though I'm not exactly sure why.

Note: key.y is y position of the key, coordinate 0 starts from the top of the keyboard, and goes down as the value increases. e.g. Coordinate 100 points to 100 pixel from the top of the keyboard :)

3) Last step is to call changeKeyHeight in your main class that extends InputMethodService. Do it inside (override it) onStartInputView() as this is where the keyboard should be redrawn after you change the height (via preference or something).

If you're looking at the Android soft keyboard sample project, it will be like this:

@Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
   super.onStartInputView(attribute, restarting);

   // Change the key height here dynamically after getting your value from shared preference or something
   mCurKeyboard.changeKeyHeight(1.5);

   // Apply the selected keyboard to the input view.
   mInputView.setKeyboard(mCurKeyboard);
   mInputView.closing();        

   final InputMethodSubtype subtype = mInputMethodManager.getCurrentInputMethodSubtype();
   mInputView.setSubtypeOnSpaceKey(subtype);
}

Cheers!

Extra: If you need a dp to pixel converter, here's the code:

private int convertDpToPx(int dp)
{
   return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
like image 159
Bruce Avatar answered Oct 16 '22 02:10

Bruce