Как изменить высоту мягкой клавиатуры во время выполнения?

Я разрабатываю мягкую клавиатуру, и я хочу изменить ее высоту во время выполнения, когда пользователь выбирает между пейзажным и портретным режимами. Я знаю, как изменить высоту ключа в xml, но мне нужно сделать это динамически.

Единственное, что мне пришло в голову, - это подкласс от Клавиатуры и переопределить его высоту setKeysHeight (int), но это кажется бесполезным поскольку вся клавиатура перестала отвечать на мои клики, а высота (хотя и отличается от ранее) не волновала "высота" в вышеупомянутой функции.

Любая идея/обходной путь?

Ответ 1

Оригинальное решение опубликовано в fooobar.com/questions/456155/..., но оно не приходит с объяснением, поэтому здесь я немного расширю его.

1) Создайте новый класс, который расширяет класс клавиатуры, который переопределяет метод getHeight().

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

Примечание: число 3 здесь - ваше общее количество строк, если ваша клавиатура имеет 5 строк, поместите 5.

Если высота каждой строки клавиатуры различна для каждой строки, здесь вам нужно вычислить себя и вернуть общую высоту (единица в пикселях, мне потребовалось некоторое время, чтобы понять, что это не dp, поэтому необходимо преобразовать dp в пиксель для всех вычислений), например:

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

2) Создайте новую публичную функцию в том же классе.

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
}

Если вы не используете height_modifier, но вместо этого настроитесь на определенную высоту, вам нужно будет вычислить позицию key.y.

Если высота каждой строки клавиатуры различна для каждой строки, вам может потребоваться проверить ключи, определить принадлежащую ей строку и установить высоту для коррекции значения, если ключи не будут перекрывать друг друга. Также сохраните высоту строки в частной переменной, которая будет использоваться в getHeight() выше. PS: При определенной конфигурации я не мог нажать клавиши нижней строки после изменения высоты клавиатуры, и я обнаружил, что вызов getNearestKeys() исправляет это, хотя я не совсем уверен, почему.

Примечание: key.y - это позиция y, координата 0 начинается с верхней части клавиатуры и уменьшается при увеличении значения. например Координата 100 точек на 100 пикселей от верхней части клавиатуры:)

3) Последний шаг - вызвать changeKeyHeight в вашем основном классе, который расширяет InputMethodService. Сделайте это внутри (переопределите) onStartInputView(), так как именно здесь клавиатура должна быть перерисована после изменения высоты (с помощью предпочтения или чего-то еще).

Если вы посмотрите на образец программы для мягкой клавиатуры Android, это будет следующим:

@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);
}

Ура!

Дополнительно: если вам нужен конвертер dp в пиксель, вот код:

private int convertDpToPx(int dp)
{
   return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}

Ответ 2

Я использую следующий код с Android 6:

private void adjustKeyboardKeyHeight (MyKeyboard keyboard, int newKeyHeight) {
   int oldKeyHeight = keyboard.getKeyHeight();
   int verticalGap = keyboard.getVerticalGap();
   int rows = 0;
   for (Keyboard.Key key : keyboard.getKeys()) {
      key.height = newKeyHeight;
      int row = (key.y + verticalGap) / (oldKeyHeight + verticalGap);
      key.y = row * newKeyHeight + (row - 1) * verticalGap;
      rows = Math.max(rows, row + 1);
      }
   keyboard.setHeight(rows * newKeyHeight + (rows - 1) * verticalGap);
}

private static class MyKeyboard extends Keyboard {
   private int height;
   MyKeyboard (Context context, int xmlLayoutResId) {
      super(context, xmlLayoutResId);
      height = super.getHeight();
   }
   @Override public int getKeyHeight() {
      return super.getKeyHeight();
   }
   @Override public int getVerticalGap() {
      return super.getVerticalGap();
   }
   public void setHeight (int newHeight) {
      height = newHeight;
   }
   @Override public int getHeight() {
      return height;
   }
}

Ответ 3

Решение Брюса больше не работает. Нижние клавиши перестают реагировать после изменения размера. Посмотрите на Keyboard.java:

    public int[] getNearestKeys(int x, int y) {
        if (mGridNeighbors == null) computeNearestNeighbors();

Таким образом, getNearestKeys не запускает никаких вычислений, computeNearestNeighbors() вызывается не более одного раза (и он закрыт, поэтому вы не можете вызвать его напрямую).

Вместо изменения размера в существующем объекте я изменил класс Keyboard.Key:

     public class FTKey extends Keyboard.Key {
        FTKey(Resources res, Keyboard.Row parent, int x, int y, XmlResourceParser parser) {
        super(res, parent, x, y, parser);

        this.height = (int) (height * FTPref.yScale);
        this.y = this.height * FTPref.yScale; // This works only if all rows of the same height
    }

В onStartInput() я каждый раз заново создаю все объекты клавиатуры:

FTPref.yScale = 0.7f;
mEnglishKeyboard = new FTKeyboard(this ...
mRussianKeyboard = new FTKeyboard(this ...

Переопределение getHeight() для вычисления общей высоты клавиатуры все еще требуется.

Будет сложно иметь ключи разной высоты, потому что вам придется рассчитывать не только общую высоту, но и y положение каждой кнопки, и это зависит от высоты предыдущих строк.