Обновлено, чтобы показать более индивидуальный подход.Обновлено для работы с windowSoftInputMode="adjustResize"
.
Похоже, отсечение за пределами окон может быть новым фактом жизни Android, хотя я не нашел документации на этот счет.Несмотря на это, следующий метод может быть предпочтительным путем и, я полагаю, является стандартным, хотя и не очень хорошо задокументированным.
В следующем примере MyInputMethodService
создает клавиатуру с восемью клавишами внизу ипустая полоса просмотра выше, где отображаются всплывающие окна для верхнего ряда клавиш.Когда клавиша нажата, значение клавиши отображается во всплывающем окне над клавишей на время нажатия клавиши.Поскольку пустое представление над клавишами закрывает всплывающие окна, отсечение не происходит.(Не очень полезная клавиатура, но она имеет смысл.)
Кнопка и «Низкий текст» EditText
находятся под видом сверхуполоса.Вызов onComputeInsets()
разрешает касания клавиш клавиатуры, но запрещает касания клавиатуры в пустой области, закрытой вставкой.В этой области прикосновения передаются к базовым представлениям - здесь «Низкий текст» EditText
и Button
, которые отображают «ОК!»при нажатии.
«Gboard», похоже, работает аналогичным образом, но использует сестру FrameLayout
для отображения всплывающих окон с переводом.Вот как выглядит всплывающее окно «4» в Инспекторе макетов для «Gboard».
MyInputMethodService
public class MyInputMethodService extends InputMethodService
implements View.OnTouchListener {
private View mTopKey;
private PopupWindow mPopupWindow;
private View mPopupView;
@Override
public View onCreateInputView() {
final ConstraintLayout keyboardView = (ConstraintLayout) getLayoutInflater().inflate(R.layout.keyboard, null);
mTopKey = keyboardView.findViewById(R.id.a);
mTopKey.setOnTouchListener(this);
keyboardView.findViewById(R.id.b).setOnTouchListener(this);
keyboardView.findViewById(R.id.c).setOnTouchListener(this);
keyboardView.findViewById(R.id.d).setOnTouchListener(this);
keyboardView.findViewById(R.id.e).setOnTouchListener(this);
keyboardView.findViewById(R.id.f).setOnTouchListener(this);
keyboardView.findViewById(R.id.g).setOnTouchListener(this);
keyboardView.findViewById(R.id.h).setOnTouchListener(this);
mPopupView = getLayoutInflater().inflate(R.layout.popup, keyboardView, false);
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mPopupView.measure(measureSpec, measureSpec);
mPopupWindow = new PopupWindow(mPopupView, ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
return keyboardView;
}
@Override
public void onComputeInsets(InputMethodService.Insets outInsets) {
// Do the standard stuff.
super.onComputeInsets(outInsets);
// Only the keyboard are with the keys is touchable. The rest should pass touches
// through to the views behind. contentTopInsets set to play nice with windowSoftInputMode
// defined in the manifest.
outInsets.visibleTopInsets = mTopKey.getTop();
outInsets.contentTopInsets = mTopKey.getTop();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
layoutAndShowPopupWindow((TextView) v);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mPopupWindow.dismiss();
break;
}
return true;
}
private void layoutAndShowPopupWindow(TextView key) {
((TextView) mPopupView.findViewById(R.id.popupKey)).setText(key.getText());
int x = key.getLeft() + (key.getWidth() - mPopupView.getMeasuredWidth()) / 2;
int y = key.getTop() - mPopupView.getMeasuredHeight();
mPopupWindow.showAtLocation(key, Gravity.NO_GRAVITY, x, y);
}
}
keyboard.xml
View
определяется исключительно для того, чтобы дать всплывающим окнам возможность расширяться, и не имеет никакой другой цели.
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/a" />
<Button
android:id="@+id/a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="A"
app:layout_constraintBottom_toTopOf="@+id/e"
app:layout_constraintEnd_toStartOf="@+id/b"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="B"
app:layout_constraintBottom_toTopOf="@+id/f"
app:layout_constraintEnd_toStartOf="@+id/c"
app:layout_constraintStart_toEndOf="@+id/a" />
<Button
android:id="@+id/c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="C"
app:layout_constraintBottom_toTopOf="@+id/g"
app:layout_constraintEnd_toStartOf="@+id/d"
app:layout_constraintStart_toEndOf="@+id/b" />
<Button
android:id="@+id/d"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="D"
app:layout_constraintBottom_toTopOf="@+id/h"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/c" />
<Button
android:id="@+id/e"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="E"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/f"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/f"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="F"
app:layout_constraintEnd_toStartOf="@+id/g"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/e"
app:layout_constraintTop_toTopOf="@+id/e" />
<Button
android:id="@+id/g"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="G"
app:layout_constraintEnd_toStartOf="@+id/h"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/f"
app:layout_constraintTop_toTopOf="@+id/e" />
<Button
android:id="@+id/h"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="H"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/g"
app:layout_constraintTop_toTopOf="@+id/g" />
</android.support.constraint.ConstraintLayout>
popup.xml
Просто всплывающее окно.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:background="@android:color/black"
android:gravity="center"
android:orientation="vertical"
android:padding="3dp">
<TextView
android:id="@+id/popupKey"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="A"
android:textColor="@android:color/white" />
</LinearLayout>
activity_main
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="High text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="20dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<EditText
android:id="@+id/editText"
android:layout_width="133dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:ems="10"
android:inputType="textPersonName"
android:hint="Low text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/button" />
</android.support.constraint.ConstraintLayout>