Created
February 18, 2019 20:03
-
-
Save tieorange/0be17a4322358fa367fefb0c21c09ac7 to your computer and use it in GitHub Desktop.
Hide and show the keyboard util
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.dobabci.android.util | |
import android.app.Activity | |
import android.content.Context | |
import android.graphics.Rect | |
import android.view.View | |
import android.view.ViewTreeObserver | |
import android.view.Window | |
import android.view.inputmethod.InputMethodManager | |
import androidx.appcompat.app.AppCompatActivity | |
import androidx.lifecycle.Lifecycle | |
import androidx.lifecycle.LifecycleObserver | |
import androidx.lifecycle.OnLifecycleEvent | |
import java.lang.ref.WeakReference | |
/** | |
* Teleprinter, like the old electromechanical typewriters. This class fills the holes of dealing | |
* with keyboards | |
*/ | |
class Teleprinter(activity: AppCompatActivity, private val observeOpenCloseEvents: Boolean = false) : LifecycleObserver, ViewTreeObserver.OnGlobalLayoutListener { | |
companion object { | |
//TODO should this be adjusted depending on the density of the device? | |
private const val KEYBOARD_THRESHOLD = 250 //px to consider keyboard opened | |
private const val NEEDED_DELAY = 100L | |
} | |
private val activityWeakReference: WeakReference<Activity> = WeakReference(activity) | |
private val viewWeakReference: WeakReference<View> = WeakReference(activity.findViewById(Window.ID_ANDROID_CONTENT)) | |
private val inputMethodManager: InputMethodManager = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager | |
private val onKeyboardOpenedListeners by lazy { mutableListOf<OnKeyboardOpenedListener>() } | |
private val onKeyboardClosedListeners by lazy { mutableListOf<OnKeyboardClosedListener>() } | |
private var isSoftKeyboardOpened: Boolean = false | |
init { | |
if (observeOpenCloseEvents) { | |
viewWeakReference.get()?.viewTreeObserver?.addOnGlobalLayoutListener(this) | |
activity.lifecycle.addObserver(this) | |
} | |
} | |
/** | |
* Hides the keyboard | |
* | |
* @return true if the keyboard is successfully hidden, false otherwise | |
*/ | |
fun hideKeyboard(flags: Int = 0): Boolean { | |
val activity = activityWeakReference.get() ?: return false | |
// Check if no view has focus: | |
val view = activity.currentFocus | |
return if (view != null) { | |
inputMethodManager.hideSoftInputFromWindow(view.windowToken, flags) | |
} else false | |
} | |
/** | |
* Show the keyboard | |
* | |
* @param view the view to get focus | |
* @return true if keyboard is show, false otherwise | |
*/ | |
fun showKeyboard(view: View, flags: Int = InputMethodManager.SHOW_IMPLICIT): Boolean { | |
return inputMethodManager.showSoftInput(view, flags) | |
} | |
/** | |
* Show the keyboard after its needed delay, specifically for usage when an activity is just created. | |
*/ | |
fun showKeyboardWithDelay(view: View, flags: Int = InputMethodManager.SHOW_IMPLICIT) { | |
view.postDelayed({ | |
showKeyboard(view, flags) | |
}, NEEDED_DELAY) | |
} | |
/** | |
* Toggle the keyboard, which forces it to show without a reference to a view | |
*/ | |
fun toggleKeyboard(showFlags: Int = InputMethodManager.SHOW_IMPLICIT, hideFlags: Int = 0) { | |
inputMethodManager.toggleSoftInput(showFlags, hideFlags) | |
} | |
/** | |
* Is the keyboard currently showing? | |
* @return true if showing, false if not | |
*/ | |
fun isKeyboardShowing(): Boolean { | |
checkObserving() | |
return isSoftKeyboardOpened | |
} | |
/** | |
* Listen for when the keyboard is opened. | |
* @param listener the listener to register | |
*/ | |
fun addOnKeyboardOpenedListener(listener: OnKeyboardOpenedListener) { | |
checkObserving() | |
onKeyboardOpenedListeners.add(listener) | |
} | |
/** | |
* Unregister for keyboard open events | |
* @param listener the listener to unregister | |
*/ | |
fun removeOnKeyboardOpenedListener(listener: OnKeyboardOpenedListener) { | |
checkObserving() | |
onKeyboardOpenedListeners.remove(listener) | |
} | |
/** | |
* Listen for when the keyboard is closed. NOTE: this will only work if your [Activity] | |
* android:windowSoftInputMode="adjustResize" | |
* @param listener the listener to register | |
*/ | |
fun addOnKeyboardClosedListener(listener: OnKeyboardClosedListener) { | |
checkObserving() | |
onKeyboardClosedListeners.add(listener) | |
} | |
/** | |
* Unregister for keyboard close events | |
* @param listener the listener to unregister | |
*/ | |
fun removeOnKeyboardClosedListener(listener: OnKeyboardClosedListener) { | |
checkObserving() | |
onKeyboardClosedListeners.remove(listener) | |
} | |
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) | |
fun onDestroy() { | |
viewWeakReference.get()?.viewTreeObserver?.removeOnGlobalLayoutListener(this) | |
onKeyboardOpenedListeners.clear() | |
onKeyboardClosedListeners.clear() | |
} | |
override fun onGlobalLayout() { | |
val r = Rect() | |
val activityRootView = viewWeakReference.get() ?: return | |
//r will be populated with the coordinates of your view that area still visible. | |
activityRootView.getWindowVisibleDisplayFrame(r) | |
val heightDiff = activityRootView.rootView.height - (r.bottom - r.top) | |
if (!isSoftKeyboardOpened && heightDiff > KEYBOARD_THRESHOLD) { // if more than 100 pixels, its probably a keyboard... | |
isSoftKeyboardOpened = true | |
onKeyboardOpenedListeners.forEach { it.invoke(heightDiff) } | |
} else if (isSoftKeyboardOpened && heightDiff < KEYBOARD_THRESHOLD) { | |
isSoftKeyboardOpened = false | |
onKeyboardClosedListeners.forEach { it.invoke() } | |
} | |
} | |
private fun checkObserving() { | |
if (!observeOpenCloseEvents) { | |
throw IllegalStateException("You are not observing open/close events. Change your constructor of Teleprinter to be Teleprinter(activity, true)") | |
} | |
} | |
} | |
typealias OnKeyboardOpenedListener = (height: Int) -> Unit | |
typealias OnKeyboardClosedListener = () -> Unit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment