Imagine that I have 10 inputs on the screen and they are in the scrollview, and I have a sticky button at the bottom. When I focus on an input, I want the input to remain on the keyboard and I want it to be scrollable.
I wrote a class for scrollview;
class AdjustingScrollView(context: Context, attrs: AttributeSet) : NestedScrollView(context, attrs) {
var keyboardOpen = false
set(value) {
field = value
requestLayout()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var modifiedHeightMeasureSpec = heightMeasureSpec
if (keyboardOpen) {
val rootView = rootView ?: return
val keyboardHeight = calculateKeyboardHeight(rootView)
modifiedHeightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - keyboardHeight, MeasureSpec.EXACTLY)
}
super.onMeasure(widthMeasureSpec, modifiedHeightMeasureSpec)
}
fun calculateKeyboardHeight(rootView: View): Int {
val rect = Rect()
rootView.getWindowVisibleDisplayFrame(rect)
val displayHeight = rootView.height
val visibleAreaHeight = rect.height()
return (displayHeight - visibleAreaHeight).takeIf { it > displayHeight * 0.15 } ?: 0
}
}
xml;
<AdjustingScrollView
android:id="@+id/scrollViewRoot"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
in fragment;
val rootView = view?.rootView
scrollViewRoot.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
rootView?.getWindowVisibleDisplayFrame(r)
val screenHeight = rootView?.height ?: 0
val keypadHeight = screenHeight - r.bottom
scrollViewRoot.keyboardOpen = keypadHeight > screenHeight * 0.15
}
input.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
scrollViewRoot.postDelayed({
val additionalPadding = dpToPx(16)
val location = IntArray(2)
v.getLocationInWindow(location)
val viewBottom = location[1] + v.height
val r = Rect()
rootView?.getWindowVisibleDisplayFrame(r)
val screenHeight = rootView?.height ?: 0
val keyboardHeight = if (scrollViewRoot.keyboardOpen) screenHeight - r.bottom else 0
val requiredScrollY = viewBottom + additionalPadding - (screenHeight - keyboardHeight)
if (requiredScrollY > 0) {
scrollViewRoot.smoothScrollTo(0, requiredScrollY)
}
}, 500)
}
}
manifest;
android:windowSoftInputMode="adjustResize"