material-components-android icon indicating copy to clipboard operation
material-components-android copied to clipboard

[BottomSheetDialogFragment] Listener set with setOnApplyWindowInsetsListener is never called

Open minas1 opened this issue 3 years ago • 2 comments

Description: I want to adjust the padding of my root view when the keyboard opens and I'm trying to accomplish it using setOnApplyWindowInsetsListener().

In a BottomSheetDialogFragment, the listener is never called.

If I change my fragment to extend from DialogFragment, the listener is called and the behavior is as expected.

Expected behavior: The listener set with setOnApplyWindowInsetsListener() is called in a BottomSheetDialogFragment and applies padding to the layout.

Source code:

package com.minasmina.bottomsheetdialogfragmentbug

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.bottomsheet.BottomSheetDialogFragment

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val dialog = TestDialog()
        dialog.show(supportFragmentManager, null)
    }
}

// TODO If you extend from DialogFragment(), `setOnApplyWindowInsetsListener` _is_ called
//  and the behavior is correct (padding is applied).
class TestDialog : BottomSheetDialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.test, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val window = requireDialog().window!!

        ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
            val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
            view.setPadding(0, 0, 0, imeHeight)
            insets
        }

        WindowCompat.setDecorFitsSystemWindows(window, false)
    }
}

test.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Comment"
        android:layout_above="@id/button" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="Test" />

</RelativeLayout>

Minimal sample app repro: https://github.com/minas1/BottomSheetDialogFragmentBug

Android API version: 32

Material Library version: 1.6.1

minas1 avatar Jul 08 '22 06:07 minas1

Dude it is not a BUG, few month ago I came across the same problem, then I found the BottomSheetDialogFragment is special. Our view returned from onCreateView is added to another View, and this view is a child of DecorView as we know. The purpose of this view is to have default insets response.

What I did is set a listener directly on DecorView, cause insets is transmitted layer by layer, parent to child. So for your code, you just need to change one parameter:

ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { _, insets ->
            val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
            view.setPadding(0, 0, 0, imeHeight)
            insets
        }

oOJohn6Oo avatar Jul 15 '22 07:07 oOJohn6Oo

Oh, sorry, maybe you should return WindowInsetsCompat.CONSUMED

oOJohn6Oo avatar Jul 15 '22 07:07 oOJohn6Oo