1

I am using Navigation from Jetpack. That means, I have only 1 single activity and I want to move the layout up the keyboard whenever the keyboard pops up. the problem is, this should happen only on certain Fragment.

Setting on Manifest works, the problem is that I need it only on a specific Fragment.

android:windowSoftInputMode="adjustResize"

The app has a BottomNavigationView, so, for retaining Fragment state, I am hidding instead of replacing and removing it. Also, each fragment has its NavigationGraph. So I cannot access to the lifecycle explicitly. I thought that setting that mode programmatically was going to work. But, as explained, it did not.

override fun onResume() {
    super.onResume()
    keyboardMode = requireActivity().window.attributes.softInputMode
    requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
}

override fun onPause() {
    super.onPause()
    keyboardMode?.let { requireActivity().window.setSoftInputMode(it) }
}

I also tried setting on my XML:

android:fitsSystemWindows="true"

It did not work. Also, on which of my nested fragments should I put it?

Any thoughts? What could I do? Is there a way to get size of the keyboard, move the fragment's content up the size of keyboard with a listener or something similar? Might solve that issue that way only...

EDIT:

I found this, which I change as needed:

class KeyboardListener(
    private val binding: FragmentWebviewBinding,
    private val listener: KeyboardInterface
) {
    private var keyboardListenersAttached = false
    private var rootLayout: ViewGroup? = null
    private val keyboardLayoutListener = OnGlobalLayoutListener {
        val r = Rect()
        binding.webview.getWindowVisibleDisplayFrame(r)
        val screenHeight = binding.root.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

        logD("Keyboard", "keypadHeight = $keypadHeight")

        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            listener.onShowKeyboard(keypadHeight)
        } else {
            // keyboard is closed
            listener.onHideKeyboard()
        }
    }

    fun attachKeyboardListeners() {
        if (keyboardListenersAttached) return
        rootLayout = binding.root as ViewGroup?
        rootLayout?.viewTreeObserver?.addOnGlobalLayoutListener(keyboardLayoutListener)
        keyboardListenersAttached = true
    }

    fun destroy() {
        if (keyboardListenersAttached) {
            rootLayout?.viewTreeObserver?.removeGlobalOnLayoutListener(keyboardLayoutListener)
        }
    }

    interface KeyboardInterface {
        fun onShowKeyboard(keyboardHeight: Int)
        fun onHideKeyboard()
    }
}

What I am doing with the listener is: if keyboard is opened, I am adding bottom margin of the keyboardHeight, if closed, returned to 0. The problem is, that is not measuring correctly. I am not sure if is from px to dp or any similar. Also, it is being called all the time.

But is the best approach so far.

EDIT 2: I was measuring incorrectly.

The correct solution was changing this lines on keyboardLayoutListener:

binding.webview.getWindowVisibleDisplayFrame(r)
val screenHeight = binding.root.height

Although, the toolbar is moving up even though I am moving on the padding of the webview only:

override fun onHideKeyboard() {
    with(binding.webview) {
        val params = layoutParams as ConstraintLayout.LayoutParams
        params.setMargins(0, 0, 0, 0)
        layoutParams = params
    }
}

override fun onShowKeyboard(keyboardHeight: Int) {
    with(binding.webview) {
        val params = layoutParams as ConstraintLayout.LayoutParams
        params.setMargins(0, 0, 0, keyboardHeight)
        layoutParams = params
    }
}
Amg91
  • 132
  • 5
  • 22

0 Answers0