Çok basit bir şey yapmam gerekiyor - yazılım klavyesinin gösterilip gösterilmediğini öğrenin. Android'de bu mümkün mü?
Çok basit bir şey yapmam gerekiyor - yazılım klavyesinin gösterilip gösterilmediğini öğrenin. Android'de bu mümkün mü?
Yanıtlar:
NEW ANSWER 25 Oca 2012 ekledi
Aşağıdaki cevabı yazdığından beri birisi beni ViewTreeObserver'ın varlığına işaret etti ve arkadaşlarının, SDK'da sürüm 1'den beri gizlenen API'ların .
Özel bir Düzen türü gerektirmek yerine, daha basit bir çözüm, etkinliğinizin kök görünümüne bilinen bir kimlik vermek, örneğin @+id/activityRoot
ViewTreeObserver'a bir GlobalLayoutListener bağlamak ve oradan etkinliğinizin görünüm kökü ile pencere boyutu arasındaki fark farkını hesaplamaktır:
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
}
}
});
Aşağıdaki gibi bir yardımcı program kullanma:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
Kolay!
Not:
Uygulamanız Android Manifest'te bu bayrağı ayarlamalıdır, android:windowSoftInputMode="adjustResize"
aksi takdirde yukarıdaki çözüm çalışmaz.
ORİJİNAL CEVAP
Evet bu mümkün, ancak olması gerekenden çok daha zor.
Klavyenin ne zaman göründüğüne ve kaybolduğuna dikkat etmem gerekiyorsa (ki bu oldukça sıktır) o zaman yaptığım şey üst düzey düzen sınıfımı geçersiz kılan bir sınıfta özelleştirmektir onMeasure()
. Temel mantık, mizanpajın pencerenin toplam alanından önemli ölçüde daha az dolum bulması durumunda, yumuşak bir klavyenin muhtemelen gösteriliyor olmasıdır.
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);
}
}
Sonra Etkinlik sınıfınızda ...
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
) kullanarak denerseniz System
, uygulamanızın yüksekliğini değiştiren varlıktan ziyade daha güvenli olduğunu söyleyebilirsiniz . Android ekibinin bize bir mola vermesi ve SoftKeyboard girişi hakkında en azından temel şeyleri bize bildirmesi çok daha güvenli olurdu.
heightDiff
Her zaman eylem çubuğunun yüksekliğini içerecek şekilde dikkat edin . Bu yüksekliğin sabitten biraz daha büyük olup olmadığını test ederek yok sayılan yeni yanıtta, ancak Nexus 4 gibi xxhdpi cihazları için 100 piksel yeterli değildir. Bu hacky çalışmasını gerçekten kullanmak istiyorsanız bu değeri DP'lere dönüştürmeyi düşünün etrafında.
Umarım bu birisine yardım eder.
Reuben Scratton'un verdiği yeni cevap harika ve gerçekten etkilidir, ancak gerçekten sadece windowSoftInputMode öğenizi ResResize ayarlayacak şekilde ayarlarsanız çalışır. AdjustPan olarak ayarlarsanız, kod snippet'ini kullanarak klavyenin görünür olup olmadığını tespit etmek yine de mümkün değildir. Bu soruna geçici bir çözüm bulmak için yukarıdaki kodda bu küçük değişikliği yaptım.
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
benzeri bir özel klavye durumunu algılamaya çalışıyordum . Çocuk basit değil, özel bir düzendi (genişliyor ), ancak ayarlara rağmen önerilen çözümü kullanarak klavyeyi algılayamadı . Teşekkürler! ImageView
RelativeLayout
android:windowSoftInputMode="adjustResize"
ActionBar
ve ActionBarSherlock
. Çok teşekkürler! Bu arada, bir yöntem var r.height()
:)
heightDiff > root.getRootView().getHeight() / 4
yüksek çözünürlüklü cihazlarla çalışmak için iyi bir değerdir. 100 piksel kısadır. 1080x1920 res ile Nexus 5'te, 1920 - (996-75)>? 100 = 999 1920 - (1776-75)>? 100 = 219 // klavye galaxy s2'de 480x800 res, 800 - (800-38) ile çalışıyor>? 100 = 38800 - (410-38)>? 100 = 428 // klavye bitti, sihirli sayı 100px yeterince iyi değil.
Bilgisayar açısından sonsuza dek sürdü, ancak bu soru hala inanılmaz derecede alakalı!
Bu yüzden yukarıdaki cevapları aldım ve onları biraz birleştirdim ve geliştirdim ...
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);
}
});
}
Benim için çalışıyor :)
NOT: Eğer fark ederseniz DefaultKeyboardDP cihazınıza uygun ve herkesin değerin ne olması gerektiğini bilmesi için bir yorum gönderirseniz ... sonunda tüm cihazlara uyacak doğru değeri elde ederiz!
Daha fazla ayrıntı için Cyborg'daki uygulamaya göz atın
Geç cevap için özür dilerim, ancak dinleyicilere ve diğer faydalı şeylere bildirimde bulunarak açık / kapalı olayları ele almak için küçük bir yardımcı sınıf oluşturmuştum, birisi yararlı olabilir:
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();
}
}
}
}
Kullanım örneği:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
getLastKeyboardHeightInPx()
bu satırın yüksekliğini içermez. Bunu da dikkate almanın bir yolunu biliyor musunuz?
Yüksek yoğunluklu cihazlarda yazılım klavyesinin görünürlüğünü yanlış algılamaktan kaçınmak için bazı iyileştirmeler:
Yükseklik farkı eşiği 128 piksel değil 128 dp olarak tanımlanmalıdır . Metrikler ve Izgara hakkında Google tasarım dokümanına
bakın , 48 dp dokunmatik nesne için rahat boyut ve düğmeler için minimum 32 dp . Genel yazılım klavyesi 4 satır tuş düğmesi içermelidir, bu nedenle minimum klavye yüksekliği şu şekilde olmalıdır: 32 dp * 4 = 128 dp , yani eşik boyutu, aygıt yoğunluğunu çarparak piksellere aktarmalıdır. Xxxhdpi aygıtları (yoğunluk 4) için, yumuşak klavye yükseklik eşiği 128 * 4 = 512 piksel olmalıdır.
Kök görünüm ve görünür alanı arasındaki yükseklik farkı:
kök görünüm yüksekliği - durum çubuğu yüksekliği - görünür çerçeve yüksekliği = kök görünüm alt - görünür çerçeve alt, çünkü durum çubuğu yüksekliği kök görünümün görünür çerçevesinin üstüne eşittir.
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;
}
Bunu anlamak için biraz zaman kullandım ... Bazı CastExceptions'ı çalıştırdım, ancak layout.xml'deki LinearLayout'u sınıfın adıyla değiştirebileceğinizi anladım.
Bunun gibi:
<?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>
Bu şekilde herhangi bir yayın sorunuyla karşılaşmazsınız.
... ve bunu her sayfada yapmak istemiyorsanız "Android'de MasterPage" kullanmanızı öneririz. Buradaki bağlantıya bakın: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
WifiKeyboard gibi bazı klavyelerin yüksekliği sıfır olduğu için öğelerin yüksekliğini kontrol etmek güvenilir değildir.
Bunun yerine, klavyenin durumunu kontrol etmek için showSoftInput () ve hideSoftInput () öğelerinin geri arama sonuçlarını kullanabilirsiniz. Tüm ayrıntılar ve örnek kod
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
Fikir şu ki, klavyenizi gizlemeniz ve yumuşak giriş durumunu aynı anda kontrol etmeniz gerekiyorsa, aşağıdaki çözümü kullanın:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
Gizlenmeden önce klavye gösteriliyorsa bu yöntem true değerini döndürür.
Ben @ Yogesh yöntemi ile birlikte @ Reuben_Scratton yönteminin bir kombinasyon en iyi gibi görünüyor bulundu. Yöntemlerini birleştirmek şöyle bir şey getirecektir:
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
}
}
});
Etkinliğin decorView özelliğini kullanarak ekran klavyesinin gizlenmesini gözlemleyebilirsiniz.
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);
}
}
Fark kodlama varsaymak yerine, benim uygulamada menü seçenekleri vardı dint gibi böyle bir şey yaptım.
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
}
}
});
Sistem ekleriyle de çözüm var, ancak yalnızca API >= 21
( Android L
) ile çalışıyor . Sahip olduğunuzu BottomNavigationView
, hangisinin çocuk olduğunu LinearLayout
ve klavye gösterildiğinde gizlemeniz gerektiğini varsayalım:
> LinearLayout
> ContentView
> BottomNavigationView
Tek yapmanız gereken LinearLayout
bu şekilde uzanmaktır :
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;
}
}
Fikir, klavye gösterildiğinde, sistem eklerinin oldukça büyük bir .bottom
değerle değiştirilmesidir .
Bunun için yardımcı olabilecek gizli bir yöntem var InputMethodManager.getInputMethodWindowVisibleHeight
. Ama neden gizli olduğunu bilmiyorum.
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()
}
}
Bu çözümlerin hiçbiri Lollipop için olduğu gibi çalışmaz. Lollipop'ta activityRootView.getRootView().getHeight()
görünümü ölçerken düğme çubuğunun yüksekliğini içerir. Lollipop ile çalışmak için yukarıdaki en iyi / en basit çözümü uyarladım.
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
}
}
});
Sabit bir sayı eklemeyi öneren yukarıdaki çözümlerin çoğunu kullanırken bir hatayla karşılaştım.
S4, gezinme çubuğunun yüksekliğinin 100 piksel olmasına neden olan yüksek bir dpi'ye sahip, bu yüzden uygulamam klavyenin her zaman açık olduğunu düşünüyor.
Yani tüm yeni yüksek çözünürlüklü telefonlar piyasaya sürüldüğünde, sabit kodlanmış bir değer kullanmanın uzun vadede iyi bir fikir olmadığını düşünüyorum.
Çeşitli ekranlar ve cihazlarda bazı testlerden sonra bulduğum daha iyi bir yaklaşım yüzde kullanmaktı. DecorView ve ur uygulama içeriği arasındaki farkı edinin ve daha sonra bu farkın yüzdesinin ne olduğunu kontrol edin. Sahip olduğum istatistiklerden, çoğu gezinti çubuğu (boyut, çözünürlük vb. Ne olursa olsun) ekranın% 3 ila% 5'ini alacaktır. Klavyenin açık olduğu yerlerde ekranın% 47 ila% 55'ini alıyordu.
Sonuç olarak benim çözümüm fark% 10'dan fazla olup olmadığını kontrol etmek oldu ben onun bir klavye açık olduğunu varsayalım.
Reuban'ın cevabının, özellikle yüksek çözünürlüklü cihazlarda, bazı durumlarda daha yararlı olduğunu kanıtlayan hafif bir varyantını kullandım.
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
, sadece kullanabilirsiniz android.R.id.content
tam olarak neye ihtiyacınız olduğu.
Bilgisayar açısından sonsuza dek sürdü, ancak bu soru hala inanılmaz derecede alakalı! Bu yüzden yukarıdaki cevapları aldım ve onları biraz birleştirdim ve geliştirdim ...
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);
}
});
}
Benim için çalışıyor.
Bunu dene:
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 ... \\
}
}
});
Cevabım temel olarak Kachi'nin cevabı ile aynı, ama benim uygulama boyunca kullanım şeklini temizlemek için güzel bir yardımcı sınıfa sardım.
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);
}
}
Bunu, uygulamanın herhangi bir yerinde klavye değişikliklerini şu şekilde tespit etmek için kullanabilirsiniz:
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
}
}
});
Not: "kayıt" çağrılarından yalnızca birini kullanın. Hepsi aynı şekilde çalışıyor ve sadece rahatlık için oradalar
bunu deneyebilir, benim için harika çalışabilirsin:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
Bir viewpager içindeki parçaların yönünü değiştirirken klavye durumunu korumakta zorlanıyordum. Neden olduğundan emin değilim, ama sadece sakat gibi görünüyor ve standart bir Faaliyetten farklı davranıyor.
Bu durumda klavye durumunu korumak için, önce klavyenizi eklemeniz android:windowSoftInputMode = "stateUnchanged"
gerekir AndroidManifest.xml
. Bununla birlikte, bunun aslında tüm sorunu çözmediğini fark edebilirsiniz - klavye daha önce yönlendirme değişikliğinden önce açılmışsa benim için açılmadı. Diğer tüm durumlarda, davranış doğru görünüyordu.
O zaman burada bahsedilen çözümlerden birini uygulamalıyız. Bulduğum en temiz George Maisuradze's - hideSoftInputFromWindow'dan boolean geri aramasını kullanın:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
Bu değeri Fragment'ın onSaveInstanceState
yönteminde sakladım ve aldım onCreate
. Daha sonra, klavyeyi onCreateView
bir değeri varsa zorla gösterdim true
(parça parça yıkımından önce gerçekten gizlemeden önce klavyenin görünür olması durumunda doğru döner).
İşte benim çözümüm ve işe yarıyor. Piksel boyutu aramak yerine, içerik görünümünün yüksekliğinin değişip değişmediğini kontrol edin:
// 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();
}
Hiçbir sabit kod yazmayın. En iyi yol, KeyBord Show ile EditText'e Odaklanın sırasında görüşlerinizi yeniden boyutlandırmanızdır. Aşağıdaki kodu kullanarak etkinlikteki resize özelliğini Manifest dosyasına ekleyerek yapabilirsiniz.
android:windowSoftInputMode="adjustResize"
Bunu bulmak için doğrudan bir yöntem var. Ayrıca, herhangi bir Düzen değişikliği gerektirmez.
Böylece, sürükleyici tam ekran modunda da çalışır.
Hile, yumuşak klavyeyi gizlemeye veya göstermeye ve bu denemenin sonucunu yakalamaya çalışmanızdır.
Panik yok, bu gerçekten klavyeyi göstermiyor veya gizlemiyor. Sadece devleti istiyoruz.
Güncel kalmak için bir Handler kullanarak işlemi, örneğin her 200 milisaniyede bir tekrarlayabilirsiniz.
Burada bir uygulama bulabilirsiniz: https://stackoverflow.com/a/27567074/2525452
Bu yöntemin klavye görünür olup olmadığını bulmanıza yardımcı olacağını düşünüyorum.
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;
}
}
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
Yarı saydam durum çubuğu modunu ayarlarsanız, Reuben Scratton'ın yeni yanıtı (HeightDiff'i hesaplayın ) etkinlikte çalışmaz.
yarı saydam durum çubuğunu kullanırsanız activityRootView.getHeight()
, yumuşak klavyenin görünür olduğu hava durumunu asla değiştirmez. her zaman etkinlik yüksekliğini ve durum çubuğunu döndürür.
Örneğin, Nexus 4, Android 5.0.1, android:windowTranslucentStatus
true olarak ayarlanmış , 1184 sonsuza kadar geri dönecek, ime bile açacaktır. Eğer ayarlarsanandroid:windowTranslucentStatus
False olarak , Yüksekliği doğru şekilde döndürür, ime görünmezse, 1134 (durum çubuğunu içermez) döndürür。 ime'yi kapatın, belki 5xx döndürür (ime'nin yüksekliğine bağlıdır)
Hava durumu bu bir hata olduğunu bilmiyorum, 4.4.4 ve 5.0.1 üzerinde denedim, sonuç aynı.
Yani, şimdiye kadar, en çok anlaşılan ikinci cevap olan Kachi'nin çözümü ime'nin yüksekliğini hesaplamanın en güvenli yolu olacak. İşte bir kopyası:
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
}
}
});
Bir yöntem , bir LayoutListener ihtiyacı yoktur
Benim durumumda, Parçamı değiştirmeden önce klavyenin durumunu kaydetmek istiyorum. Ben yöntemini çağırır hideSoftInputFromWindow danonSaveInstanceState
klavye görünür veya değildi beni ister klavye ve döner kapatır.
Bu yöntem basittir, ancak klavyenizin durumunu değiştirebilir.
Bunun eski bir yazı olduğunu biliyorum ama bunun bildiğim en basit yaklaşım olduğunu ve test cihazımın Nexus 5 olduğunu düşünüyorum. Başka cihazlarda denemedim. Umarım kodumu iyi bulmazlarsa diğerlerinin yaklaşımlarını paylaşırlar :)
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 boole değerini döndürür.
Teşekkürler,
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
Yukarıdaki işlev, bir Klavyenin görünür olup olmadığını kontrol etmek için kullandığım işlevdir. Eğer öyleyse, kapatırım.
Aşağıda gerekli iki yöntem gösterilmektedir.
İlk olarak, onCreate'da uygulanabilir Pencere yüksekliğini tanımlayın.
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;
//
}
Ardından, bu örnekte Window yüksekliğini alan bir boolean yöntemi ekleyin. Orijinalle eşleşmiyorsa (yol boyunca değiştirmediğinizi varsayarsak ...) o zaman klavye açıktır.
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!
Klavyenin gizli olup olmadığını nasıl kesin olarak belirleyebileceğinizi biliyorum.
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;
}
Bu tabletler için geçerlidir. Gezinme çubuğu yatay olarak gösterildiğinde.