Softtastatur zum Öffnen und Schließen des Listeners in einer Aktivität in Android


136

Ich habe eine Activitywo es 5 EditTexts gibt. Wenn der Benutzer auf die erste klickt EditText, wird die Softtastatur geöffnet, um einen Wert einzugeben. Ich möchte die ViewSichtbarkeit eines anderen festlegen , Gonewenn die Softtastatur geöffnet wird und wenn der Benutzer auf die erste klickt EditTextund wenn die Softtastatur von derselben aus geschlossen wirdEditText die Softtastatur beim Drücken der Zurück-Taste . Dann möchte ich die ViewSichtbarkeit eines anderen auf sichtbar setzen.

Gibt es einen Listener oder Rückruf oder einen Hack, wenn die Softtastatur durch Klicken auf die erste EditTextin Android geöffnet wird ?


1
Nein, es gibt keine solchen Zuhörer. Es gibt Hacks, um das zu erreichen, was Sie versuchen. Hier ist ein möglicher Ansatz: So senden Sie ein Zeigerereignis in Android .
Vikram

@ Vikram Ich suche nichttrying to detect the virtual keyboard height in Android.
N Sharma

Ich weiß. Wenn Sie den Code durchgehen, sehen Sie, wie die Höhe bestimmt wird. Ein Zeigerereignis wird gesendet -> zwei Fälle => 1. wenn die Tastatur geöffnet ist => & wenn der Zeiger Xund die YPosition auf / über die Tastatur fallen => SecurityException=> dekrementieren Yund erneut versuchen => bis keine Ausnahme ausgelöst wird => Der aktuelle YWert ist die Tastaturhöhe. 2. wenn die Tastatur nicht geöffnet ist => nein SecurityException.
Vikram

Wie trifft dies auf Ihr Szenario zu? Senden Sie ein Zeigerereignis mit beispielsweise 2/3 der Bildschirmhöhe. Wenn a SecurityExceptiongeworfen wird => ist die Tastatur geöffnet. Andernfalls ist die Tastatur geschlossen.
Vikram

@ Vikram Ich will das nur erstmal EditTextnicht anders EditText. Wie kann ich das unterscheiden?
N Sharma

Antworten:


91

Dies funktioniert nur, wenn android:windowSoftInputModeIhre Aktivität adjustResizeim Manifest festgelegt ist. Sie können einen Layout-Listener verwenden, um festzustellen, ob die Größe des Stammlayouts Ihrer Aktivität über die Tastatur geändert wird.

Ich verwende für meine Aktivitäten so etwas wie die folgende Basisklasse:

public class BaseActivity extends Activity {
    private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
            int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();

            LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(BaseActivity.this);

            if(heightDiff <= contentViewTop){
                onHideKeyboard();

                Intent intent = new Intent("KeyboardWillHide");
                broadcastManager.sendBroadcast(intent);
            } else {
                int keyboardHeight = heightDiff - contentViewTop;
                onShowKeyboard(keyboardHeight);

                Intent intent = new Intent("KeyboardWillShow");
                intent.putExtra("KeyboardHeight", keyboardHeight);
                broadcastManager.sendBroadcast(intent);
            }
        }
    };

    private boolean keyboardListenersAttached = false;
    private ViewGroup rootLayout;

    protected void onShowKeyboard(int keyboardHeight) {}
    protected void onHideKeyboard() {}

    protected void attachKeyboardListeners() {
        if (keyboardListenersAttached) {
            return;
        }

        rootLayout = (ViewGroup) findViewById(R.id.rootLayout);
        rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);

        keyboardListenersAttached = true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (keyboardListenersAttached) {
            rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
        }
    }
}

In der folgenden Beispielaktivität wird dies verwendet, um eine Ansicht auszublenden, wenn die Tastatur angezeigt wird, und um sie erneut anzuzeigen, wenn die Tastatur ausgeblendet ist.

Das XML-Layout:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/rootLayout"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">              

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        >

        <!-- omitted for brevity -->

    </ScrollView>

    <LinearLayout android:id="@+id/bottomContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <!-- omitted for brevity -->

    </LinearLayout>

</LinearLayout>

Und die Aktivität:

public class TestActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        attachKeyboardListeners();
    }

    @Override
    protected void onShowKeyboard(int keyboardHeight) {
        // do things when keyboard is shown
        bottomContainer.setVisibility(View.GONE);
    }

    @Override
    protected void onHideKeyboard() {
        // do things when keyboard is hidden
        bottomContainer.setVisibility(View.VISIBLE);
    }        
}

4
+1 Ja, das ist die perfekte Lösung für mein Problem.
N Sharma

18
Hallo, Sie haben getTop () für Window.ID_ANDROID_CONTENT verwendet. Get top funktioniert bei mir nicht. Hier ist es immer 0, es funktioniert so, als ob stattdessen getHeight () verwendet werden soll.
Daniele Segato

1
Woher kommst du rootLayout = (ViewGroup) findViewById(R.id.rootLayout);?
CommonSenseCode

1
Es funktioniert aus irgendeinem Grund nicht für mich und ruft immer ShowKeyboard auf, entweder ich öffne es oder schließe es. Ich verwende findViewById (android.R.id.content). Vielleicht ist das das Problem?
McSullivan D'Ander

2
@tsig Ihre + 100-Lösung hängt von einem bestimmten Bildschirm ab. Auf Tablets und HDPI-Handys fehlgeschlagen. Ich habe die Korrektur als zehn Prozent der Gerätehöhe verwendet. Das heißt, wenn die Ansichtshöhe niedriger als screenHeight - 10% ist, ist die Tastatur geöffnet. sonst ist die Tastatur geschlossen. Hier ist mein contentViewTop in onGlobalLayout: contentViewTop = (getWindow (). GetDecorView (). GetBottom () / 10)
ilker

93

Ein Kinderspiel mit der fantastischen KeyboardVisibilityEvent-Bibliothek

KeyboardVisibilityEvent.setEventListener(
    getActivity(),
    new KeyboardVisibilityEventListener() {
        @Override
        public void onVisibilityChanged(boolean isOpen) {
            // write your code
        }
    });

Credits für Yasuhiro SHIMIZU


Dies funktioniert nicht, da Tastaturen keine statischen Höhen haben und die Höhe in dieser Bibliothek auf 100 dp eingestellt ist.
Milosmns

@milosmns Für die Tastaturerkennung wird eine Schwellenhöhe von 100 dp verwendet. Es wird keine Annahme über die tatsächliche Tastaturhöhe gemacht
Nino van Hooff

11
Es ist immer noch hart codiert. Multi Fenster? Samsung Split View? Bild im Bildmodus? Es gibt auch eine minimale einzeilige Tastatur, die unter 100 dp fällt. Es gibt keine Silberkugel hier ...
Milosmns

1
Da es für dieses Problem keinen Haken gibt, scheint dies am einfachsten zu implementieren zu sein und Sie kehren einfach zu dem Code zurück, an dem Sie tatsächlich arbeiten möchten :)
Machine Tribe

1
Dies ist bei weitem die beste Antwort, absolut zuverlässig auf jedem Gerät
Pelanes

69

Wie Vikram in den Kommentaren betonte, ist es nur mit einigen hässlichen Hacks möglich festzustellen, ob das Softkeyboard angezeigt wird oder verschwunden ist.

Vielleicht reicht es aus, einen Fokus-Listener auf den Edittext zu setzen :

yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            //got focus
        } else {
            //lost focus
        }
   }
});

27
Angenommen, ich klicke auf den Edittext, dann wird der setOnFocusChangeListenerListener aufgerufen, dann drücke ich zurück, dann schließt er die Tastatur und klickt nicht auf andere Ansichten. Jetzt klicke ich wieder auf denselben Edittext, der bereits den Fokus hat. Was passiert dann?
N Sharma

3
@ Williams Ich bin mir nicht ganz sicher, aber ich vermute, dass onFocusChange()das nicht aufgerufen wird.
CommonGuy

1
Das ist nicht meine Frage. Bitte lesen Sie meine Frage noch einmal - ich habe Aktivität, bei der es 5 EditText gibt. Wenn der Benutzer zuerst auf EditText klickt, wird die Softtastatur geöffnet, um einen Wert einzugeben. Ich möchte die Sichtbarkeit einer anderen Ansicht auf "Gone" setzen, wenn die Softtastatur geöffnet wird, wenn der Benutzer zuerst auf "EditText" klickt, und wenn die Softtastatur beim Zurückdrücken von demselben EditText aus geschlossen wird. Dann möchte ich die Sichtbarkeit einer anderen Ansicht auf "Sichtbar" setzen. Gibt es einen Listener oder Rückruf oder einen Hack, wenn die Softtastatur beim Klicken auf den ersten EditText in Android geöffnet wird?
N Sharma

4
Jungs sehen diese Antwort nicht, weil er etwas anderes erzählt, auch wenn ich es nicht verstehe.
N Sharma

2
Wie auch immer, es funktioniert bei mir nicht ... Wenn die Softtastatur ausgeblendet ist, ist beim EditText keine Fokusänderung aufgetreten ... Ich kann also keine Benachrichtigung von diesem Listener erhalten.
Licat Julius

50

Für Aktivität:

    final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();

                activityRootView.getWindowVisibleDisplayFrame(r);

                int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 100) { 
                 //enter your code here
                }else{
                 //enter code for hid
                }
            }
        });

Für Fragment:

    view = inflater.inflate(R.layout.live_chat_fragment, null);
view.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.
                view.getWindowVisibleDisplayFrame(r);

                int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 500) { // if more than 100 pixels, its probably a keyboard...

                }
            }
        });

3
Ich habe es für Aktivitäten verwendet, aber anstatt es mit der Ansicht zu vergleichen, habe ich es mit der Bildschirmgröße verglichen. funktioniert
super

Besser wäre es, heightDiff mit einer Höhe in dp zu vergleichen, anstatt in Pixel. Es kann erheblich variieren.
Leo Droidcoder

Braucht das das android:windowSoftInputMode="adjustResize"In-Manifest?
LiuWenbin_NO.

android: windowSoftInputMode = "adjustResize" android: configChanges = "Ausrichtung | Tastatur | Tastatur
versteckt

Es funktioniert bei mir, trotzdem habe ich eine Frage. Kostet es viele Ressourcen?
Licat Julius

32

Jaaps Antwort wird nicht für AppCompatActivity arbeiten. Ermitteln Sie stattdessen die Höhe der Statusleiste und der Navigationsleiste usw. und vergleichen Sie sie mit der Fenstergröße Ihrer App.

Wie so:

    private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // navigation bar height
        int navigationBarHeight = 0;
        int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            navigationBarHeight = getResources().getDimensionPixelSize(resourceId);
        }

        // status bar height
        int statusBarHeight = 0;
        resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = getResources().getDimensionPixelSize(resourceId);
        }

        // display window size for the app layout
        Rect rect = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);

        // screen height - (user app height + status + nav) ..... if non-zero, then there is a soft keyboard
        int keyboardHeight = rootLayout.getRootView().getHeight() - (statusBarHeight + navigationBarHeight + rect.height());

        if (keyboardHeight <= 0) {
            onHideKeyboard();
        } else {
            onShowKeyboard(keyboardHeight);
        }
    }
};

Scheint mit einer Ausnahme ziemlich gut zu funktionieren: Pausen im Split-Screen-Modus. Ansonsten ist es toll.
MCLLC

14

Du kannst es versuchen:

private void initKeyBoardListener() {
    // Минимальное значение клавиатуры. 
    // Threshold for minimal keyboard height.
    final int MIN_KEYBOARD_HEIGHT_PX = 150;
    // Окно верхнего уровня view. 
    // Top-level window decor view.
    final View decorView = getWindow().getDecorView();
    // Регистрируем глобальный слушатель. Register global layout listener.
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        // Видимый прямоугольник внутри окна. 
        // Retrieve visible rectangle inside window.
        private final Rect windowVisibleDisplayFrame = new Rect();
        private int lastVisibleDecorViewHeight;

        @Override
        public void onGlobalLayout() {
            decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
            final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();

            if (lastVisibleDecorViewHeight != 0) {
                if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) {
                    Log.d("Pasha", "SHOW");
                } else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) {
                    Log.d("Pasha", "HIDE");
                }
            }
            // Сохраняем текущую высоту view до следующего вызова.
            // Save current decor view height for the next call.
            lastVisibleDecorViewHeight = visibleDecorViewHeight;
        }
    });
}

Spasibo, Dolbik! :)
AlexS

4

Sie können meine Rx-Erweiterungsfunktion (Kotlin) verwenden.

/**
 * @return [Observable] to subscribe of keyboard visibility changes.
 */
fun AppCompatActivity.keyboardVisibilityChanges(): Observable<Boolean> {

    // flag indicates whether keyboard is open
    var isKeyboardOpen = false

    val notifier: BehaviorSubject<Boolean> = BehaviorSubject.create()

    // approximate keyboard height
    val approximateKeyboardHeight = dip(100)

    // device screen height
    val screenHeight: Int = getScreenHeight()

    val visibleDisplayFrame = Rect()

    val viewTreeObserver = window.decorView.viewTreeObserver

    val onDrawListener = ViewTreeObserver.OnDrawListener {

        window.decorView.getWindowVisibleDisplayFrame(visibleDisplayFrame)

        val keyboardHeight = screenHeight - (visibleDisplayFrame.bottom - visibleDisplayFrame.top)

        val keyboardOpen = keyboardHeight >= approximateKeyboardHeight

        val hasChanged = isKeyboardOpen xor keyboardOpen

        if (hasChanged) {
            isKeyboardOpen = keyboardOpen
            notifier.onNext(keyboardOpen)
        }
    }

    val lifeCycleObserver = object : GenericLifecycleObserver {
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event?) {
            if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
                viewTreeObserver.removeOnDrawListener(onDrawListener)
                source.lifecycle.removeObserver(this)
                notifier.onComplete()
            }
        }
    }

    viewTreeObserver.addOnDrawListener(onDrawListener)
    lifecycle.addObserver(lifeCycleObserver)

    return notifier
            .doOnDispose {
                viewTreeObserver.removeOnDrawListener(onDrawListener)
                lifecycle.removeObserver(lifeCycleObserver)
            }
            .onTerminateDetach()
            .hide()
}

Beispiel:

(context as AppCompatActivity)
                    .keyboardVisibilityChanges()
                    .subscribeBy { isKeyboardOpen ->
                        // your logic
                    }

Funktioniert bei mir nicht Kann keine Methoden finden dip()undgetScreenHeight()
Marcin Kunert

@MarcinKunert ist nur eine Erweiterungsfunktion, mit der Sie Pixel in dp konvertieren und die Bildschirmhöhe ermitteln können. Wenn Sie möchten, kann ich Ihnen ein Beispiel für solche Funktionen geben
Vlad

GenericLifecycleObserver ist veraltet? irgendeine Lösung?
Zainal Fahrudin

4

Der folgende Code funktioniert für mich,

mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (mainLayout != null) {
                int heightDiff = mainLayout.getRootView().getHeight() - mainLayout.getHeight();
                if (heightDiff > dpToPx(getActivity(), 200)) { 
                   //keyboard is open
                } else {
                   //keyboard is hide
                }
            }
        }
    });

2

Wenn Sie können, versuchen Sie, EditText zu erweitern und die Methode 'onKeyPreIme' zu überschreiben.

@Override
public void setOnEditorActionListener(final OnEditorActionListener listener) {
    mEditorListener = listener; //keep it for later usage
    super.setOnEditorActionListener(listener);
}

@Override
public boolean onKeyPreIme(final int keyCode, final KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        if (mEditorListener != null) {
            //you can define and use custom listener,
            //OR define custom R.id.<imeId>
            //OR check event.keyCode in listener impl
            //* I used editor action because of ButterKnife @
            mEditorListener.onEditorAction(this, android.R.id.closeButton, event);
        }
    }
    return super.onKeyPreIme(keyCode, event);
}

Wie können Sie es erweitern:

  1. Implementieren Sie onFocus Listening und deklarieren Sie 'onKeyboardShown'.
  2. deklariere 'onKeyboardHidden'

Ich denke, dass die Neuberechnung der Bildschirmhöhe nicht 100% erfolgreich ist, wie bereits erwähnt. Um klar zu sein, wird das Überschreiben von 'onKeyPreIme' bei den Methoden 'Soft Keyboard programmgesteuert ausblenden' nicht aufgerufen. ABER wenn Sie dies irgendwo tun, sollten Sie dort die Logik 'onKeyboardHidden' ausführen und keine umfassenden Lösungen erstellen.


1
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainactivity);
    attachKeyboardListeners();
    ....
    yourEditText1.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                yourEditText2.setVisibility(View.GONE);
                yourEditText3.setVisibility(View.GONE);
                yourEditText4.setVisibility(View.GONE);
                yourEditText5.setVisibility(View.GONE);
            } else {
                yourEditText2.setVisibility(View.VISIBLE);
                yourEditText3.setVisibility(View.VISIBLE);
                yourEditText4.setVisibility(View.VISIBLE);
                yourEditText5.setVisibility(VISIBLE);
            }
       }
    });
    }
}

Angenommen, ich klicke auf den Edittext, dann wird der setOnFocusChangeListenerListener aufgerufen, dann drücke ich zurück, dann schließt er die Tastatur und klickt nicht auf andere Ansichten. Jetzt klicke ich wieder auf denselben Edittext, der bereits den Fokus hat. Was passiert dann?
N Sharma

Das ist nicht meine Frage. Bitte lesen Sie meine Frage noch einmal - ich habe Aktivität mit 5 EditText. Wenn der Benutzer zuerst auf EditText klickt, wird die Softtastatur geöffnet, um einen Wert einzugeben. Ich möchte die Sichtbarkeit einer anderen Ansicht auf "Gone" setzen, wenn die Softtastatur geöffnet wird, wenn der Benutzer zuerst auf "EditText" klickt, und wenn die Softtastatur beim Zurückdrücken von demselben EditText aus geschlossen wird. Dann möchte ich die Sichtbarkeit einer anderen Ansicht auf "Sichtbar" setzen. Gibt es einen Listener oder Rückruf oder einen Hack, wenn die Softtastatur beim Klicken auf den ersten EditText in Android geöffnet wird?
N Sharma

1
Wenn Sie zurück drücken, wird die Tastatur geschlossen, wenn der onfocusHörer nie anruft. Ich schaue nicht nach dem, was Sie vorschlagen
N Sharma

1

Verwenden Sie diese Klasse,

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

public class SoftKeyboard implements View.OnFocusChangeListener
{
private static final int CLEAR_FOCUS = 0;

private ViewGroup layout;
private int layoutBottom;
private InputMethodManager im;
private int[] coords;
private boolean isKeyboardShow;
private SoftKeyboardChangesThread softKeyboardThread;
private List<EditText> editTextList;

private View tempView; // reference to a focused EditText

public SoftKeyboard(ViewGroup layout, InputMethodManager im)
{
    this.layout = layout;
    keyboardHideByDefault();
    initEditTexts(layout);
    this.im = im;
    this.coords = new int[2];
    this.isKeyboardShow = false;
    this.softKeyboardThread = new SoftKeyboardChangesThread();
    this.softKeyboardThread.start();
}

public void openSoftKeyboard()
{
    if(!isKeyboardShow)
    {
        layoutBottom = getLayoutCoordinates();
        im.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);
        softKeyboardThread.keyboardOpened();
        isKeyboardShow = true;
    }
}

public void closeSoftKeyboard()
{
    if(isKeyboardShow)
    {
        im.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
        isKeyboardShow = false;
    }
}

public void setSoftKeyboardCallback(SoftKeyboardChanged mCallback)
{
    softKeyboardThread.setCallback(mCallback);
}

public void unRegisterSoftKeyboardCallback()
{
    softKeyboardThread.stopThread();
}

public interface SoftKeyboardChanged 
{
    public void onSoftKeyboardHide();
    public void onSoftKeyboardShow();   
}

private int getLayoutCoordinates()
{
    layout.getLocationOnScreen(coords);
    return coords[1] + layout.getHeight();
}

private void keyboardHideByDefault()
{
    layout.setFocusable(true);
    layout.setFocusableInTouchMode(true);
}

/*
 * InitEditTexts now handles EditTexts in nested views
 * Thanks to Francesco Verheye (verheye.francesco@gmail.com)
 */
private void initEditTexts(ViewGroup viewgroup) 
{
    if(editTextList == null)
        editTextList = new ArrayList<EditText>();

    int childCount = viewgroup.getChildCount();
    for(int i=0; i<= childCount-1;i++) 
    {
        View v = viewgroup.getChildAt(i);

        if(v instanceof ViewGroup) 
        {
            initEditTexts((ViewGroup) v);
        }

        if(v instanceof EditText) 
        {
            EditText editText = (EditText) v;
            editText.setOnFocusChangeListener(this);
            editText.setCursorVisible(true);
            editTextList.add(editText);
        }
    }
}

/*
 * OnFocusChange does update tempView correctly now when keyboard is still shown
 * Thanks to Israel Dominguez (dominguez.israel@gmail.com)
 */
@Override
public void onFocusChange(View v, boolean hasFocus) 
{
    if(hasFocus) 
    {
        tempView = v;
        if(!isKeyboardShow) 
        {
            layoutBottom = getLayoutCoordinates();
            softKeyboardThread.keyboardOpened();
            isKeyboardShow = true;
        }
    }
}

// This handler will clear focus of selected EditText
private final Handler mHandler = new Handler()
{
    @Override
    public void handleMessage(Message m)
    {
        switch(m.what)
        {
        case CLEAR_FOCUS:
            if(tempView != null)
            {
                tempView.clearFocus();
                tempView = null;
            }
            break;
        }
    }
};

private class SoftKeyboardChangesThread extends Thread
{
    private AtomicBoolean started;
    private SoftKeyboardChanged mCallback;

    public SoftKeyboardChangesThread()
    {
        started = new AtomicBoolean(true);
    }

    public void setCallback(SoftKeyboardChanged mCallback)
    {
        this.mCallback = mCallback;
    }

    @Override
    public void run()
    {
        while(started.get())
        {
            // Wait until keyboard is requested to open
            synchronized(this)
            {
                try 
                {
                    wait();
                } catch (InterruptedException e) 
                {
                    e.printStackTrace();
                }
            }

            int currentBottomLocation = getLayoutCoordinates();

            // There is some lag between open soft-keyboard function and when it really appears.
            while(currentBottomLocation == layoutBottom && started.get())
            {
                currentBottomLocation = getLayoutCoordinates();
            }

            if(started.get())
                mCallback.onSoftKeyboardShow();

            // When keyboard is opened from EditText, initial bottom location is greater than layoutBottom
            // and at some moment equals layoutBottom.
            // That broke the previous logic, so I added this new loop to handle this.
            while(currentBottomLocation >= layoutBottom && started.get())
            {
                currentBottomLocation = getLayoutCoordinates();
            }

            // Now Keyboard is shown, keep checking layout dimensions until keyboard is gone
            while(currentBottomLocation != layoutBottom && started.get())
            {
                                    synchronized(this)
                {
                    try 
                    {
                        wait(500);
                    } catch (InterruptedException e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                currentBottomLocation = getLayoutCoordinates();
            }

            if(started.get())
                mCallback.onSoftKeyboardHide();

            // if keyboard has been opened clicking and EditText.
            if(isKeyboardShow && started.get())
                isKeyboardShow = false;

            // if an EditText is focused, remove its focus (on UI thread)
            if(started.get())
                mHandler.obtainMessage(CLEAR_FOCUS).sendToTarget();
        }   
    }

    public void keyboardOpened()
    {
        synchronized(this)
        {
            notify();
        }
    }

    public void stopThread()
    {
        synchronized(this)
        {
            started.set(false);
            notify();
        }
    }

}
}

In Android Manifest, android:windowSoftInputMode="adjustResize"ist notwendig.

/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root
InputMethodManager im = (InputMethodManager)getSystemService(Service.INPUT_METHOD_SERVICE);

/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged() {

@Override
public void onSoftKeyboardHide()  {
    // Code here
}

@Override
public void onSoftKeyboardShow() {
    // Code here
}   
});

/*
Open or close the soft keyboard easily
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();

/* Prevent memory leaks:*/
@Override
public void onDestroy() {
    super.onDestroy();
    softKeyboard.unRegisterSoftKeyboardCallback();
}

PS - Komplett von hier genommen .


1

Für den Fall von adjustResizeund FragmentActivity akzeptierte Lösung von @Jaap funktioniert bei mir nicht.

Hier ist meine Lösung:

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    private int contentDiff;
    private int rootHeight;
    @Override
    public void onGlobalLayout() {
        View contentView = getWindow().findViewById(Window.ID_ANDROID_CONTENT);
        if (rootHeight != mDrawerLayout.getRootView().getHeight()) {
            rootHeight = mDrawerLayout.getRootView().getHeight();
            contentDiff = rootHeight - contentView.getHeight();
            return;
        }
        int newContentDiff = rootHeight - contentView.getHeight();
        if (contentDiff != newContentDiff) {
            if (contentDiff < newContentDiff) {
                onShowKeyboard(newContentDiff - contentDiff);
            } else {
                onHideKeyboard();
            }
            contentDiff = newContentDiff;
        }
    }
};

1

Ein anderer Ansatz wäre zu überprüfen, wann der Benutzer aufgehört hat zu tippen ...

Wenn ein TextEdit im Fokus ist (Benutzer tippt / tippt), können Sie die Ansichten ausblenden (Fokus-Listener).

Verwenden Sie einen Handler + Runnable und einen Textänderungs-Listener, um die Tastatur zu schließen (unabhängig von ihrer Sichtbarkeit) und die Ansichten nach einiger Verzögerung anzuzeigen.

Die Hauptsache, auf die Sie achten sollten, ist die Verzögerung, die Sie verwenden und die vom Inhalt dieser TextEdits abhängt.

Handler timeoutHandler = new Handler();
Runnable typingRunnable = new Runnable() {
    public void run() {
        // current TextEdit
        View view = getCurrentFocus();

        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        // reset focus
        view.clearFocus();
        // close keyboard (whether its open or not)
        imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);

        // SET VIEWS VISIBLE
    }
};

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            // SET VIEWS GONE

            // reset handler
            timeoutHandler.removeCallbacks(typingRunnable);
            timeoutHandler.postDelayed(typingRunnable, TYPING_TIMEOUT);
        }
    }
});

editText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // Reset Handler...
        timeoutHandler.removeCallbacks(typingRunnable);
    }

    @Override
    public void afterTextChanged(Editable s) {
        // Reset Handler Cont.
        if (editText.getText().toString().trim().length() > 0) {
            timeoutHandler.postDelayed(typingRunnable, TYPING_TIMEOUT);
        }
    }
});

1

Dieser Code funktioniert sehr gut

Verwenden Sie diese Klasse für die Stammansicht:

public class KeyboardConstraintLayout extends ConstraintLayout {

private KeyboardListener keyboardListener;
private EditText targetEditText;
private int minKeyboardHeight;
private boolean isShow;

public KeyboardConstraintLayout(Context context) {
    super(context);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); //128dp
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); // 128dp
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); // 128dp
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (!isInEditMode()) {
        Activity activity = (Activity) getContext();
        @SuppressLint("DrawAllocation")
        Rect rect = new Rect();
        getWindowVisibleDisplayFrame(rect);

        int statusBarHeight = rect.top;
        int keyboardHeight = activity.getWindowManager().getDefaultDisplay().getHeight() - (rect.bottom - rect.top) - statusBarHeight;

        if (keyboardListener != null && targetEditText != null && targetEditText.isFocused()) {
            if (keyboardHeight > minKeyboardHeight) {
                if (!isShow) {
                    isShow = true;
                    keyboardListener.onKeyboardVisibility(true);
                }
            }else {
                if (isShow) {
                    isShow = false;
                    keyboardListener.onKeyboardVisibility(false);
                }
            }
        }
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

public boolean isShowKeyboard() {
    return isShow;
}

public void setKeyboardListener(EditText targetEditText, KeyboardListener keyboardListener) {
    this.targetEditText = targetEditText;
    this.keyboardListener = keyboardListener;
}

public interface KeyboardListener {
    void onKeyboardVisibility (boolean isVisible);
}

}}

und setzen Sie den Tastatur-Listener auf Aktivität oder Fragment:

        rootLayout.setKeyboardListener(targetEditText, new KeyboardConstraintLayout.KeyboardListener() {
        @Override
        public void onKeyboardVisibility(boolean isVisible) {

        }
    });


0

Leider habe ich kein ausreichend hohes Ansehen, um die Antwort von Jaap van Hengstum zu kommentieren. Aber ich habe ein paar Kommentare von Leuten gelesen, die das Problem haben, contentViewTopdas immer 0und das istonShowKeyboard(...) immer genannt wird.

Ich hatte das gleiche Problem und fand das Problem heraus, das ich hatte. Ich habe eine AppCompatActivityanstelle einer "normalen" verwendet Activity. In diesem Fall Window.ID_ANDROID_CONTENTbezieht sich auf ein ContentFrameLayoutund nicht auf das FrameLayoutmit dem richtigen Spitzenwert. In meinem Fall war es in Ordnung, den 'normalen' zu verwenden Activity. Wenn Sie einen anderen Aktivitätstyp verwenden müssen (ich habe gerade den getestet AppCompatActivity, vielleicht ist es auch ein Problem mit anderen Aktivitätstypen wie dem FragmentActivity), müssen Sie auf den zugreifen FrameLayout, das heißt ein Vorfahr der ContentFrameLayout.


0

wenn Tastatur zeigen

rootLayout.getHeight() < rootLayout.getRootView().getHeight() - getStatusBarHeight() 

ist wahr, sonst verstecken


0
private boolean isKeyboardShown = false;
private int prevContentHeight = 0;
private ViewGroup contentLayout;

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener =
        new ViewTreeObserver.OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        int contentHeight = contentLayout.getHeight();
        int rootViewHeight = contentLayout.getRootView().getHeight();

        if (contentHeight > 0) {

            if (!isKeyboardShown) {
                if (contentHeight < prevContentHeight) {
                    isKeyboardShown = true;
                    onShowKeyboard(rootViewHeight - contentHeight);
                }
            } else {
                if (contentHeight > prevContentHeight) {
                    isKeyboardShown = false;
                    onHideKeyboard();
                }
            }

            prevContentHeight = contentHeight;
        }
    }
};

Ich habe die akzeptierte Antwort des Jaap ein wenig geändert. In meinem Fall gibt es jedoch nur wenige Annahmen wie: android:windowSoftInputMode=adjustResizeDie Tastatur wird zu Beginn des App-Starts nicht angezeigt. Außerdem gehe ich davon aus, dass der Bildschirm in Bezug auf die Größe der Eltern übereinstimmt.

contentHeight > 0Durch diese Überprüfung kann ich feststellen, ob der betreffende Bildschirm ausgeblendet oder angezeigt wird, um das Abhören von Tastaturereignissen für diesen bestimmten Bildschirm anzuwenden. Außerdem übergebe ich die Layoutansicht des betreffenden Bildschirms in attachKeyboardListeners(<your layout view here>)der onCreate()Methode meiner Hauptaktivität . Jedes Mal, wenn sich die Höhe des betreffenden Bildschirms ändert, speichere ich ihn unterprevContentHeight Variablen, um später zu überprüfen, ob die Tastatur angezeigt oder ausgeblendet wird.

Für mich hat es bisher ziemlich gut geklappt. Ich hoffe, dass es auch für andere funktioniert.


0

Die Antwort von "Jaap van Hengstum" funktioniert für mich, aber es ist nicht nötig, "android: windowSoftInputMode" einzustellen, wie er gerade sagte!

Ich habe es kleiner gemacht (es erkennt jetzt nur, was ich will, eigentlich ein Ereignis beim Ein- und Ausblenden der Tastatur):

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
        int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
        if(heightDiff <= contentViewTop){
            onHideKeyboard();
        } else {
            onShowKeyboard();
        }
    }
};

private boolean keyboardListenersAttached = false;
private ViewGroup rootLayout;

protected void onShowKeyboard() {}
protected void onHideKeyboard() {}

protected void attachKeyboardListeners() {
    if (keyboardListenersAttached) {
        return;
    }

    rootLayout = (ViewGroup) findViewById(R.id.CommentsActivity);
    rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);

    keyboardListenersAttached = true;
}

@Override
protected void onDestroy() {
    super.onDestroy();

    if (keyboardListenersAttached) {
        rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
    }
}

und vergessen Sie einfach nicht, dies hinzuzufügen

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_comments);
    attachKeyboardListeners();}

0

Dies funktioniert, ohne dass Sie Ihre Aktivitäten ändern müssen android:windowSoftInputMode

Schritt 1: Erweitern Sie die EditText-Klasse und überschreiben Sie diese beiden:

@Override
public void setOnEditorActionListener(final OnEditorActionListener listener) {
    mEditorListener = listener;
    super.setOnEditorActionListener(listener);
}

@Override
public boolean onKeyPreIme(final int keyCode, final KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        if (mEditorListener != null) {
            mEditorListener.onEditorAction(this, android.R.id.closeButton, event);
        }
    }
    return super.onKeyPreIme(keyCode, event);
}

Schritt 2: Erstellen Sie diese beiden in Ihrer Aktivität:

private void initKeyboard() {
    final AppEditText editText = findViewById(R.id.some_id);
    editText.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            setKeyboard(hasFocus);
        }
    });
    editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (event == null || event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                editText.clearFocus();
            }
            return false;
        }
    });
}

public void setKeyboard(boolean isShowing) {
    // do something
}

*** clearFocusDenken Sie daran, dass Sie Eltern oder erstes Kind in der Elternhierarchie fokussierbar machen müssen, damit die Arbeit funktioniert.

    setFocusableInTouchMode(true);
    setFocusable(true);

0

Dies funktioniert nicht wie gewünscht ...

... haben viele Größenberechnungen verwendet, um zu überprüfen ...

Ich wollte feststellen, ob es offen war oder nicht und fand es isAcceptingText()

Dies beantwortet die Frage also wirklich nicht, da es sich nicht um das Öffnen oder Schließen handelt, sondern eher um das Öffnen oder Schließen, also um verwandten Code, der anderen in verschiedenen Szenarien helfen kann ...

in einer Aktivität

    if (((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
    } else {
        Log.d(TAG,"Software Keyboard was not shown");
    }

in einem Fragment

    if (((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)).isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
    } else {
        Log.d(TAG,"Software Keyboard was not shown");

    }

0

Überprüfen Sie mit dem folgenden Code:

XML-CODE:

<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorParent"
    style="@style/parentLayoutPaddingStyle"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  .................


</android.support.constraint.ConstraintLayout>

JAVA CODE:

//Global Variable
android.support.constraint.ConstraintLayout activityRootView;
boolean isKeyboardShowing = false;
private  ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener;
android.support.constraint.ConstraintLayout.LayoutParams layoutParams;




 //onCreate or onViewAttached
    activityRootView = view.findViewById(R.id.coordinatorParent);
        onGlobalLayoutListener = onGlobalLayoutListener();
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);


  //outside oncreate
  ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener() {
        return new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                activityRootView.getWindowVisibleDisplayFrame(r);
                int screenHeight = activityRootView.getRootView().getHeight();
                int keypadHeight = screenHeight - r.bottom;

                if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
                    if (!isKeyboardShowing) {  // keyboard is opened
                        isKeyboardShowing = true;
                        onKeyboardVisibilityChanged(true);
                   }
                }
                else {
                    if (isKeyboardShowing) {   // keyboard is closed
                        isKeyboardShowing = false;
                        onKeyboardVisibilityChanged(false);
                    }
                }
            }//ends here
        };

    }


    void onKeyboardVisibilityChanged(boolean value) {
        layoutParams = (android.support.constraint.ConstraintLayout.LayoutParams)topImg.getLayoutParams();

        if(value){
           int length = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90, getResources().getDisplayMetrics());
            layoutParams.height= length;
            layoutParams.width = length;
            topImg.setLayoutParams(layoutParams);
            Log.i("keyboard " ,""+ value);
        }else{
            int length1 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 175, getResources().getDisplayMetrics());
            layoutParams.height= length1;
            layoutParams.width = length1;
            topImg.setLayoutParams(layoutParams);
            Log.i("keyboard " ,""+ value);
        }
    }


    @Override
    public void onDetach() {
        super.onDetach();
        if(onGlobalLayoutListener != null) {
            activityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
        }
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.