Czy w Androidzie jest sposób na wykrycie, czy klawiatura programowa (inaczej „miękka”) jest widoczna na ekranie?
Czy w Androidzie jest sposób na wykrycie, czy klawiatura programowa (inaczej „miękka”) jest widoczna na ekranie?
Odpowiedzi:
Nie ma bezpośredniego sposobu - patrz http://groups.google.com/group/android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898a, gdzie odpowiedziała Dianne Hackborn z zespołu Android. Można go jednak wykryć pośrednio, sprawdzając, czy rozmiar okna zmienił się w #onMeasure. Zobacz Jak sprawdzić widoczność klawiatury oprogramowania w systemie Android? .
To działa dla mnie. Może to zawsze najlepszy sposób dla wszystkich wersji .
Skuteczne byłoby uczynienie właściwości widoczności klawiatury i obserwowanie tych zmian z opóźnieniem, ponieważ metoda onGlobalLayout wywołuje wiele razy. Dobrze jest również sprawdzić obrót urządzenia i windowSoftInputMode
tak nie jest adjustNothing
.
boolean isKeyboardShowing = false;
void onKeyboardVisibilityChanged(boolean opened) {
print("keyboard " + opened);
}
// ContentView is the root view of the layout of this activity/fragment
contentView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
contentView.getWindowVisibleDisplayFrame(r);
int screenHeight = contentView.getRootView().getHeight();
// r.bottom is the position above soft keypad or device button.
// if keypad is shown, the r.bottom is smaller than that before.
int keypadHeight = screenHeight - r.bottom;
Log.d(TAG, "keypadHeight = " + keypadHeight);
if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
// keyboard is opened
if (!isKeyboardShowing) {
isKeyboardShowing = true
onKeyboardVisibilityChanged(true)
}
}
else {
// keyboard is closed
if (isKeyboardShowing) {
isKeyboardShowing = false
onKeyboardVisibilityChanged(false)
}
}
}
});
contentView
zadeklarowane?
Spróbuj tego:
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
writeToLog("Software Keyboard was shown");
} else {
writeToLog("Software Keyboard was not shown");
}
Stworzyłem prostą klasę, której można użyć do tego: https://github.com/ravindu1024/android-keyboardlistener . Po prostu skopiuj go do swojego projektu i użyj:
KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
{
@Override
public void onToggleSoftKeyboard(boolean isVisible)
{
Log.d("keyboard", "keyboard visible: "+isVisible);
}
});
rootView
jest tylko widokiem wskazującym mój widok główny w tym przypadku relative layout
:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/addresses_confirm_root_view"
android:background="@color/WHITE_CLR">
RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view);
getViewTreeObserver()
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();
if (heightDiff > 100) {
Log.e("MyActivity", "keyboard opened");
} else {
Log.e("MyActivity", "keyboard closed");
}
}
});
1
. Bez znaczenia. Tylko to musi być mniejsza niż rzeczywista długość klawiatury
Użyłem tego jako podstawy: http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android
/**
* To capture the result of IMM hide/show soft keyboard
*/
public class IMMResult extends ResultReceiver {
public int result = -1;
public IMMResult() {
super(null);
}
@Override
public void onReceiveResult(int r, Bundle data) {
result = r;
}
// poll result value for up to 500 milliseconds
public int getResult() {
try {
int sleep = 0;
while (result == -1 && sleep < 500) {
Thread.sleep(100);
sleep += 100;
}
} catch (InterruptedException e) {
Log.e("IMMResult", e.getMessage());
}
return result;
}
}
Następnie napisał tę metodę:
public boolean isSoftKeyboardShown(InputMethodManager imm, View v) {
IMMResult result = new IMMResult();
int res;
imm.showSoftInput(v, 0, result);
// if keyboard doesn't change, handle the keypress
res = result.getResult();
if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN ||
res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) {
return true;
}
else
return false;
}
Następnie możesz użyć tego do przetestowania wszystkich pól (EditText, AutoCompleteTextView itp.), Które mogły otworzyć klawiaturę programową:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if(isSoftKeyboardShown(imm, editText1) | isSoftKeyboardShown(imm, autocompletetextview1))
//close the softkeyboard
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
Wprawdzie nie jest to idealne rozwiązanie, ale wykonuje zadanie.
Możesz użyć wyniku wywołania zwrotnego programów showSoftInput () i hideSoftInput (), aby sprawdzić status klawiatury. Pełne szczegóły i przykładowy kod na
http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android
Możesz odnieść się do tej odpowiedzi - https://stackoverflow.com/a/24105062/3629912
To działało dla mnie za każdym razem.
adb shell dumpsys window InputMethod | grep "mHasSurface"
Zwróci wartość true, jeśli klawiatura oprogramowania jest widoczna.
Więc po długim czasie zabawy z usługami AccessibilityServices, wstawkami okien, wykrywaniem wysokości ekranu itp., Myślę, że znalazłem sposób, aby to zrobić.
Oświadczenie: używa ukrytej metody w Androidzie, co oznacza, że może nie być spójna. Jednak w moich testach wydaje się, że działa.
Metodą jest InputMethodManager # getInputMethodWindowVisibleHeight () i istnieje od wersji Lollipop (5.0).
Wywołanie, które zwraca wysokość bieżącej klawiatury (w pikselach). Teoretycznie klawiatura nie powinna mieć 0 pikseli wysokości, więc wykonałem prostą kontrolę wysokości (w Kotlinie):
val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
//keyboard is shown
else {
//keyboard is hidden
}
Używam Android Hidden API, aby uniknąć odbicia, gdy wywołuję metody ukryte (robię to dużo dla aplikacji, które opracowuję, które są w większości aplikacjami typu hacky / tuner), ale powinno to być możliwe również z odbiciem:
val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
val windowHeightMethod = InputMethodManager::class.java.getMethod("getInputMethodWindowVisibleHeight")
val height = windowHeightMethod.invoke(imm) as Int
//use the height val in your logic
Było to o wiele mniej skomplikowane dla potrzeb, których potrzebowałem. Mam nadzieję, że to może pomóc:
Na MainActivity:
public void dismissKeyboard(){
InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
mKeyboardStatus = false;
}
public void showKeyboard(){
InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
mKeyboardStatus = true;
}
private boolean isKeyboardActive(){
return mKeyboardStatus;
}
Domyślna pierwotna wartość logiczna dla mKeyboardStatus zostanie zainicjowana na false .
Następnie sprawdź wartość w następujący sposób i w razie potrzeby wykonaj akcję:
mSearchBox.requestFocus();
if(!isKeyboardActive()){
showKeyboard();
}else{
dismissKeyboard();
}
Powinno to działać, jeśli chcesz sprawdzić stan klawiatury:
fun Activity.isKeyboardOpened(): Boolean {
val r = Rect()
val activityRoot = getActivityRoot()
val visibleThreshold = dip(UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP)
activityRoot.getWindowVisibleDisplayFrame(r)
val heightDiff = activityRoot.rootView.height - r.height()
return heightDiff > visibleThreshold;
}
fun Activity.getActivityRoot(): View {
return (findViewById<ViewGroup>(android.R.id.content)).getChildAt(0);
}
Gdzie UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP
= 100, a dip () to funkcja anko, która konwertuje dpToPx:
fun dip(value: Int): Int {
return (value * Resources.getSystem().displayMetrics.density).toInt()
}
Zrobiłem to, ustawiając GlobalLayoutListener w następujący sposób:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightView = activityRootView.getHeight();
int widthView = activityRootView.getWidth();
if (1.0 * widthView / heightView > 3) {
//Make changes for Keyboard not visible
} else {
//Make changes for keyboard visible
}
}
});
Wypróbuj ten kod, który naprawdę działa, jeśli wyświetlona zostanie opcja KeyboardShown, a następnie ta funkcja zwróci prawdziwą wartość ....
private final String TAG = "TextEditor";
private TextView mTextEditor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
mTextEditor = (TextView) findViewById(R.id.text_editor);
mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
isKeyboardShown(mTextEditor.getRootView());
}
});
}
private boolean isKeyboardShown(View rootView) {
/* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
/* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
int heightDiff = rootView.getBottom() - r.bottom;
/* Threshold size: dp to pixels, multiply with display density */
boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;
Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
+ "root view height:" + rootView.getHeight() + ", rect:" + r);
return isKeyboardShown;
}
W moim przypadku miałem tylko jeden EditText
układ do zarządzania, więc wymyśliłem to rozwiązanie. Działa dobrze, w zasadzie jest to zwyczaj, EditText
który nasłuchuje fokusu i wysyła transmisję lokalną, jeśli fokus zmieni się lub jeśli zostanie naciśnięty przycisk Wstecz / Gotowe. Aby pracować, musisz umieścić manekina View
w swoim układzie za pomocą android:focusable="true"
i android:focusableInTouchMode="true"
ponieważ podczas rozmowyclearFocus()
fokus zostanie ponownie przypisany do pierwszego widoku, który można ustawić. Przykładowy widok manekina:
<View
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"/>
Dodatkowe informacje
Rozwiązanie, które wykrywa różnicę w zmianach układu, nie działa zbyt dobrze, ponieważ silnie zależy od gęstości ekranu, ponieważ 100 pikseli może być dużo w określonym urządzeniu, a w innych nie można uzyskać fałszywych wyników dodatnich. Również różni dostawcy mają różne klawiatury.
W Androidzie możesz wykryć za pomocą powłoki ADB. Napisałem i używam tej metody:
{
JSch jsch = new JSch();
try {
Session session = jsch.getSession("<userName>", "<IP>", 22);
session.setPassword("<Password>");
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelExec channel = (ChannelExec)session.openChannel("exec");
BufferedReader in = new BufferedReader(new
InputStreamReader(channel.getInputStream()));
channel.setCommand("C:/Android/android-sdk/platform-tools/adb shell dumpsys window
InputMethod | findstr \"mHasSurface\"");
channel.connect();
String msg = null;
String msg2 = " mHasSurface=true";
while ((msg = in.readLine()) != null) {
Boolean isContain = msg.contains(msg2);
log.info(isContain);
if (isContain){
log.info("Hiding keyboard...");
driver.hideKeyboard();
}
else {
log.info("No need to hide keyboard.");
}
}
channel.disconnect();
session.disconnect();
} catch (JSchException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
final View activityRootView = findViewById(R.id.rootlayout);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
activityRootView.getWindowVisibleDisplayFrame(r);
int screenHeight = activityRootView.getRootView().getHeight();
Log.e("screenHeight", String.valueOf(screenHeight));
int heightDiff = screenHeight - (r.bottom - r.top);
Log.e("heightDiff", String.valueOf(heightDiff));
boolean visible = heightDiff > screenHeight / 3;
Log.e("visible", String.valueOf(visible));
if (visible) {
Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show();
}
}
});
Odpowiedź @iWantScala jest świetna, ale nie działa dla mnie
rootView.getRootView().getHeight()
zawsze ma tę samą wartość
Jednym ze sposobów jest zdefiniowanie dwóch zmiennych
private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;
dodaj globalny odbiornik
rootView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
currentRootViewHeight = rootView.getHeight();
if (currentRootViewHeight > maxRootViewHeight) {
maxRootViewHeight = currentRootViewHeight;
}
}
});
następnie sprawdź
if (currentRootViewHeight >= maxRootViewHeight) {
// Keyboard is hidden
} else {
// Keyboard is shown
}
działa w porządku
Wreszcie jest teraz bezpośredni sposób, zaczynając od Androida R opartego na Kotlinie.
val imeInsets = view.rootWindowInsets.getInsets(Type.ime())
if (imeInsets.isVisible) {
//Ime is visible
//Lets move our view by the height of the IME
view.translationX = imeInsets.bottom }
Miałem podobny problem. Musiałem zareagować na przycisk Enter na ekranie (który ukrywał klawiaturę). W takim przypadku możesz zasubskrybować opcję OnEditorAction widoku tekstowego, z którym korzystała klawiatura - jeśli masz wiele edytowalnych pól, zasubskrybuj je wszystkie.
W swojej działalności masz pełną kontrolę nad klawiaturą, więc w żadnym momencie nie staniesz przed problemem, czy klawiatura jest otwarta, czy nie, jeśli słuchasz wszystkich zdarzeń otwierania i zamykania.
Istnieje bezpośredni sposób, aby się tego dowiedzieć. I nie wymaga zmian układu.
Działa więc również w trybie pełnego ekranu.
Ale niestety nie działa na wszystkich urządzeniach. Musisz to przetestować na swoich urządzeniach.
Sztuka polega na tym, że próbujesz ukryć lub pokazać miękką klawiaturę i uchwycić wynik tej próby.
Jeśli działa poprawnie, klawiatura nie jest tak naprawdę pokazywana ani ukryta. Po prostu pytamy o państwo.
Aby być na bieżąco, wystarczy powtórzyć tę operację, np. Co 200 milisekund, używając programu obsługi.
Poniższa implementacja wykonuje tylko jedną kontrolę.
Jeśli wykonujesz wiele kontroli, powinieneś włączyć wszystkie testy (_keyboardVisible).
public interface OnKeyboardShowHide
{
void onShowKeyboard( Object param );
void onHideKeyboard( Object param );
}
private static Handler _keyboardHandler = new Handler();
private boolean _keyboardVisible = false;
private OnKeyboardShowHide _keyboardCallback;
private Object _keyboardCallbackParam;
public void start( OnKeyboardShowHide callback, Object callbackParam )
{
_keyboardCallback = callback;
_keyboardCallbackParam = callbackParam;
//
View view = getCurrentFocus();
if (view != null)
{
InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
}
else // if (_keyboardVisible)
{
_keyboardVisible = false;
_keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
}
}
private ResultReceiver _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
{
@Override
protected void onReceiveResult( int resultCode, Bundle resultData )
{
switch (resultCode)
{
case InputMethodManager.RESULT_SHOWN :
case InputMethodManager.RESULT_UNCHANGED_SHOWN :
// if (!_keyboardVisible)
{
_keyboardVisible = true;
_keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
}
break;
case InputMethodManager.RESULT_HIDDEN :
case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
// if (_keyboardVisible)
{
_keyboardVisible = false;
_keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
}
break;
}
}
};
Oto obejście, aby wiedzieć, czy klawiatura programowa jest widoczna.
Niektóre popularne klawiatury mają określone słowa kluczowe w swojej klasieNazwy:
W ActivityManager.RunningServiceInfo sprawdź powyższe wzorce w ClassNames. Ponadto, clientPackage = android , ActivityManager.RunningServiceInfo's = android, wskazując, że klawiatura jest powiązana z systemem.
Powyższe informacje można połączyć w celu dokładnego sprawdzenia, czy widoczna jest miękka klawiatura.
Jak zapewne wiesz, klawiatura oprogramowania Android będzie widoczna tylko wtedy, gdy możliwe jest pisanie na klawiaturze. Innymi słowy Klawiatura staje się widoczna tylko wtedy, gdy jest skoncentrowany EditText. oznacza to, że możesz uzyskać pogodę, że klawiatura jest widoczna lub nie, używając OnFocusChangeListener .
//Declare this Globally
public boolean isKeyBoardVisible = false;
//In OnCreate *[For Activity]*, OnCreateView *[For Fragment]*
text_send.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus)
isKeyBoardVisible = true;
else
isKeyBoardVisible = false;
}
});
Teraz możesz użyć zmiennej isKeyBoardVisible w dowolnym miejscu w klasie, aby uzyskać pogodę, że klawiatura jest otwarta lub nie. To działało dla mnie dobrze.
Uwaga: Ten proces nie działa, gdy klawiatura jest otwierana programowo za pomocą InputMethodManager, ponieważ nie wywołuje OnFocusChangeListener.
Przekształciłem odpowiedź na kotlin, mam nadzieję, że pomoże to użytkownikom kotlin.
private fun checkKeyboardVisibility() {
var isKeyboardShowing = false
binding.coordinator.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
binding.coordinator.getWindowVisibleDisplayFrame(r)
val screenHeight = binding.coordinator.rootView.height
// r.bottom is the position above soft keypad or device button.
// if keypad is shown, the r.bottom is smaller than that before.
val keypadHeight = screenHeight - r.bottom
if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
// keyboard is opened
if (!isKeyboardShowing) {
isKeyboardShowing = true
}
} else {
// keyboard is closed
if (isKeyboardShowing) {
isKeyboardShowing = false
}
}
}
}
Działa z funkcją dostosowaniaNie są używane flagi aktywności i zdarzeń cyklu życia. Również z Kotlinem:
/**
* This class uses a PopupWindow to calculate the window height when the floating keyboard is opened and closed
*
* @param activity The parent activity
* The root activity that uses this KeyboardManager
*/
class KeyboardManager(private val activity: AppCompatActivity) : PopupWindow(activity), LifecycleObserver {
private var observerList = mutableListOf<((keyboardTop: Int) -> Unit)>()
/** The last value of keyboardTop */
private var keyboardTop: Int = 0
/** The view that is used to calculate the keyboard top */
private val popupView: View?
/** The parent view */
private var parentView: View
var isKeyboardShown = false
private set
/**
* Create transparent view which will be stretched over to the full screen
*/
private fun createFullScreenView(): View {
val view = LinearLayout(activity)
view.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
view.background = ColorDrawable(Color.TRANSPARENT)
return view
}
init {
this.popupView = createFullScreenView()
contentView = popupView
softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE or LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
inputMethodMode = INPUT_METHOD_NEEDED
parentView = activity.findViewById(android.R.id.content)
width = 0
height = LayoutParams.MATCH_PARENT
popupView.viewTreeObserver.addOnGlobalLayoutListener {
val rect = Rect()
popupView.getWindowVisibleDisplayFrame(rect)
val keyboardTop = rect.bottom
if (this.keyboardTop != keyboardTop) {
isKeyboardShown = keyboardTop < this.keyboardTop
this.keyboardTop = keyboardTop
observerList.forEach { it(keyboardTop) }
}
}
activity.lifecycle.addObserver(this)
}
/**
* This must be called after the onResume of the Activity or inside view.post { } .
* PopupWindows are not allowed to be registered before the onResume has finished
* of the Activity
*/
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun start() {
parentView.post {
if (!isShowing && parentView.windowToken != null) {
setBackgroundDrawable(ColorDrawable(0))
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
}
}
}
/**
* This manager will not be used anymore
*/
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun close() {
activity.lifecycle.removeObserver(this)
observerList.clear()
dismiss()
}
/**
* Set the keyboard top observer. The observer will be notified when the keyboard top has changed.
* For example when the keyboard is opened or closed
*
* @param observer The observer to be added to this provider
*/
fun registerKeyboardTopObserver(observer: (keyboardTop: Int) -> Unit) {
observerList.add(observer)
}
}
Przydatna metoda utrzymywania widoku zawsze nad klawiaturą
fun KeyboardManager.updateBottomMarginIfKeyboardShown(
view: View,
activity: AppCompatActivity,
// marginBottom of view when keyboard is hide
marginBottomHideKeyboard: Int,
// marginBottom of view when keybouard is shown
marginBottomShowKeyboard: Int
) {
registerKeyboardTopObserver { bottomKeyboard ->
val bottomView = ViewUtils.getFullViewBounds(view).bottom
val maxHeight = ScreenUtils.getFullScreenSize(activity.windowManager).y
// Check that view is within the window size
if (bottomView < maxHeight) {
if (bottomKeyboard < bottomView) {
ViewUtils.updateMargin(view, bottomMargin = bottomView - bottomKeyboard +
view.marginBottom + marginBottomShowKeyboard)
} else ViewUtils.updateMargin(view, bottomMargin = marginBottomHideKeyboard)
}
}
}
Gdzie getFullViewBounds
fun getLocationOnScreen(view: View): Point {
val location = IntArray(2)
view.getLocationOnScreen(location)
return Point(location[0], location[1])
}
fun getFullViewBounds(view: View): Rect {
val location = getLocationOnScreen(view)
return Rect(location.x, location.y, location.x + view.width,
location.y + view.height)
}
Gdzie getFullScreenSize
fun getFullScreenSize(wm: WindowManager? = null) =
getScreenSize(wm) { getRealSize(it) }
private fun getScreenSize(wm: WindowManager? = null, block: Display.(Point) -> Unit): Point {
val windowManager = wm ?: App.INSTANCE.getSystemService(Context.WINDOW_SERVICE)
as WindowManager
val point = Point()
windowManager.defaultDisplay.block(point)
return point
}
Gdzie updateMargin
fun updateMargin(
view: View,
leftMargin: Int? = null,
topMargin: Int? = null,
rightMargin: Int? = null,
bottomMargin: Int? = null
) {
val layoutParams = view.layoutParams as ViewGroup.MarginLayoutParams
if (leftMargin != null) layoutParams.leftMargin = leftMargin
if (topMargin != null) layoutParams.topMargin = topMargin
if (rightMargin != null) layoutParams.rightMargin = rightMargin
if (bottomMargin != null) layoutParams.bottomMargin = bottomMargin
view.layoutParams = layoutParams
}
Zrobiłem to w następujący sposób, ale ma to znaczenie tylko wtedy, gdy Twoim celem jest zamknięcie / otwarcie klucza.
zamknij przykład: (sprawdzenie, czy klawiatura jest już zamknięta, jeśli nie - zamknięcie)
imm.showSoftInput(etSearch, InputMethodManager.HIDE_IMPLICIT_ONLY, new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN)
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
});
a może używać:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(
getClass().getSimpleName(),
String.format("conf: %s", newConfig));
if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
onHardwareKeyboardChange(newConfig.hardKeyboardHidden);
hardKeyboardHidden = newConfig.hardKeyboardHidden;
}
if (newConfig.keyboardHidden != keyboardHidden) {
onKeyboardChange(newConfig.keyboardHidden);
keyboardHidden = newConfig.hardKeyboardHidden;
}
}
public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;
//todo
private void onKeyboardChange(int keyboardHidden) {
}
//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {
}
Napisałem próbkę .
To repozytorium może pomóc w wykryciu stanu klawiatury bez założenia, że „klawiatura powinna być w więcej niż X części ekranu”
Jeśli w swojej aplikacji obsługujesz api dla AndroidR, możesz użyć poniższej metody.
In kotlin :
var imeInsets = view.rootWindowInsets.getInsets(Type.ime())
if (imeInsets.isVisible) {
view.translationX = imeInsets.bottom
}
Uwaga: ta opcja jest dostępna tylko dla systemu AndroidR, a poniżej wersja Androida musi podążać za inną odpowiedzią lub zaktualizuję ją w tym celu.