Android'de bir etkinlikte yumuşak klavye açık ve kapalı dinleyici


136

Activity5 EditTexts olan bir yerim var . Kullanıcı ilkini tıkladığında, EditTextiçine bir değer girmek için yazılım klavyesi açılır. Yazılım klavyesi açıldığında ve kullanıcı ilk tıklattığında ve yazılım klavyesi arka düğmedeki aynı tuştan kapandığında başka bir Viewgörünürlük ayarlamak istiyorum . Sonra başkalarının görünürlüğünü görünür yapmak istiyorum.GoneEditTextEditTextView

EditTextAndroid'de ilk tıklamayla yumuşak klavye açıldığında herhangi bir dinleyici, geri arama veya herhangi bir kesmek var mı?


1
Hayır. Böyle bir dinleyici yok. Yapmaya çalıştığın şeyleri başarmak için hack'ler var . İşte olası bir yaklaşım: Android'de işaretçi olayı nasıl gönderilir .
Vikram

@Vikram Aramıyorumtrying to detect the virtual keyboard height in Android.
N Sharma

Biliyorum. Koddan geçerseniz, yüksekliğin nasıl belirlendiğini göreceksiniz. Bir işaretçi olay gönderiliyor -> iki durum => 1. Klavye ise açık => & işaretçi en takdirde Xve Ykonumu üzerinde / klavye üzerinde => düşer SecurityException=> eksiltme Yve tekrar deneyin => istisna atılır kadar => geçerli Ydeğer klavye yüksekliğidir. 2. klavye açık değilse => hayır SecurityException.
Vikram

Senaryonuz için nasıl geçerlidir? Ekran yüksekliğinin 2 / 3'üne bir işaretçi etkinliği gönderin. A SecurityExceptionatılırsa => klavye açıktır. Başka, klavye kapalı.
Vikram

@ Vikram Bunu sadece ilk önce EditTextdeğil, diğeri için istiyorum EditText. Bunu nasıl ayırt edebilirim?
N Sharma

Yanıtlar:


91

Bu yalnızca android:windowSoftInputModeetkinliğiniz adjustResizemanifest'te olarak ayarlandığında çalışır . Etkinliğinizin kök düzeninin klavye tarafından yeniden boyutlandırılıp boyutlandırılmadığını görmek için bir düzen dinleyici kullanabilirsiniz.

Etkinliklerim için aşağıdaki temel sınıf gibi bir şey kullanıyorum:

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

Aşağıdaki örnek etkinlik bunu, klavye gösterildiğinde bir görünümü gizlemek ve klavye gizlendiğinde tekrar göstermek için kullanır.

XML düzeni:

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

Ve etkinlik:

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 Evet Bu sorunum için mükemmel bir çözüm.
N Sharma

18
Merhaba, Window.ID_ANDROID_CONTENT üzerinde getTop () kullandınız. Başa dön benim için işe yaramıyor. burada her zaman 0, bunun yerine getHeight () kullanması gerektiği gibi çalışır.
Daniele Segato

1
nerede alabilirim rootLayout = (ViewGroup) findViewById(R.id.rootLayout);dan?
CommonSenseCode

1
Herhangi bir nedenden dolayı benim için çalışmıyor, her zaman açıyorum ya da kapatıyorum. FindViewById (android.R.id.content) kullanıyorum, belki sorun budur?
McSullivan D'Ander

2
@tsig +100 çözümünüz belirli ekrana bağlıdır. Tabletlerde ve hdpi telefonlarda başarısız oldu. Düzeltmeyi cihaz yüksekliğinin yüzde on'u olarak kullandım. Bu, görünüm yüksekliği ekrandan düşükse, yükseklik -% 10 klavye açık demektir. yoksa klavye kapalı. İşte onGlobalLayout'taki contentViewTop'um: contentViewTop = (getWindow (). GetDecorView (). GetBottom () / 10)
ilker

94

Müthiş ile Çantada keklik KeyboardVisibilityEvent kütüphanesinde

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

Yasuhiro SHIMIZU için kredi


Klavyelerin statik yükseklikleri olmadığı ve bu kitaplıktaki yükseklik 100dp olarak ayarlandığı için bu çalışmaz.
milosmlar

@milosmns, klavye algılaması için 100dp'lik bir eşik yüksekliği kullanılır. Gerçek klavye yüksekliği hakkında bir varsayım yok
Nino van Hooff

11
Hala kodlanmış. Çoklu pencere? Samsung bölünmüş görünüm? Resim modunda resim? Ayrıca 100dp'nin altına düşecek minimum tek satırlı bir klavye var. Burada gümüş mermi yok ...
milosmlar

1
Bu sorun için tüm yakalama olmadığı için, bu en kolay uygulama gibi görünüyor ve sadece üzerinde çalışmak istediğiniz koda geri dönün :)
Machine Tribe

1
Bu, en iyi cevaptır, herhangi bir cihazda tamamen güvenilirdir
Pelanes

70

Vikram'ın açıklamalarda belirttiği gibi, ekran klavyesinin gösterilip gösterilmediğini tespit etmek sadece bazı çirkin hack'lerle mümkündür.

Belki de düzenleme metnine bir odak dinleyici ayarlamak yeterlidir :

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

28
düzenleme metnine tıkladığımı varsayalım, o zaman setOnFocusChangeListenerdinleyici çağrılacak, sonra geri basıyorum, sonra klavyeyi kapatıyor ve diğer görünümlere tıklamıyorum, şimdi yine odak olan aynı düzenleme metnine tıklıyorum, sonra ne olacak?
N Sharma

3
@Williams Tamamen emin değilim, ama onFocusChange()bunun çağrılmayacağından şüpheleniyorum .
commonguy

1
bu benim sorum değil. Lütfen sorumu tekrar okuyun - 5 EditText'in olduğu bir etkinliğim var. Kullanıcı ilk EditText'i tıklattığında, içine bir miktar değer girmek için yumuşak klavye açılır. Kullanıcı ilk EditText'i tıklattığında yazılım klavyesi açıldığında ve arka tuşa aynı EditText'ten yazılım klavyesi kapandığında diğer bazı Görünüm görünürlüğünü Git olarak ayarlamak istiyorum, sonra diğer bazı Görünüm görünürlüğünü görünür olarak ayarlamak istiyorum. Android'de ilk EditText'e tıklandığında yumuşak klavye açıldığında herhangi bir dinleyici, geri arama veya herhangi bir kesmek var mı?
N Sharma

4
Çocuklar bu cevaba bakmıyor çünkü anlamıyorum bile farklı bir şey söylüyor.
N Sharma

2
Her neyse, benim için işe yaramaz ... Yazılım klavyesi gizlendiğinde, EditText'te herhangi bir odak değişikliği olmaz ... Bu yüzden bu Dinleyiciden bildirim alamıyorum.
Licat Julius

51

Etkinlik için:

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

Parça için:

    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
Etkinlik için kullanılır, ancak ekran boyutu ile karşılaştırıldığında görünüm i ile karşılaştırmak yerine kullanılır. harika çalışıyor
Roee

heightDiff'i piksel yerine dp cinsinden bir yükseklik ile karşılaştırmak daha iyidir. Önemli ölçüde değişebilir.
Leo Droidcoder

Bunun android:windowSoftInputMode="adjustResize"manifest'e ihtiyacı var mı ?
LiuWenbin_NO.

android: windowSoftInputMode = "adjustResize" android: configChanges = "yönlendirme | klavye | keyboardHidden"
M Singh Karnawat

Benim için çalışıyor, yine de bir sorum var. Çok fazla kaynak maliyeti var mı?
Licat Julius

32

Jaap'ın yanıtı AppCompatActivity için çalışmaz. Bunun yerine Durum Çubuğu ve Gezinme çubuğu vb. Yüksekliklerini alın ve uygulamanızın pencere boyutuyla karşılaştırın.

Bunun gibi:

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

Bir istisna dışında oldukça iyi çalışıyor gibi görünüyor: bölünmüş ekran modunda molalar. Aksi takdirde harika.
MCLLC

14

Deneyebilirsin:

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

Rx uzatma işlevimi (Kotlin) kullanabilirsiniz.

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

Misal:

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

Benim için çalışmıyor. Yöntemleri bulamıyorum dip()vegetScreenHeight()
Marcin Kunert

@MarcinKunert, pikselleri dp'ye dönüştürmenize ve ekran yüksekliğini almanıza yardımcı olan sadece uzantı işlevidir. İsterseniz, bu tür işlevlere örnek verebilirim
Vlad

GenericLifecycleObserver kullanımdan kaldırıldı mı? herhangi bir çözüm?
Zainal Fahrudin

4

Aşağıdaki kod benim için çalışıyor,

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

Yapabiliyorsanız, EditText'i genişletmeyi ve 'onKeyPreIme' yöntemini geçersiz kılmayı deneyin.

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

Nasıl uzatabilirsiniz:

  1. Netleme dinlemeyi uygulayın ve 'onKeyboardShown' ilan edin
  2. 'onKeyboardHidden' bildir

Ekran yüksekliğinin yeniden hesaplanmasının daha önce belirtildiği gibi% 100 başarılı olmadığını düşünüyorum. Açık olmak gerekirse, 'onKeyPreIme' 'in geçersiz kılınması' yumuşak klavyeyi programlı olarak gizle 'yöntemlerinde çağrılmaz, ancak herhangi bir yerde yapıyorsanız, orada' onKeyboardHidden 'mantığını yapmalı ve kapsamlı bir çözüm oluşturmamalısınız.


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

düzenleme metnine tıkladığımı varsayalım, o zaman setOnFocusChangeListenerdinleyici çağrılacak, sonra geri basıyorum, sonra klavyeyi kapatıyor ve diğer görünümlere tıklamıyorum, şimdi yine odak olan aynı düzenleme metnine tıklıyorum, sonra ne olacak?
N Sharma

bu benim sorum değil. Lütfen sorumu tekrar okuyun - 5 EditText'in olduğu bir etkinliğim var. Kullanıcı ilk EditText'i tıklattığında, içine bir değer girmek için yumuşak klavye açılır. Kullanıcı ilk EditText'i tıklattığında yazılım klavyesi açıldığında ve arka tuşa aynı EditText'ten yazılım klavyesi kapandığında diğer bazı Görünüm görünürlüğünü Git olarak ayarlamak istiyorum, sonra diğer bazı Görünüm görünürlüğünü görünür olarak ayarlamak istiyorum. Android'de ilk EditText'e tıklandığında yumuşak klavye açıldığında herhangi bir dinleyici, geri arama veya herhangi bir kesmek var mı?
N Sharma

1
Geri bastığınızda o zaman o Klavyeyi kapatmak onfocusdinleyici ı değil arıyorum öneriyorsun hangi olduğundan hiç aramıyorsun
N Sharma

1

Bu sınıfı kullanın,

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"gereklidir.

/*
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 - Tamamen buradan alınır .


1

Davası için adjustResize @Jaap gelen ve FragmentActivity kabul çözümü benim için çalış yapmaz.

İşte benim çözümüm:

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

Farklı bir yaklaşım, kullanıcının yazmayı ne zaman bıraktığını kontrol etmektir ...

Bir TextEdit odakta olduğunda (kullanıcı yazıyor / yazıyordu) görünümleri gizleyebilirsiniz (odak dinleyicisi)

ve klavyeyi kapatmak için (görünürlüğünden bağımsız olarak) bir Handler + Runnable ve bir metin değiştirme dinleyicisi kullanın ve bir süre sonra görünümleri gösterin.

Dikkat edilmesi gereken en önemli şey, bu TextEdits içeriğine bağlı olarak kullandığınız gecikmedir.

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

Bu kod harika çalışıyor

kök görünüm için bu sınıfı kullanın:

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

}

ve klavye dinleyicisini etkinlik veya parça olarak ayarlayın:

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

        }
    });


0

Ne yazık ki Jaap van Hengstum'un cevabı hakkında yorum yapmak için yeterince yüksek bir itibarım yok. Ama insanların birkaç yorumu okudum contentViewTop, her zaman sorun olan 0veonShowKeyboard(...) her zaman denilen .

Aynı sorunu yaşadım ve yaşadığım sorunu çözdüm. Bir kullanılan AppCompatActivity'normal' yerine Activity. Bu durumda , doğru en yüksek değere sahip olan ve değil Window.ID_ANDROID_CONTENTanlamına gelir . Benim durumumda 'normal' kullanmak iyiydi , eğer başka bir aktivite türü kullanmak zorundaysanız (sadece test ettim , belki de bu gibi diğer aktivitelerle ilgili bir sorun ), erişmek zorundasınız , atası .ContentFrameLayoutFrameLayoutActivityAppCompatActivityFragmentActivityFrameLayoutContentFrameLayout


0

klavye gösterisi ne zaman

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

doğrudur, başka saklan


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

Jaap'ın kabul edilen cevabını biraz değiştirdim. Ama benim durumumda, gibi birkaç varsayım var android:windowSoftInputMode=adjustResizeve uygulama başladığında klavye başlangıçta görünmüyor. Ve ayrıca, ekranın ebeveynin yüksekliğiyle eşleştiğini varsayıyorum.

contentHeight > 0bu kontrol, ilgili ekranın gizli olup olmadığını veya bu belirli ekran için klavye olayı dinlemeyi uygulamak için gösterilip gösterilmediğini bilmemi sağlar. Ayrıca, ilgili ekranın düzen görünümünü attachKeyboardListeners(<your layout view here>)ana faaliyetimin onCreate()yönteminde geçiriyorum. İlgili ekranın yüksekliği her değiştiğindeprevContentHeight daha sonra klavyenin gösterilip gösterilmeyeceğini veya gizlenip gizlenmediğini kontrol etmek değişkene .

Benim için şimdiye kadar oldukça iyi çalıştı. Umarım başkaları için de çalışır.


0

"Jaap van Hengstum" 'un cevabı benim için çalışıyor, ama sadece "android: windowSoftInputMode" ayarlamasına gerek yok!

Daha küçük yaptım (şimdi sadece istediğimi algılıyor, aslında klavyenin gösterilmesi ve gizlenmesi ile ilgili bir olay):

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

ve bunu eklemeyi unutma

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

0

Bu, etkinliklerinizi değiştirmeye gerek kalmadan çalışacaktır android:windowSoftInputMode

1. adım: EditText sınıfını genişletin ve şu ikisini geçersiz kılın:

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

2. adım: Bu ikisini etkinliğinizde oluşturun:

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
}

*** clearFocusİş yapabilmek için ebeveyn hiyerarşisindeki ebeveyn veya ilk çocuğu odaklanabilir yapmanız gerektiğini unutmayın .

    setFocusableInTouchMode(true);
    setFocusable(true);

0

Bu istediğiniz gibi çalışmıyor ...

... kontrol etmek için birçok kullanım boyutu hesaplaması gördük ...

Açık olup olmadığını belirlemek istedim ve buldum isAcceptingText()

bu yüzden bu soruya cevap vermiyor çünkü açık veya kapalı gibi daha çok açılma veya kapanmaya değinmiyor, bu yüzden çeşitli senaryolarda başkalarına yardımcı olabilecek ilgili kod ...

bir aktivitede

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

bir parça halinde

    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

aşağıdaki kodla kontrol edin:

XML KODU:

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

//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);
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.