Saya perlu melakukan hal yang sangat sederhana - cari tahu apakah keyboard perangkat lunak ditampilkan. Apakah ini mungkin di Android?
Saya perlu melakukan hal yang sangat sederhana - cari tahu apakah keyboard perangkat lunak ditampilkan. Apakah ini mungkin di Android?
Jawaban:
NEW ANSWER ditambahkan 25 Jan 2012
Sejak menulis jawaban di bawah ini, seseorang memberi petunjuk kepada saya tentang keberadaan ViewTreeObserver dan teman-teman, API yang telah mengintai di SDK sejak versi 1.
Daripada memerlukan jenis Tata Letak khusus, solusi yang jauh lebih sederhana adalah memberikan tampilan root aktivitas Anda ID yang dikenal, katakan @+id/activityRoot
, kaitkan GlobalLayoutListener ke ViewTreeObserver, dan dari sana hitung perbedaan ukuran antara root tampilan aktivitas Anda dan ukuran jendela:
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
}
}
});
Menggunakan utilitas seperti:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
Mudah!
Catatan:
Aplikasi Anda harus mengatur tanda ini di Android Manifest android:windowSoftInputMode="adjustResize"
jika tidak, solusi di atas tidak akan berfungsi.
JAWABAN ASLI
Ya itu mungkin, tapi itu jauh lebih sulit dari yang seharusnya.
Jika saya perlu peduli kapan keyboard muncul dan menghilang (yang cukup sering) maka apa yang saya lakukan adalah menyesuaikan kelas tata letak tingkat atas saya menjadi yang ditimpa onMeasure()
. Logika dasar adalah bahwa jika tata letak menemukan dirinya mengisi secara signifikan kurang dari total luas jendela, maka keyboard lunak mungkin ditampilkan.
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);
}
}
Kemudian di kelas Aktivitas Anda ...
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
) Anda akan dapat lebih percaya diri mengatakan bahwa System
alih - alih aplikasi Anda adalah entitas yang mengubah tingginya. Akan jauh lebih aman bagi tim Android untuk memberi kami istirahat dan beri tahu kami setidaknya hal-hal dasar tentang input SoftKeyboard.
heightDiff
akan selalu mencakup ketinggian bilah tindakan. Di jawaban baru yang telah diabaikan oleh pengujian apakah ketinggian itu lebih besar dari beberapa konstanta, tetapi 100 piksel tidak cukup untuk perangkat xxhdpi seperti Nexus 4. Pertimbangkan untuk mengubah nilai itu ke DP jika Anda benar-benar ingin menggunakan pekerjaan yang peretasan ini- sekitar.
Jadi semoga ini membantu seseorang keluar.
Jawaban baru yang diberikan Reuben Scratton sangat bagus dan sangat efisien, tetapi itu benar-benar hanya berfungsi jika Anda mengatur windowSoftInputMode Anda untuk menyesuaikanResize. Jika Anda mengaturnya ke AdjustPan, masih tidak mungkin mendeteksi apakah keyboard terlihat menggunakan potongan kode-nya atau tidak. Untuk mengatasinya, saya membuat modifikasi kecil pada kode di atas.
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
mirip dengan stackoverflow.com/a/5224088/530513 meskipun dengan zooming juga. Anak itu tidak sederhana ImageView
tetapi tata letak kustom (meluas RelativeLayout
) tetapi tidak dapat mendeteksi keyboard menggunakan solusi yang disarankan meskipun pengaturan android:windowSoftInputMode="adjustResize"
. Terima kasih!
ActionBar
dan ActionBarSherlock
. Terima kasih banyak! Omong-omong, ada metode r.height()
:)
heightDiff > root.getRootView().getHeight() / 4
adalah nilai yang baik untuk bekerja dengan perangkat resolusi tinggi. 100px adalah singkatnya. di Nexus 5 dengan 1080x1920 res, 1920 - (996-75)>? 100 = 999 1920 - (1776-75)>? 100 = 219 // keyboard menyala di galaxy s2 dengan 480x800 res, 800 - (800-38)>? 100 = 38 800 - (410-38)>? 100 = 428 // keyboard naik jadi, angka ajaib 100px tidak cukup baik.
Sudah selamanya dalam hal komputer tetapi pertanyaan ini masih sangat relevan!
Jadi saya telah mengambil jawaban di atas dan telah menggabungkan dan memperbaikinya sedikit ...
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);
}
});
}
Bekerja untuk saya :)
CATATAN: Jika Anda melihat bahwa DefaultKeyboardDP tidak sesuai dengan perangkat Anda bermain dengan nilai dan memposting komentar untuk semua orang untuk mengetahui apa yang seharusnya menjadi nilai ... akhirnya kami akan mendapatkan nilai yang benar untuk semua perangkat!
Untuk detail lebih lanjut, lihat implementasi di Cyborg
Maaf atas jawaban yang terlambat, tetapi saya telah membuat kelas pembantu kecil untuk menangani acara buka / tutup dengan memberi tahu pendengar dan hal-hal bermanfaat lainnya, mungkin seseorang akan merasa terbantu:
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();
}
}
}
}
Contoh penggunaan:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
getLastKeyboardHeightInPx()
tidak termasuk ketinggian baris itu. Apakah Anda tahu cara untuk memperhitungkannya juga?
Beberapa peningkatan untuk menghindari kesalahan mendeteksi visibilitas keyboard lunak pada perangkat kepadatan tinggi:
Ambang batas perbedaan ketinggian harus didefinisikan sebagai 128 dp , bukan 128 piksel .
Lihat dokumen desain Google tentang Metrik dan Kotak , 48 dp adalah ukuran yang nyaman untuk objek sentuh dan 32 dp minimum untuk tombol. Keyboard lunak generik harus menyertakan 4 baris tombol, jadi tinggi minimum keyboard harus: 32 dp * 4 = 128 dp , itu berarti ukuran ambang batas harus ditransfer ke piksel dengan mengalikan kepadatan perangkat. Untuk perangkat xxxhdpi (kepadatan 4), ambang tinggi keyboard lunak harus 128 * 4 = 512 piksel.
Perbedaan tinggi antara tampilan root dan area yang terlihat:
tinggi tampilan root - tinggi status bar - tinggi bingkai terlihat = tampilan dasar root - bawah bingkai terlihat, karena tinggi status bar sama dengan bagian atas bingkai terlihat pandangan root.
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;
}
Saya menggunakan sedikit waktu untuk mencari tahu ini ... Saya menjalankannya beberapa CastExceptions, tetapi menemukan bahwa Anda dapat menggantikan Anda LinearLayout di layout.xml dengan nama kelas.
Seperti ini:
<?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>
Dengan begitu Anda tidak mengalami masalah pemeran.
... dan jika Anda tidak ingin melakukan ini di setiap halaman, saya sarankan Anda menggunakan "MasterPage di Android". Lihat tautan di sini: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
Memeriksa ketinggian elemen tidak dapat diandalkan karena beberapa keyboard seperti WifiKeyboard memiliki tinggi nol.
Sebagai gantinya, Anda dapat menggunakan hasil panggil balik showSoftInput () dan hideSoftInput () untuk memeriksa status keyboard. Rincian lengkap dan kode contoh di
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
Idenya adalah, jika Anda perlu menyembunyikan keyboard Anda dan memeriksa status input lunak pada saat yang sama, gunakan solusi berikut:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
Metode ini mengembalikan true jika keyboard ditampilkan sebelum bersembunyi.
Saya menemukan bahwa kombinasi metode @ Reuben_Scratton bersama dengan metode @ Yogesh tampaknya bekerja paling baik. Menggabungkan metode mereka akan menghasilkan sesuatu seperti ini:
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
}
}
});
Anda dapat mengamati persembunyian papan tombol dengan menggunakan decorView aktivitas.
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);
}
}
Alih-alih mengasumsikan perbedaan coding saya melakukan sesuatu seperti ini, karena saya tidak punya opsi menu di aplikasi saya.
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
}
}
});
Ada juga solusi dengan insets sistem, tetapi hanya bekerja dengan API >= 21
( Android L
). Katakan sudah BottomNavigationView
, yang merupakan anak dari LinearLayout
dan Anda perlu menyembunyikannya saat keyboard ditampilkan:
> LinearLayout
> ContentView
> BottomNavigationView
Yang perlu Anda lakukan adalah memperluas LinearLayout
sedemikian rupa:
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;
}
}
Idenya adalah ketika keyboard ditampilkan, insets sistem diubah dengan .bottom
nilai yang cukup besar .
Ada metode tersembunyi yang bisa membantu untuk ini InputMethodManager.getInputMethodWindowVisibleHeight
,. Tapi saya tidak tahu mengapa itu disembunyikan.
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()
}
}
Tak satu pun dari solusi ini yang akan berfungsi untuk Lollipop seperti apa adanya. Di LollipopactivityRootView.getRootView().getHeight()
termasuk ketinggian bilah tombol, sedangkan mengukur tampilan tidak. Saya telah mengadaptasi solusi terbaik / paling sederhana di atas untuk bekerja dengan 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
}
}
});
Saya baru saja menemukan bug saat menggunakan sebagian besar solusi di atas yang menyarankan menambahkan nomor tetap.
S4 memiliki dpi tinggi yang mengakibatkan ketinggian bilah navigasi menjadi 100px sehingga aplikasi saya berpikir bahwa keyboard terbuka sepanjang waktu.
Jadi dengan semua ponsel beresolusi tinggi yang baru dirilis saya percaya menggunakan nilai kode keras bukan ide yang baik untuk jangka panjang.
Pendekatan yang lebih baik yang saya temukan setelah beberapa pengujian pada berbagai layar dan perangkat adalah menggunakan persentase. Dapatkan perbedaan antara decorView dan konten aplikasi Anda dan kemudian periksa berapa persentase perbedaan itu. Dari statistik yang saya dapatkan, sebagian besar nav bar (terlepas dari ukuran, resolusi dll.) Akan mengambil antara 3% hingga 5% dari layar. Di mana seolah-olah keyboard terbuka itu mengambil antara 47% hingga 55% dari layar.
Sebagai kesimpulan solusi saya adalah untuk memeriksa apakah diff lebih dari 10% maka saya menganggap itu keyboard terbuka.
Saya menggunakan sedikit varian dari jawaban Reuban, yang terbukti lebih membantu dalam keadaan tertentu, terutama dengan perangkat resolusi tinggi.
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
, Anda cukup menggunakan android.R.id.content
yang persis Anda butuhkan.
Sudah selamanya dalam hal komputer tetapi pertanyaan ini masih sangat relevan! Jadi saya telah mengambil jawaban di atas dan telah menggabungkan dan memperbaikinya sedikit ...
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);
}
});
}
Ini bekerja untuk saya.
Coba ini:
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 ... \\
}
}
});
Jawaban saya pada dasarnya sama dengan jawaban Kachi, tetapi saya membungkusnya menjadi kelas pembantu yang bagus untuk membersihkan cara penggunaannya di seluruh aplikasi saya.
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);
}
}
Anda dapat menggunakan ini untuk mendeteksi perubahan keyboard di mana saja di seluruh aplikasi seperti ini:
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
}
}
});
Catatan: hanya gunakan salah satu panggilan "daftar". Mereka semua bekerja sama dan hanya ada untuk kenyamanan
Anda dapat mencoba ini, bekerja sangat baik untuk saya:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
Saya mengalami kesulitan mempertahankan keadaan keyboard saat mengubah orientasi fragmen dalam viewpager. Saya tidak yakin mengapa, tetapi sepertinya tidak stabil dan bertindak berbeda dari Kegiatan standar.
Untuk mempertahankan keadaan keyboard dalam hal ini, pertama Anda harus menambahkan android:windowSoftInputMode = "stateUnchanged"
keAndroidManifest.xml
. Anda mungkin memperhatikan, bahwa ini tidak benar-benar menyelesaikan seluruh masalah - keyboard tidak terbuka untuk saya jika sebelumnya dibuka sebelum perubahan orientasi. Dalam semua kasus lain, perilaku itu tampaknya benar.
Kemudian, kita perlu mengimplementasikan salah satu solusi yang disebutkan di sini. Yang terbersih yang saya temukan adalah milik George Maisuradze - gunakan panggilan balik boolean dari hideSoftInputFromWindow:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
Saya menyimpan nilai ini dalam onSaveInstanceState
metode Fragmen saya dan mengambilnya onCreate
. Kemudian, saya secara paksa menunjukkan keyboard onCreateView
jika memiliki nilai true
(mengembalikan benar jika keyboard terlihat sebelum benar-benar menyembunyikannya sebelum penghancuran Fragmen).
Inilah solusi saya, dan itu berhasil. Alih-alih mencari ukuran piksel cukup periksa bahwa ketinggian tampilan konten telah berubah atau tidak:
// 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();
}
Jangan membuat kode keras. Cara terbaik adalah Anda harus mengubah ukuran tampilan saat di Dapatkan Fokus pada EditText dengan KeyBord Show. Anda dapat melakukan ini menambahkan properti ukuran pada aktivitas ke dalam file Manifest menggunakan kode di bawah ini.
android:windowSoftInputMode="adjustResize"
Ada metode langsung untuk mengetahuinya. Dan, itu tidak memerlukan perubahan Tata Letak.
Jadi, ia bekerja dalam mode layar penuh imersif juga.
Kuncinya adalah Anda mencoba menyembunyikan atau menampilkan keyboard lunak dan menangkap hasil percobaan itu.
Jangan panik, ini tidak benar-benar menunjukkan atau menyembunyikan keyboard. Kami hanya meminta negara.
Agar tetap terkini, Anda cukup mengulangi operasi, misalnya setiap 200 milidetik, menggunakan Handler.
Anda menemukan implementasi di sini: https://stackoverflow.com/a/27567074/2525452
Saya pikir metode ini akan membantu Anda untuk mengetahui apakah keybord terlihat atau tidak.
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;
}
}
Jawaban baru Reuben Scratton (menghitung HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
) tidak akan berfungsi dalam aktivitas jika Anda mengatur mode status bar transparan.
jika Anda menggunakan bilah status transparan, activityRootView.getHeight()
tidak akan pernah mengubah cuaca keyboard lunak terlihat. itu akan selalu mengembalikan ketinggian aktivitas dan status bar.
Sebagai contoh, Nexus 4, Android 5.0.1, disetel android:windowTranslucentStatus
ke true, itu akan mengembalikan 1184 selamanya, bahkan saat sedang opend. Jika Anda mengaturandroid:windowTranslucentStatus
false, itu akan mengembalikan Tinggi dengan benar, jika saya tidak terlihat, itu mengembalikan 1134 (tidak termasuk status bar)。 tutup ime, itu akan mengembalikan 5xx mungkin (tergantung pada tinggi ime)
Saya tidak tahu apakah ini bug, saya sudah mencoba 4.4.4 dan 5.0.1, hasilnya sama.
Jadi, hingga sekarang, jawaban kedua yang paling disepakati, solusi Kachi akan menjadi cara paling aman untuk menghitung ketinggian waktu. Ini salinannya:
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
}
}
});
Metode yang tidak memerlukan LayoutListener
Dalam kasus saya, saya ingin menyimpan keadaan keyboard sebelum mengganti Fragmen saya. Saya memanggil metode hideSoftInputFromWindow dari onSaveInstanceState
, yang menutup keyboard dan mengembalikan saya apakah keyboard itu terlihat atau tidak.
Metode ini mudah tetapi dapat mengubah kondisi keyboard Anda.
Saya tahu bahwa ini adalah posting lama tetapi saya pikir ini adalah pendekatan paling sederhana yang saya tahu dan perangkat pengujian saya adalah Nexus 5. Saya belum mencobanya di perangkat lain. Berharap bahwa orang lain akan membagikan pendekatan mereka jika mereka menemukan kode saya tidak baik :)
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 mengembalikan boolean.
Terima kasih,
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
Fungsi di atas adalah apa yang saya gunakan untuk memeriksa apakah Keyboard terlihat. Jika ya, maka saya akan menutupnya.
Di bawah ini menunjukkan dua metode yang diperlukan.
Pertama, tentukan ketinggian Window yang bisa diterapkan di 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;
//
}
Kemudian, tambahkan metode boolean yang mendapatkan tinggi Window pada saat itu. Jika tidak cocok dengan aslinya (dengan asumsi Anda tidak mengubahnya sepanjang jalan ...) maka, keyboard terbuka
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;
}
}
Frotz!
Saya tahu seberapa tepat Anda dapat menentukan apakah keyboard disembunyikan atau tidak.
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;
}
Ini berfungsi untuk tablet. Ketika bilah navigasi ditampilkan secara horizontal.