मुझे एक बहुत ही सरल काम करने की ज़रूरत है - पता करें कि क्या सॉफ्टवेयर कीबोर्ड दिखाया गया है। क्या यह एंड्रॉइड में संभव है?
मुझे एक बहुत ही सरल काम करने की ज़रूरत है - पता करें कि क्या सॉफ्टवेयर कीबोर्ड दिखाया गया है। क्या यह एंड्रॉइड में संभव है?
जवाबों:
नई उत्तर 25 जनवरी 2012 को जोड़ा गया
नीचे दिए गए उत्तर को लिखने के बाद से, किसी ने मुझे ViewTreeObserver और दोस्तों, API के अस्तित्व से चिपकाया , जो कि संस्करण 1 के बाद से SDK में गुप्त है।
कस्टम लेआउट प्रकार की आवश्यकता के बजाय, एक बहुत ही सरल उपाय आपकी गतिविधि के मूल दृश्य को एक ज्ञात आईडी देना है, कहते हैं @+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 मैनिफ़ेस्ट में सेट करना होगा android:windowSoftInputMode="adjustResize"
अन्यथा उपरोक्त समाधान काम नहीं करेगा।
मूल ANSWER
हाँ यह संभव है, लेकिन यह जितना होना चाहिए उससे कहीं अधिक कठिन है।
यदि मुझे इस बात की परवाह करने की आवश्यकता है कि कीबोर्ड कब दिखाई देता है और गायब हो जाता है (जो कि अक्सर होता है) तो मैं जो करता हूं वह मेरे टॉप-लेवल लेआउट क्लास को एक में अनुकूलित करता है जो ओवरराइड करता है 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
आपके आवेदन की बजाय इकाई बदल रही है। एंड्रॉइड टीम को हमें ब्रेक देने के लिए बहुत अधिक सुरक्षित होगा और हमें सॉफ्टकबोर्ड इनपुट के बारे में कम से कम बुनियादी बातें बताएं।
heightDiff
हमेशा एक्शन बार की ऊंचाई शामिल होगी। नए उत्तर में जिसे परीक्षण द्वारा नजरअंदाज किया गया है यदि वह ऊंचाई कुछ स्थिर से अधिक है, लेकिन 100 पिक्सल xxhdpi उपकरणों जैसे कि Nexus 4 के लिए पर्याप्त नहीं है। यदि आप वास्तव में इस हैक किए गए कार्य का उपयोग करना चाहते हैं, तो उस मान को DPs में परिवर्तित करने पर विचार करें- चारों ओर।
तो उम्मीद है कि यह किसी को बाहर करने में मदद करता है।
रूबेन स्क्रैटन ने जो नया उत्तर दिया, वह महान और वास्तव में कुशल है, लेकिन यह वास्तव में केवल तभी काम करता है जब आप समायोजित करने के लिए अपने विंडो को सेट करें। InputMode। यदि आप इसे एडजस्ट करने के लिए सेट करते हैं, तो यह पता लगाना संभव नहीं है कि कीबोर्ड अपने कोड स्निपेट का उपयोग कर रहा है या नहीं। इसके चारों ओर काम करने के लिए, मैंने इस छोटे से संशोधन को ऊपर दिए गए कोड में कर दिया।
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 को छोटा करना है। नेक्सस 5 में 1080x1920 रेस, 1920 - (996-75)> के साथ? 100 = 999 1920 - (1776-75)>? 100 = 219 // कीबोर्ड 480x800 रेस, 800 - (800-38)> के साथ आकाशगंगा s2 में है? 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 आपके डिवाइस को मूल्य के साथ खेलने के लिए फिट नहीं करता है और सभी के लिए एक टिप्पणी पोस्ट करता है कि यह जानने के लिए कि मूल्य क्या होना चाहिए ... आखिरकार हमें सभी उपकरणों को फिट करने के लिए सही मूल्य मिलेगा!
अधिक जानकारी के लिए, साइबोर्ग पर कार्यान्वयन की जांच करें
देर से जवाब के लिए क्षमा करें, लेकिन मैंने श्रोताओं और अन्य उपयोगी चीजों को सूचित करने के साथ खुली / करीबी घटनाओं को संभालने के लिए एक छोटा सहायक वर्ग बनाया था, हो सकता है कि कोई व्यक्ति इसे उपयोगी समझे:
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 डीपी के रूप में परिभाषित किया जाना चाहिए , न कि 128 पिक्सेल । मेट्रिक्स और ग्रिड के बारे में Google डिज़ाइन डॉक्टर
को देखें , 48 dp टच ऑब्जेक्ट के लिए आरामदायक आकार है और बटन के लिए 32 dp न्यूनतम है। जेनेरिक सॉफ्ट कीबोर्ड में कुंजी बटन की 4 पंक्तियाँ शामिल होनी चाहिए, इसलिए न्यूनतम कीबोर्ड की ऊँचाई होनी चाहिए: 32 डीपी * 4 = 128 डीपी , इसका अर्थ है कि थ्रेशोल्ड आकार को गुणा डिवाइस घनत्व द्वारा पिक्सेल में स्थानांतरित करना चाहिए। 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;
}
मैंने यह पता लगाने के लिए थोड़ा समय का उपयोग किया ... मैंने इसे कुछ CastException चलाया, लेकिन यह पता लगा लिया कि आप LinearLayout को लेआउट के रूप में बदल सकते हैं। वर्ग के नाम के साथ 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>
इस तरह आप किसी भी कास्ट इश्यू में नहीं चलते हैं।
... और यदि आप हर पृष्ठ पर ऐसा नहीं करना चाहते हैं, तो मेरा सुझाव है कि आप "Android में MasterPage" का उपयोग करें। यहां देखें लिंक: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
तत्वों की ऊंचाई की जाँच विश्वसनीय नहीं है क्योंकि WifiKeyboard जैसे कुछ कीबोर्ड में शून्य ऊँचाई होती है।
इसके बजाय, आप कीबोर्ड की स्थिति की जांच करने के लिए showSoftInput () और HideSoftInput () के कॉलबैक परिणाम का उपयोग कर सकते हैं। पूर्ण विवरण और उदाहरण कोड
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);
}
यदि कीबोर्ड छिपने से पहले दिखाया गया था, तो यह विधि सही है।
मैंने पाया कि @ योगेश की विधि के साथ @ रूबेन_क्रैटन की विधि का संयोजन सबसे अच्छा काम करता है। उनके तरीकों को मिलाने से कुछ ऐसा होगा:
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
}
}
});
आप गतिविधि के सजावट दृश्य का उपयोग करके सॉफ्टबोर्ड के छिपाने का निरीक्षण कर सकते हैं।
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()
}
}
इनमें से कोई भी समाधान लॉलीपॉप के लिए काम नहीं करेगा। लॉलीपॉप activityRootView.getRootView().getHeight()
में बटन बार की ऊंचाई शामिल है, जबकि दृश्य माप नहीं करता है। मैंने लॉलीपॉप के साथ काम करने के लिए ऊपर दिए गए सबसे अच्छे / सरल समाधान को अनुकूलित किया है।
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 में एक उच्च डीपीआई है, जिसके परिणामस्वरूप नेविगेशन बार की ऊंचाई 100px है, इसलिए मेरा ऐप यह सोचता है कि कीबोर्ड हर समय खुला है।
इसलिए जारी किए गए सभी नए उच्च रेस फोन के साथ मेरा मानना है कि एक कठिन कोडित मूल्य का उपयोग करना दीर्घकालिक के लिए एक अच्छा विचार नहीं है।
एक बेहतर दृष्टिकोण जो मैंने विभिन्न स्क्रीन और उपकरणों पर कुछ परीक्षण के बाद पाया, प्रतिशत का उपयोग करना था। सज्जा दृश्य और उर ऐप सामग्री के बीच अंतर प्राप्त करें और बाद में जांच लें कि उस अंतर का प्रतिशत क्या है। मुझे जो आंकड़े मिले हैं, उनमें से अधिकांश नेवि बार (आकार, रिज़ॉल्यूशन आदि की परवाह किए बिना) स्क्रीन के 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
। आप देख सकते हैं, हालांकि, यह वास्तव में पूरी समस्या को हल नहीं करता है - कीबोर्ड मेरे लिए खुला नहीं था अगर यह अभिविन्यास परिवर्तन से पहले खोला गया था। अन्य सभी मामलों में, व्यवहार सही लग रहा था।
फिर, हमें यहां वर्णित समाधानों में से एक को लागू करने की आवश्यकता है। मुझे जो सबसे साफ-सुथरा पाया गया वह था जॉर्ज मैसुरदेज़ का - छिपाने से बुलियन कॉलबैक का उपयोग करना।
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();
}
कोई हार्ड कोड न बनाएं। सबसे अच्छा तरीका है कि आपको अपने विचारों का आकार बदलना है, जबकि KeyBord शो के साथ EditText पर ध्यान केंद्रित करें। आप इसे निम्न कोड के उपयोग से मेनिफेस्ट फ़ाइल में गतिविधि पर आकार बदलने वाली संपत्ति जोड़ सकते हैं।
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;
}
}
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
यदि आप ट्रांसलूसेंट स्टेटस बार मोड सेट करते हैं तो रूबेन स्क्रैटन का नया उत्तर (हाइटडिफ़ की गणना ) गतिविधि में काम नहीं करेगा।
यदि आप पारभासी स्थिति पट्टी का उपयोग करते हैं, activityRootView.getHeight()
तो कभी भी मौसम में बदलाव नहीं होगा जो कि नरम कीबोर्ड दिखाई देता है। यह हमेशा गतिविधि और स्थिति पट्टी की ऊंचाई वापस करेगा।
उदाहरण के लिए, नेक्सस 4, एंड्रॉइड 5.0.1 android:windowTranslucentStatus
, यह सच है, यह 1184 हमेशा के लिए वापस आ जाएगा, यहां तक कि चूने का भी ऑपेंड है। यदि आप सेट करते हैंandroid:windowTranslucentStatus
असत्य पर होते हैं, तो यह ऊँचाई को सही ढंग से लौटाएगा, यदि ime अदृश्य है, तो यह 1134 लौटाता है (स्टेटस बार को शामिल नहीं करता है) imeclose, यह 5xx वापस आ जाएगा शायद (ime की ऊंचाई पर निर्भर करता है)
मुझे नहीं पता कि मौसम यह एक बग है, मैंने 4.4.4 और 5.0.1 पर कोशिश की है, परिणाम समान है।
तो, अब तक, दूसरा सबसे सहमत उत्तर, काची का समाधान ime की ऊंचाई को शांत करने का सबसे सुरक्षित तरीका होगा। यहाँ एक प्रति है:
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
}
}
});
एक ऐसी विधि जिसमें एक लेआउटलिस्ट की जरूरत नहीं है
मेरे मामले में, मैं अपने फ्रैगमेंट को बदलने से पहले कीबोर्ड की स्थिति को बचाना चाहूंगा। मैं पद्धति को कॉल करता हूं HideSoftInputFromWindow से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;
//
}
फिर, एक बूलियन विधि जोड़ें जो उस उदाहरण पर विंडो ऊंचाई प्राप्त करती है। यदि यह मूल से मेल नहीं खाता (यह मानते हुए कि आप इसे रास्ते में नहीं बदल रहे हैं ...) तो, कीबोर्ड खुला है।
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!
मुझे पता है कि आप यह निर्धारित कर सकते हैं कि कीबोर्ड छिपा है या नहीं।
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;
}
यह गोलियों के लिए काम करता है। जब नेवीगेशन को क्षैतिज रूप से दिखाया जाता है।