Мені потрібно зробити дуже просту річ - з’ясувати, чи відображається клавіатура програмного забезпечення. Чи можливо це в Android?
Мені потрібно зробити дуже просту річ - з’ясувати, чи відображається клавіатура програмного забезпечення. Чи можливо це в Android?
Відповіді:
НОВИЙ ВІДПОВІСТЬ додано 25 січня 2012 року
З моменту написання відповіді нижче, хтось підказав мені на існування ViewTreeObserver та друзів, API, які ховаються в SDK з версії 1.
Замість того, щоб вимагати спеціального типу макета, набагато простішим рішенням є надати кореневому представленню вашої діяльності відомий ідентифікатор, скажімо @+id/activityRoot
, підключити GlobalLayoutListener до ViewTreeObserver, і звідти обчислити розмір, що відрізняється між коренем подання вашої діяльності та розміром вікна:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard...
// ... do something here
}
}
});
Використання утиліти, наприклад:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
Легко!
Примітка:
Ваша програма повинна встановити цей прапор в Android Manifest, android:windowSoftInputMode="adjustResize"
інакше вищевказане рішення не працюватиме.
ОРИГІНАЛЬНИЙ ВІДПОВІДЬ
Так, це можливо, але це набагато важче, ніж це повинно бути.
Якщо мені потрібно подбати про те, коли клавіатура з'являється і зникає (що досить часто), то те, що я роблю, - це налаштувати мій клас макета верхнього рівня на той, який перевизначає onMeasure()
. Основна логіка полягає в тому, що якщо макет заповнює значно менше загальної площі вікна, то, ймовірно, відображається м'яка клавіатура.
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.LinearLayout;
/*
* LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when
* the soft keyboard is shown and hidden (something Android can't tell you, weirdly).
*/
public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {
public LinearLayoutThatDetectsSoftKeyboard(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface Listener {
public void onSoftKeyboardShown(boolean isShowing);
}
private Listener listener;
public void setListener(Listener listener) {
this.listener = listener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
Activity activity = (Activity)getContext();
Rect rect = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
int diff = (screenHeight - statusBarHeight) - height;
if (listener != null) {
listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Потім у вашому класі активності ...
public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);
mainLayout.setListener(this);
...
}
@Override
public void onSoftKeyboardShown(boolean isShowing) {
// do whatever you need to do here
}
...
}
((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)
android.R.id.content
), ви зможете впевнено сказати, що System
замість вашої програми є суб'єкт, що змінює свою висоту. Команді Android було б набагато безпечніше відпочити і дати нам знати хоча б основні речі про вхід SoftKeyboard.
heightDiff
завжди містилася висота смуги дій. У новій відповіді, яку було проігноровано тестуванням, чи не більше цієї константи висоти, але 100 пікселів недостатньо для пристроїв xxhdpi, таких як Nexus 4. Поміркуйте про перетворення цього значення в DP, якщо ви дійсно хочете використовувати цю хакітну роботу- навколо.
Тож сподіваємось, що це комусь допоможе.
Нова відповідь, яку дав Реубен Скреттон, є чудовою і дійсно ефективною, але вона справді працює лише в тому випадку, якщо ви встановите вікноSoftInputMode для настройкиResize. Якщо встановити його для настройкиPan, все одно неможливо визначити, чи відображається клавіатура за допомогою його фрагмента коду. Щоб вирішити це, я зробив цю крихітну модифікацію коду вище.
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
... do something here
}
}
});
TwoDScrollerView
подібного до stackoverflow.com/a/5224088/530513, хоча і зі збільшенням. Дитина не була простою, ImageView
але користувацькою компонуванням (розширюється RelativeLayout
), але не змогла виявити клавіатуру за допомогою рекомендованого рішення, незважаючи на налаштування android:windowSoftInputMode="adjustResize"
. Дякую!
ActionBar
та ActionBarSherlock
. Дуже дякую! До речі, є метод r.height()
:)
heightDiff > root.getRootView().getHeight() / 4
хороша цінність для роботи з пристроєм високої роздільної здатності. 100px - короткий. у Nexus 5 з 1080x1920 res, 1920 - (996-75)>? 100 = 999 1920 - (1776-75)>? 100 = 219 // клавіатура знаходиться в галактиці s2 з роздільною здатністю 480x800, 800 - (800-38)>? 100 = 38 800 - (410-38)>? 100 = 428 // клавіатура працює так, магічне число 100px недостатньо добре.
Це назавжди з точки зору комп'ютера, але це питання все ще неймовірно актуальне!
Тож я взяв вищевказані відповіді і трохи їх поєднав і уточнив ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final int DefaultKeyboardDP = 100;
// From @nathanielwolf answer... Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
// Convert the dp to pixels.
int estimatedKeyboardHeight = (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());
// Conclude whether the keyboard is shown or not.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isShown = heightDiff >= estimatedKeyboardHeight;
if (isShown == wasOpened) {
Log.d("Keyboard state", "Ignoring global layout change...");
return;
}
wasOpened = isShown;
listener.onVisibilityChanged(isShown);
}
});
}
Для мене працює :)
ПРИМІТКА. Якщо ви помітили, що DefaultKeyboardDP не відповідає вашому пристрою, відтворюється зі значенням, і опублікуйте коментар, щоб усі знали, яким має бути значення ... зрештою, ми отримаємо правильне значення для всіх пристроїв!
Для отримання більш детальної інформації ознайомтеся з реалізацією на Cyborg
Вибачте за пізню відповідь, але я створив невеликий допоміжний клас для обробки відкритих та закритих подій із сповіщенням слухачів та інших корисних речей, можливо, хтось вважатиме це корисним:
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import java.util.LinkedList;
import java.util.List;
public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {
public interface SoftKeyboardStateListener {
void onSoftKeyboardOpened(int keyboardHeightInPx);
void onSoftKeyboardClosed();
}
private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
private final View activityRootView;
private int lastSoftKeyboardHeightInPx;
private boolean isSoftKeyboardOpened;
public SoftKeyboardStateWatcher(View activityRootView) {
this(activityRootView, false);
}
public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
this.activityRootView = activityRootView;
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
final Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
isSoftKeyboardOpened = true;
notifyOnSoftKeyboardOpened(heightDiff);
} else if (isSoftKeyboardOpened && heightDiff < 100) {
isSoftKeyboardOpened = false;
notifyOnSoftKeyboardClosed();
}
}
public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
}
public boolean isSoftKeyboardOpened() {
return isSoftKeyboardOpened;
}
/**
* Default value is zero {@code 0}.
*
* @return last saved keyboard height in px
*/
public int getLastSoftKeyboardHeightInPx() {
return lastSoftKeyboardHeightInPx;
}
public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.add(listener);
}
public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.remove(listener);
}
private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardOpened(keyboardHeightInPx);
}
}
}
private void notifyOnSoftKeyboardClosed() {
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardClosed();
}
}
}
}
Приклад використання:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
getLastKeyboardHeightInPx()
не включає висоту цього рядка. Чи знаєте ви про спосіб його врахування?
Деякі вдосконалення, щоб уникнути помилкового виявлення видимості м’якої клавіатури на пристроях високої щільності:
Поріг різниці висоти слід визначати як 128 dp , а не 128 пікселів .
Зверніться до дизайнерської документації Google про метрику та сітку , 48 дп - це зручний розмір для сенсорного об'єкта, а 32 дп - мінімум для кнопок. Універсальна м'яка клавіатура повинна містити 4 ряди клавішних клавіш, тому мінімальна висота клавіатури повинна становити: 32 dp * 4 = 128 dp , це означає, що розмір порогу повинен переноситися на пікселі, збільшуючи щільність пристрою. Для пристроїв xxxhdpi (щільність 4) поріг висоти м'якої клавіатури повинен становити 128 * 4 = 512 пікселів.
Різниця висоти між кореневим видом та його видимою областю:
висота кореневого виду - висота рядка статусу - видима висота кадру = вид кореневого виду - нижня частина кадру, оскільки висота рядка стану дорівнює верхній частині видимого кадру кореневого виду.
private final String TAG = "TextEditor";
private TextView mTextEditor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
mTextEditor = (TextView) findViewById(R.id.text_editor);
mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
isKeyboardShown(mTextEditor.getRootView());
}
});
}
private boolean isKeyboardShown(View rootView) {
/* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
/* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
int heightDiff = rootView.getBottom() - r.bottom;
/* Threshold size: dp to pixels, multiply with display density */
boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;
Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
+ "root view height:" + rootView.getHeight() + ", rect:" + r);
return isKeyboardShown;
}
Я використав трохи часу, щоб розібратися в цьому ... Я запустив це кілька CastExceptions, але зрозумів, що ви можете замінити LinearLayout у layout.xml на ім'я класу.
Подобається це:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">
<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:id="@+id/rlMaster" >
<LinearLayout android:layout_width="fill_parent"
android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>
....
</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>
</LinearLayout>
Таким чином, ви не стикаєтесь з жодними викликами викликів.
... і якщо ви не хочете робити це на кожній сторінці, рекомендую вам використовувати "MasterPage в Android". Дивіться посилання тут: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
Перевірка висоти елементів не є надійною, оскільки деякі клавіатури типу WifiKeyboard мають нульову висоту.
Натомість ви можете використовувати результат зворотного виклику showSoftInput () та hidSoftInput (), щоб перевірити стан клавіатури. Повна інформація та приклад коду на
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
Ідея полягає в тому, що якщо вам потрібно сховати клавіатуру і перевірити стан м'якого введення одночасно, використовуйте наступне рішення:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
Цей метод повертає істину, якщо клавіатура була показана перед приховуванням.
Я виявив, що поєднання методу @ Reuben_Scratton разом із методом @ Йогеша, здається, працює найкраще. Поєднання їх методів дасть щось подібне:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
// ... do something here
}
}
});
Ви можете спостерігати за приховуванням програмної клавіатури, використовуючи decorView діяльності.
public final class SoftKeyboardUtil {
public static final String TAG = "SoftKeyboardUtil";
public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
final View decorView = activity.getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
int displayHight = rect.bottom - rect.top;
int hight = decorView.getHeight();
boolean hide = (double)displayHight / hight > 0.8 ;
if(Log.isLoggable(TAG, Log.DEBUG)){
Log.d(TAG ,"DecorView display hight = "+displayHight);
Log.d(TAG ,"DecorView hight = "+ hight);
Log.d(TAG, "softkeyboard visible = " + !hide);
}
listener.onSoftKeyBoardVisible(!hide);
}
});
}
public interface OnSoftKeyBoardHideListener{
void onSoftKeyBoardVisible(boolean visible);
}
}
Замість того, щоб вважати різницеве кодування, я зробив щось подібне, оскільки я мав в своєму додатку параметри меню.
final View root= findViewById(R.id.myrootview);
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = root.getRootView().getHeight() - root.getHeight();
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
if(heightDiff <= contentViewTop){
//Soft KeyBoard Hidden
}else{
//Soft KeyBoard Shown
}
}
});
Також є рішення із системними вставками, але воно працює лише з API >= 21
( Android L
). Скажіть, у вас BottomNavigationView
є дитина, яка є дочірнім, LinearLayout
і вам потрібно заховати це, коли відображається клавіатура:
> LinearLayout
> ContentView
> BottomNavigationView
Все, що вам потрібно зробити, це розширити LinearLayout
таким чином:
public class KeyboardAwareLinearLayout extends LinearLayout {
public KeyboardAwareLinearLayout(Context context) {
super(context);
}
public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public KeyboardAwareLinearLayout(Context context,
@Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
View view = getChildAt(index);
if (view instanceof BottomNavigationView) {
int bottom = insets.getSystemWindowInsetBottom();
if (bottom >= ViewUtils.dpToPx(200)) {
// keyboard is shown
view.setVisibility(GONE);
} else {
// keyboard is hidden
view.setVisibility(VISIBLE);
}
}
}
return insets;
}
}
Ідея полягає в тому, що коли відображається клавіатура, системні вставки змінюються з досить великим .bottom
значенням.
Існує прихований метод може допомогти в цьому InputMethodManager.getInputMethodWindowVisibleHeight
,. Але я не знаю, чому це приховано.
import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager
class SoftKeyboardStateWatcher(private val ctx: Context) {
companion object {
private const val DELAY = 10L
}
private val handler = Handler()
private var isSoftKeyboardOpened: Boolean = false
private val height: Int
get() {
val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
method.isAccessible = true
return method.invoke(imm) as Int
}
private val task: Runnable by lazy {
Runnable {
start()
if (!isSoftKeyboardOpened && height > 0) {
isSoftKeyboardOpened = true
notifyOnSoftKeyboardOpened(height)
} else if (isSoftKeyboardOpened && height == 0) {
isSoftKeyboardOpened = false
notifyOnSoftKeyboardClosed()
}
}
}
var listener: SoftKeyboardStateListener? = null
interface SoftKeyboardStateListener {
fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
fun onSoftKeyboardClosed()
}
fun start() {
handler.postDelayed(task, DELAY)
}
fun stop() {
handler.postDelayed({
if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
}, DELAY * 10)
}
private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
listener?.onSoftKeyboardOpened(keyboardHeightInPx)
}
private fun notifyOnSoftKeyboardClosed() {
listener?.onSoftKeyboardClosed()
}
}
Жодне з цих рішень не працює для Lollipop, як є. У Lollipop activityRootView.getRootView().getHeight()
включена висота панелі кнопок, при цьому вимірювання виду не робить. Я пристосував найкраще / найпростіше рішення для роботи з Lollipop.
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
Resources res = getResources();
// The status bar is 25dp, use 50dp for assurance
float maxDiff =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());
//Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float buttonBarHeight =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
maxDiff += buttonBarHeight;
}
if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
...do something here
}
}
});
Я щойно стикався з помилкою, використовуючи більшість рішень вище, які пропонують додати фіксовану кількість.
S4 має високий dpi, що призвело до того, що висота панелі навігації становила 100 пікселів, тому мій додаток думає, що клавіатура відкрита весь час.
Тож, коли випускаються всі нові телефони з високою роздільною здатністю, я вважаю, що використання жорсткого кодованого значення не є хорошою ідеєю на тривалий термін.
Кращим підходом, який я знайшов після деяких тестувань на різних екранах та пристроях, було використання відсотків. Отримайте різницю між вмістом програми decorView та ур, а потім перевірте, який відсоток від цієї різниці. З статистики, яку я отримав, більшість навігаційних панелей (незалежно від розміру, роздільної здатності тощо) займуть від 3% до 5% екрана. Якщо ніби клавіатура відкрита, вона займає від 47% до 55% екрану.
Як висновок, моє рішення було перевірити, чи різниця більше 10%, то я вважаю, що її клавіатура відкрита.
Я використав невеликий варіант відповіді Реубана, який виявився кориснішим за певних обставин, особливо з пристроями високої роздільної здатності.
final View activityRootView = findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightView = activityRootView.getHeight();
int widthView = activityRootView.getWidth();
if (1.0 * widthView / heightView > 3) {
//Make changes for Keyboard not visible
} else {
//Make changes for keyboard visible
}
}
});
R.id.activityRoot
ви можете просто використовувати android.R.id.content
саме те, що вам потрібно.
Це назавжди з точки зору комп'ютера, але це питання все ще неймовірно актуальне! Тож я взяв вищевказані відповіді і трохи їх поєднав і уточнив ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isOpen = heightDiff > 100;
if (isOpen == wasOpened) {
logDebug("Ignoring global layout change...");
return;
}
wasOpened = isOpen;
listener.onVisibilityChanged(isOpen);
}
});
}
Це працює для мене.
Спробуйте це:
final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
// ... do something here ... \\
}
}
});
Моя відповідь, в основному, така ж, як відповідь Качі, але я перетворив її в гарний клас помічників, щоб очистити спосіб, яким він користується в моєму додатку.
import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/**
* Detects Keyboard Status changes and fires events only once for each change
*/
public class KeyboardStatusDetector {
KeyboardVisibilityListener visibilityListener;
boolean keyboardVisible = false;
public void registerFragment(Fragment f) {
registerView(f.getView());
}
public void registerActivity(Activity a) {
registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
}
public KeyboardStatusDetector registerView(final View v) {
v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
v.getWindowVisibleDisplayFrame(r);
int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
/** Check this variable to debounce layout events */
if(!keyboardVisible) {
keyboardVisible = true;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
}
} else {
if(keyboardVisible) {
keyboardVisible = false;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
}
}
}
});
return this;
}
public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
visibilityListener = listener;
return this;
}
public static interface KeyboardVisibilityListener {
public void onVisibilityChanged(boolean keyboardVisible);
}
}
Ви можете використовувати це для виявлення змін клавіатури в будь-якій точці програми так:
new KeyboardStatusDetector()
.registerFragment(fragment) //register to a fragment
.registerActivity(activity) //or register to an activity
.registerView(view) //or register to a view
.setVisibilityListener(new KeyboardVisibilityListener() {
@Override
public void onVisibilityChanged(boolean keyboardVisible) {
if(keyboardVisible) {
//Do stuff for keyboard visible
}else {
//Do stuff for keyboard hidden
}
}
});
Примітка: використовуйте лише один із дзвінків "зареєструвати". Всі вони працюють однаково і є лише для зручності
ви можете спробувати це, чудово працює для мене:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
У мене виникли труднощі з підтримкою стану клавіатури при зміні орієнтації фрагментів у вікні перегляду. Я не впевнений, чому, але це, здається, химерно і діє не так, як у стандартній діяльності.
Щоб підтримувати стан клавіатури в цьому випадку, спочатку слід додати android:windowSoftInputMode = "stateUnchanged"
його AndroidManifest.xml
. Ви можете помітити, що це насправді не вирішує всю проблему - клавіатура не відкривалася для мене, якщо вона була раніше відкрита перед зміною орієнтації. У всіх інших випадках поведінка здавалася правильною.
Тоді нам потрібно реалізувати одне із згаданих тут рішень. Найчистішим, який я знайшов, був Джордж Майсурадзе - використовуйте бульний зворотний виклик від hidSoftInputFromWindow:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
Я зберігав це значення в onSaveInstanceState
методі мого фрагмента і отримував його onCreate
. Потім я насильно показав клавіатуру, onCreateView
якщо вона мала значення true
(вона повертає справжнє значення, якщо клавіатура видно, перш ніж її фактично приховати до знищення фрагмента).
Ось моє рішення, і воно працює. Замість того, щоб шукати розмір пікселів, просто перевірте, чи змінилася висота подання вмісту чи ні:
// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private int oldHeight;
@Override
public void onGlobalLayout() {
int newHeight = commentsContent.getMeasuredHeight();
if (newHeight < oldHeight) {
// Check for the keyboard showing in case the height difference
// is a result of orientation change
if (isSoftKeyboardShowing(CommentsActivity.this)) {
// Keyboard is showing so scroll to the latest comment
scrollToLatestComment();
}
}
oldHeight = newHeight;
}
});
public static boolean isSoftKeyboardShowing(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
return inputMethodManager.isActive();
}
Не робіть жодного жорсткого коду. Найкращий спосіб - вам змінити розмір переглядів, перебуваючи під час фокусування на EditText за допомогою KeyBord Show. Ви можете зробити це, додавши властивість зміни розміру за активністю у файл Manifest, використовуючи код нижче.
android:windowSoftInputMode="adjustResize"
Існує прямий метод, щоб дізнатися це. І це не потребує змін у макеті.
Отже, він також працює в режимі повноекранного режиму.
Хитрість полягає в тому, що ви намагаєтесь сховати або показати м'яку клавіатуру і зафіксувати результат цієї спроби.
Ніякої паніки, це насправді не показує і не приховує клавіатуру. Ми просто просимо державу.
Щоб бути в курсі останніх, ви можете просто повторити операцію, наприклад, кожні 200 мілісекунд, використовуючи обробник.
Ви знайдете реалізацію тут: https://stackoverflow.com/a/27567074/2525452
Я думаю, що цей метод допоможе вам з’ясувати, видно чи не клавіатура.
public Boolean isSoftKeyBoardVisible(){
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
Log.d(TAG,"Software Keyboard was shown");
return true;
} else {
Log.d(TAG,"Software Keyboard was not shown");
return false;
}
}
Нова відповідь Реубена Скреттона (обчисліть HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
) не працюватиме, якщо встановити режим напівпрозорого рядка стану.
якщо ви використовуєте напівпрозору панель стану, activityRootView.getHeight()
вона ніколи не змінить погоду, видно м'яку клавіатуру. вона завжди повертатиме висоту активності та смугу стану.
Наприклад, Nexus 4, Android 5.0.1, встановлений android:windowTranslucentStatus
на true, він поверне 1184 назавжди, навіть ім’я відкриється. Якщо встановлено android:windowTranslucentStatus
значення false, воно вірно поверне Height, якщо ім’я невидиме, воно поверне 1134 (не включаючи рядок стану)
Я не знаю, погода це помилка, я спробував 4.4.4 та 5.0.1, результат той самий.
Отже, на сьогоднішній день, друга найбільш узгоджена відповідь, рішення Качі буде найбезпечнішим способом обчислення висоти імені. Ось копія:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});
Метод, який не потребує LayoutListener
У своєму випадку я хотів би зберегти стан клавіатури перед тим, як замінити мій фрагмент. Я називаю метод hidSoftInputFromWindow від onSaveInstanceState
, який закриває клавіатуру і повертає мені, чи була клавіатура видимою чи ні.
Цей метод простий, але може змінити стан вашої клавіатури.
Я знаю, що це старий пост, але я думаю, що це найпростіший підхід, про який я знаю, і мій тестовий пристрій Nexus 5. Я не пробував його на інших пристроях. Сподіваюся, що інші поділяться своїм підходом, якщо вони знайдуть мій код, це не добре :)
public static boolean isKeyboardShown(Context context, View view) {
if (context == null || view == null) {
return false;
}
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
imm.hideSoftInputFromWindow повертає логічне значення.
Дякую,
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
Вищенаведена функція - це те, що я використовую, щоб перевірити, чи не відображається клавіатура. Якщо є, то я його закриваю.
Нижче показані два необхідні методи.
Спочатку визначте працездатну висоту вікна в onCreate.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// add to onCreate method
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
sheight= rectgle.bottom;
//
}
Потім додайте булевий метод, який отримує висоту Window у цьому екземплярі. Якщо він не відповідає оригіналу (якщо припустити, що ви його не змінюєте по дорозі ...), клавіатура відкрита.
public boolean keyopen()
{
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int curheight= rectgle.bottom;
if (curheight!=sheight)
{
return true;
}
else
{
return false;
}
}
Фроц!
Я знаю, наскільки точно ви можете визначити, прихована чи ні клавіатура.
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public int getNavigationBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public boolean isKeyboardHidden() {
int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
- getSupportActionBar().getHeight();
return delta <= 0;
}
Це працює для планшетів. Коли панель навігації відображається горизонтально.