-
-
Save felHR85/6070f643d25f5a0b3674 to your computer and use it in GitHub Desktop.
/* | |
* Author: Felipe Herranz (felhr85@gmail.com) | |
* Contributors:Francesco Verheye (verheye.francesco@gmail.com) | |
* Israel Dominguez (dominguez.israel@gmail.com) | |
*/ | |
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(); | |
} | |
} | |
} | |
} |
/* | |
* Android Manifest: android:windowSoftInputMode="adjustResize" | |
*/ | |
/* | |
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(); | |
} |
This does not work properly with fragments. Keyboard show method is being called but the Hide method is not being called. For Activity it is working fine.
@arshu-dev did you finally get the solution?
It works. Thank you! 💯
I have edittext in listview items .After back press when one item's edittext has focus and keypad is open ,method hidekeypad is not calling.
This class I want to use in listview but it is not working pls help for same
Here is Kotlin friendly change :)
https://gist.github.com/stasbar/095cb359846c225156fb15b3cc1eed86
Your code was not worked for me :'(
SoftKeyboard.SoftKeyboardChanged()
this method wasn't called ??
I use redmi note 4x, API 24
Guys it doen't work don't spent time on that
thank you very much.
Is there a Kotlin version of this?
thank you very much. it resolved my hard issues.