Keyboard lembut membuka dan menutup pendengar dalam suatu aktivitas di Android


141

Saya memiliki di Activitymana ada 5 EditTexts. Ketika pengguna mengklik yang pertama EditText, keyboard lunak terbuka untuk memasukkan beberapa nilai di dalamnya. Saya ingin mengatur Viewvisibilitas orang lain ke Gonesaat soft keyboard terbuka dan juga saat pengguna mengklik yang pertama EditTextdan juga saat soft keyboard menutup dari yang sama EditTextsaat tombol kembali ditekan. Kemudian saya ingin mengatur Viewvisibilitas orang lain menjadi terlihat.

Apakah ada pendengar atau panggilan balik atau peretasan apa pun ketika keyboard lunak terbuka dari klik pertama EditTextdi Android?


1
Tidak. Tidak ada pendengar seperti itu. Ada yang hacks untuk mencapai apa yang Anda coba untuk. Berikut adalah pendekatan yang mungkin: Cara mengirimkan peristiwa pointer di Android .
Vikram

@Vikram Saya tidak mencaritrying to detect the virtual keyboard height in Android.
N Sharma

Aku tahu. Jika Anda melihat kode, Anda akan melihat bagaimana ketinggian ditentukan. Peristiwa pointer sedang dikirim -> dua kasus => 1. jika keyboard terbuka => & jika pointer Xdan Ylokasi jatuh pada / di atas keyboard => SecurityException=> decrement Ydan coba lagi => sampai tidak ada pengecualian yang dilemparkan => Ynilai saat ini adalah ketinggian keyboard. 2. jika keyboard tidak terbuka => no SecurityException.
Vikram

Bagaimana ini berlaku untuk skenario Anda? Kirim peristiwa penunjuk pada katakanlah 2/3 dari tinggi layar. Jika a SecurityExceptiondilempar => keyboard terbuka. Jika tidak, keyboard ditutup.
Vikram

@Vikram Saya hanya ingin ini pertama EditTextbukan yang lain EditText. Bagaimana saya bisa membedakan ini?
N Sharma

Jawaban:


90

Ini hanya berfungsi jika android:windowSoftInputModeaktivitas Anda disetel ke adjustResizedalam manifes. Anda bisa menggunakan pendengar tata letak untuk melihat apakah tata letak akar aktivitas Anda diubah ukurannya oleh keyboard.

Saya menggunakan sesuatu seperti kelas dasar berikut untuk aktivitas saya:

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);
        }
    }
}

Contoh aktivitas berikut menggunakan ini untuk menyembunyikan tampilan saat keyboard ditampilkan dan menampilkannya lagi saat keyboard disembunyikan.

Tata letak xml:

<?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>

Dan aktivitasnya:

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 Ya Ini adalah solusi sempurna untuk masalah saya.
N Sharma

20
Hai, Anda menggunakan getTop () di Window.ID_ANDROID_CONTENT. Dapatkan atas tidak berhasil untuk saya. selalu 0 di sini, berfungsi seperti seharusnya menggunakan getHeight () sebagai gantinya.
Daniele Segato

1
mana Anda mendapatkan rootLayout = (ViewGroup) findViewById(R.id.rootLayout);dari?
CommonSenseCode

1
Tidak bekerja untuk saya karena suatu alasan, itu selalu memanggil onShowKeyboard baik saya membukanya atau menutupnya. Saya menggunakan findViewById (android.R.id.content), mungkin itu masalahnya?
McSullivan D'Ander

3
@tsig solusi +100 Anda bergantung pada layar tertentu. Gagal di tablet dan ponsel hdpi. Saya menggunakan koreksi sebagai sepuluh persen dari tinggi perangkat. Artinya jika ketinggian tampilan lebih rendah dari screenHeight - 10% keyboard terbuka. kalau tidak, keyboard ditutup. Ini contentViewTop saya di onGlobalLayout: contentViewTop = (getWindow (). GetDecorView (). GetBottom () / 10)
ilker

100

Sepotong kue dengan perpustakaan KeyboardVisibilityEvent yang mengagumkan

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

Penghargaan untuk Yasuhiro SHIMIZU


1
Ini tidak akan berfungsi karena keyboard tidak memiliki ketinggian statis, dan tinggi di perpustakaan ini disetel ke 100dp.
milosmns

12
Ini masih sulit dikodekan. Multi jendela? Samsung split view? Gambar dalam mode gambar? Juga ada keyboard satu baris minimal yang akan jatuh di bawah 100dp. Tidak ada peluru perak di sini ...
milosmns

1
Karena tidak ada batasan semua untuk masalah ini, ini tampaknya yang paling mudah diterapkan dan cukup kembali ke kode yang sebenarnya ingin Anda kerjakan :)
Machine Tribe

1
Sejauh ini, ini adalah jawaban terbaik, benar-benar dapat diandalkan pada perangkat apa pun
Pelanes

1
@TimCastelijns menurut pengalaman saya, saya sudah mencoba beberapa variasi dan ini yang bekerja lebih baik di sebagian besar perangkat. Mungkin tidak sempurna, tetapi saya mengalami banyak masalah dengan fitur ini di Nexus 5X dan perangkat Nexus lainnya, dan ini bekerja dengan sempurna.
Pelanes

70

Seperti yang ditunjukkan Vikram di komentar, mendeteksi apakah softkeyboard ditampilkan atau telah menghilang hanya mungkin dilakukan dengan beberapa peretasan yang buruk.

Mungkin cukup dengan menetapkan pendengar fokus pada teks editan :

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

32
misalkan saya klik edittext maka setOnFocusChangeListenerlistener akan dipanggil lalu saya tekan kembali lalu tutup keyboard & tapi tidak klik view lain, sekarang lagi saya klik edittext yang sama yang sudah fokus lalu apa yang akan terjadi?
N Sharma

3
@Williams Saya tidak sepenuhnya yakin, tapi saya curiga itu onFocusChange()tidak akan dipanggil.
Manuel Allenspach

1
ini bukan pertanyaanku. Silakan baca pertanyaan saya lagi - Saya memiliki Aktivitas di mana ada 5 EditText. Ketika pengguna mengklik EditText pertama kemudian keyboard lunak terbuka untuk memasukkan beberapa nilai di dalamnya. Saya ingin mengatur beberapa View visibility lainnya ke Gone ketika soft keyboard terbuka ketika pengguna mengklik EditText pertama dan ketika soft keyboard menutup dari EditText yang sama pada back press maka saya ingin mengatur visibilitas View lainnya menjadi terlihat. Apakah ada pendengar atau panggilan balik atau peretasan apa pun ketika keyboard lunak terbuka saat diklik EditText pertama di Android?
N Sharma

4
Cowok tidak melihat jawaban ini karena dia mengatakan sesuatu yang berbeda bahkan saya tidak mengerti.
N Sharma

2
Bagaimanapun, Ini tidak berhasil untuk saya ... Saat soft keyboard disembunyikan, Tidak ada perubahan fokus apa pun yang terjadi pada EditText ... Jadi saya tidak bisa mendapatkan pemberitahuan dari Pendengar ini.
Licat Julius

52

Untuk Aktivitas:

    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
                }
            }
        });

Untuk Fragmen:

    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
Digunakan untuk aktivitas, tetapi bukannya membandingkan dengan tampilan saya dibandingkan dengan ukuran layar. bekerja dengan baik
Roee

lebih baik membandingkan heightDiff dengan tinggi dalam dp daripada dalam piksel. Itu bisa sangat bervariasi.
Leo Droidcoder

Apakah ini perlu android:windowSoftInputMode="adjustResize"dimanifestasikan?
LiuWenbin_NO.

android: windowSoftInputMode = "adjustResize" android: configChanges = "orientasi | keyboard | keyboardHidden"
M Singh Karnawat

Ini berhasil untuk saya, tetap saja, saya punya pertanyaan. Apakah membutuhkan banyak sumber daya?
Licat Julius

34

Jawaban Jaap tidak akan berfungsi untuk AppCompatActivity. Alih-alih, dapatkan tinggi Status Bar dan bilah Navigasi, dll. Dan bandingkan dengan ukuran jendela aplikasi Anda.

Seperti:

    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);
        }
    }
};

Tampaknya berfungsi cukup baik dengan satu pengecualian: jeda dalam mode layar terbagi. Kalau tidak, itu bagus.
MCLLC

17

Kamu bisa mencobanya:

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;
        }
    });
}

1
Spasibo, Dolbik! :)
AlexS

5

Kode di bawah ini berfungsi untuk saya,

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
                }
            }
        }
    });

Apa itu mainLayout? Dan heightDiff selalu 0 saat teks mengajukan bagian atas tampilan.
Md Imran Choudhury

4

Anda dapat menggunakan fungsi ekstensi Rx saya (Kotlin).

/**
 * @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()
}

Contoh:

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

Tidak berhasil untuk saya. Tidak dapat menemukan metode dip()dangetScreenHeight()
Marcin Kunert

@MarcinKunert itu hanya fungsi ekstensi yang membantu Anda mengubah piksel menjadi dp, dan mendapatkan tinggi layar. Jika Anda mau, saya dapat memberikan contoh fungsi tersebut
Vlad

GenericLifecycleObserver tidak digunakan lagi? ada solusi?
Zainal Fahrudin

2

Jika Anda bisa, coba untuk memperluas EditText dan mengganti metode 'onKeyPreIme'.

@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);
}

Bagaimana Anda bisa memperpanjangnya:

  1. Menerapkan mendengarkan onFocus dan mendeklarasikan 'onKeyboardShown'
  2. nyatakan 'onKeyboardHidden'

Menurut saya, penghitungan ulang ketinggian layar tidak 100% berhasil seperti yang disebutkan sebelumnya. Agar jelas, menimpa 'onKeyPreIme' tidak dipanggil pada metode 'sembunyikan keyboard lunak secara terprogram', TETAPI jika Anda melakukannya di mana saja, Anda harus melakukan logika 'onKeyboardHidden' di sana dan tidak membuat solusi yang komprehensif.


2

Ini akan bekerja tanpa perlu mengubah aktivitas Anda android:windowSoftInputMode

langkah 1: perluas kelas EditText dan timpa keduanya:

@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);
}

langkah 2: buat keduanya dalam aktivitas Anda:

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
}

*** Ingat untuk membuat clearFocuspekerjaan, Anda harus membuat orang tua atau anak pertama dalam hierarki induk dapat difokuskan.

    setFocusableInTouchMode(true);
    setFocusable(true);

Buat editText kustom adalah solusi paling sederhana!
Kebab Krabby

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);
            }
       }
    });
    }
}

misalkan saya klik edittext maka setOnFocusChangeListenerlistener akan dipanggil lalu saya tekan kembali lalu tutup keyboard & tapi tidak klik view lain, sekarang lagi saya klik edittext yang sama yang sudah fokus lalu apa yang akan terjadi?
N Sharma

ini bukan pertanyaanku. Silakan baca pertanyaan saya lagi - Saya memiliki Aktivitas di mana ada 5 EditText. Ketika pengguna mengklik EditText pertama kemudian keyboard lunak terbuka untuk memasukkan beberapa nilai di dalamnya. Saya ingin mengatur beberapa View visibility lainnya ke Gone ketika soft keyboard terbuka ketika pengguna mengklik EditText pertama dan ketika soft keyboard menutup dari EditText yang sama pada back press maka saya ingin mengatur visibilitas View lainnya menjadi terlihat. Apakah ada pendengar atau panggilan balik atau peretasan apa pun ketika keyboard lunak terbuka saat diklik EditText pertama di Android?
N Sharma

1
Ketika Anda menekan kembali maka itu menutup keyboard bahwa onfocuspendengar waktu tidak pernah memanggil itu Saya tidak melihat yang Anda sarankan
N Sharma

1

Gunakan kelas ini,

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();
        }
    }

}
}

Di Android Manifest, android:windowSoftInputMode="adjustResize"perlu.

/*
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 - Sepenuhnya diambil dari sini .


1

Untuk kasus adjustResizedan FragmentActivity, solusi yang diterima dari @Jaap tidak berfungsi untuk saya.

Inilah solusi saya:

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

Pendekatan yang berbeda adalah memeriksa ketika pengguna berhenti mengetik ...

Saat TextEdit berada dalam fokus (pengguna sedang / sedang mengetik) Anda dapat menyembunyikan tampilan (pendengar fokus)

dan gunakan Handler + Runnable dan pemroses perubahan teks untuk menutup keyboard (terlepas dari visibilitasnya) dan menampilkan tampilan setelah beberapa penundaan.

Hal utama yang harus diperhatikan adalah penundaan yang Anda gunakan, yang akan bergantung pada konten TextEdits ini.

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

Kode ini bekerja dengan sangat baik

gunakan kelas ini untuk tampilan root:

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);
}

}

dan setel pendengar keyboard dalam aktivitas atau fragmen:

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

        }
    });


0

Sayangnya saya tidak memiliki reputasi yang cukup tinggi untuk mengomentari jawaban Jaap van Hengstum. Tetapi saya membaca beberapa komentar orang, memiliki masalah yang contentViewTopselalu 0dan yang onShowKeyboard(...)selalu disebut.

Saya memiliki masalah yang sama dan menemukan masalah yang saya alami. Saya menggunakan AppCompatActivitybukan 'normal' Activity. Dalam hal ini Window.ID_ANDROID_CONTENTmengacu pada ContentFrameLayoutdan bukan ke FrameLayoutdengan nilai atas kanan. Dalam kasus saya, tidak masalah menggunakan 'normal' Activity, jika Anda harus menggunakan jenis aktivitas lain (saya baru saja menguji AppCompatActivity, mungkin ini juga merupakan masalah dengan jenis aktivitas lain seperti FragmentActivity), Anda harus mengakses FrameLayout, yaitu nenek moyang dari ContentFrameLayout.


0

saat keyboard ditampilkan

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

benar, kalau tidak sembunyikan


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;
        }
    }
};

Saya telah mengubah sedikit jawaban yang diterima Jaap. Namun dalam kasus saya, ada beberapa asumsi seperti android:windowSoftInputMode=adjustResizedan keyboard tidak muncul di awal saat aplikasi dimulai. Dan juga, saya berasumsi bahwa layar tersebut sesuai dengan tinggi induknya.

contentHeight > 0Pemeriksaan ini memberi saya tahu apakah layar terkait disembunyikan atau ditampilkan untuk menerapkan acara keyboard yang mendengarkan untuk layar khusus ini. Saya juga meneruskan tampilan tata letak layar terkait dalam metode attachKeyboardListeners(<your layout view here>)aktivitas utama saya onCreate(). Setiap kali ketinggian layar berubah, saya menyimpannya ke prevContentHeightvariabel untuk memeriksa nanti apakah keyboard ditampilkan atau disembunyikan.

Bagi saya, sejauh ini sudah berhasil dengan baik. Saya berharap ini juga berhasil untuk orang lain.


0

Jawaban "Jaap van Hengstum" berfungsi untuk saya, tetapi tidak perlu menyetel "android: windowSoftInputMode" seperti yang baru saja dia katakan!

Saya telah membuatnya lebih kecil (sekarang hanya mendeteksi apa yang saya inginkan, sebenarnya sebuah peristiwa yang menunjukkan dan menyembunyikan keyboard):

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);
    }
}

dan jangan lupa untuk menambahkan ini

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

0

Ini tidak berfungsi seperti yang diinginkan ...

... telah melihat banyak menggunakan perhitungan ukuran untuk memeriksa ...

Saya ingin menentukan apakah itu terbuka atau tidak dan saya menemukannya isAcceptingText()

jadi ini benar-benar tidak menjawab pertanyaan karena tidak membahas pembukaan atau penutupan melainkan lebih seperti buka atau tutup jadi ini adalah kode terkait yang dapat membantu orang lain dalam berbagai skenario ...

dalam suatu aktivitas

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

dalam sebuah fragmen

    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

periksa dengan kode di bawah ini:

KODE XML:

<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>

KODE JAWA:

//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);
        }
    }

0

Saya terlambat tetapi saya baru saja menemukan ketergantungan yang sangat nyaman di luar sana. Dengan menggunakannya, Anda dapat memeriksa visibilitas keyboard serta membuat keyboard "Sembunyikan" dan Tampilkan Kapanpun yang Anda inginkan dengan satu Baris Kode.

implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:3.0.0-RC2'

Dan kemudian Anda cukup menggunakan segmen kode ini untuk memeriksa visibilitas keyboard.

KeyboardVisibilityEvent.setEventListener(this, new KeyboardVisibilityEventListener() {
        
@Override
  public void onVisibilityChanged(boolean isOpen) {

if (isOpen) 
  Toast.makeText(MainActivity.this, "keyboard opened",Toast.LENGTH_SHORT).show();
else 
  Toast.makeText(MainActivity.this, "keyboard hidden", Toast.LENGTH_SHORT).show();
}
});

Kemudian jika Anda ingin Sembunyikan / Tampilkan keyboard kapan saja, Anda cukup menulis salah satu baris ini untuk mencapainya.

        UIUtil.showKeyboard(this,edittext_to_be_focused);
        UIUtil.hideKeyboard(this);

0

Ada pendengar keyboard yang ditutup.
Kelas SearchEditTextditurunkan dari android.widget.EditTextkelas. Ada antarmuka SearchEditText.OnKeyboardDismissListenerdi kelas ini. Anda dapat melihat dokumentasi:
https://developer.android.com/reference/androidx/leanback/widget/SearchEditText

Catatan. Sebelum menggunakan SearchEditText, Anda perlu menyiapkan dependensi Gradle di build.gradle (: app):

implementation 'androidx.leanback:leanback:1.1.0-alpha05'

Mungkin seseorang akan berguna.

Tanggapan rinci:

import androidx.appcompat.app.AppCompatActivity;
import androidx.leanback.widget.SearchEditText;

import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
        implements SearchEditText.OnKeyboardDismissListener {

    SearchEditText searchEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        searchEditText = findViewById(R.id.search_edit_text);

        searchEditText.setOnKeyboardDismissListener(this);
    }

    /**
     * Method invoked when the keyboard is dismissed.
     */
    @Override
    public void onKeyboardDismiss() {
        Toast.makeText(this, "The listener worked", Toast.LENGTH_LONG).show();
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.leanback.widget.SearchEditText
        android:id="@+id/search_edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:textSize="20sp"
        android:focusableInTouchMode="true"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Catatan: pendengar bekerja dengan:

android:windowSoftInputMode="adjustPan"
android:windowSoftInputMode="adjustResize"

Saya mengimplementasikan ini pada MainActivity dan hanya ada satu editText di UI, tetapi tidak dipanggil saat penutupan keyboard.
Asad Mukhtar

@AsadMukhtar Hai, lihat tanggapan mendetail saya di atas. Semoga membantu.
Kasus Justin
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.