Solution to the problem that the input dialog box popped up by PreferenceFragment under the Android immersive status bar cannot follow the upward movement of the keyboard

Background introduction

When the status bar is not immersed, when there is in PreferenceFragmentCompat, the input dialog box called out by clicking the entry will move up along with the keyboard, but Once set inEditTextPreferencestyles.xml

<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>

That is, after immersing the status bar or navigation bar, you cannot move up when calling out the dialog box.

Recap history

This is an old bug from 20131. Since Google introduced the immersive status bar feature, this bug has never been resolved. Repair, and there are many posts on stackoverflow2, which roughly solve the problem by manually moving the control up.

my question

Most of these posts are for the EditText on the custom View, so customization is relatively easy, and the best one is this GitHub answer, It can adapt to almost any layout, but under system packaging, this code can only detect the height change after the keyboard is called out, but cannot automatically move the input box up. PreferenceFragmentCompat

Solution

After synthesizing the above information and combining the characteristics of PreferenceFragmentCompat, I wrote the final solution. It may not be a perfect solution, but it works fine.

package xxx.yyy.zzz

import android.animation.ObjectAnimator
import android.graphics.Rect
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.Window
import androidx.annotation.Keep
import androidx.preference.EditTextPreference
import androidx.preference.EditTextPreferenceDialogFragmentCompat
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import xxx.yyy.zzz.R
import java.lang.Thread.sleep

class SettingsFragment: PreferenceFragmentCompat() {
    
    
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
    
    
        setPreferencesFromResource(R.xml.pref_setting, rootKey)
    }

    override fun onDisplayPreferenceDialog(preference: Preference) {
    
    
        if (preference is EditTextPreference) {
    
    
            Log.d("MySF", "preference is EditTextPreference")
            val f = EditTextPreferenceDialogFragmentCompat.newInstance(preference.key)
            f.setTargetFragment(this, 0)
            f.show(parentFragmentManager, null)
            Thread {
    
    
                var diff = 0
                var cnt = 0
                while (diff == 0 && cnt++ < 20) {
    
    
                    sleep(50)
                    if (f.dialog == null) continue
                    val v = view?:return@Thread
                    // https://github.com/mikepenz/MaterialDrawer/blob/aa9136fb4f5b3a80460fe5f47213985026d20c88/library/src/main/java/com/mikepenz/materialdrawer/util/KeyboardUtil.java
                    val r = Rect()
                    //r will be populated with the coordinates of your view that area still visible.
                    v.getWindowVisibleDisplayFrame(r)
                    //get screen height and calculate the difference with the useable area from the r
                    val height = v.context.resources.displayMetrics.heightPixels
                    diff = height - r.bottom
                    Log.d("MySF", "diff: $diff")
                }
                Log.d("MySF", "diff out while: $diff")
                if (diff <= 0) return@Thread
                Log.d("MySF", "f.dialog is ${
      
      f.dialog}")
                f.activity?.runOnUiThread {
    
    
                    f.dialog?.window?.apply {
    
    
                        val attr = attributes
                        Log.d("MySF", "animate from ${
      
      attr.y} to ${
      
      attr.y-diff/2}")
                        ObjectAnimator.ofInt(WindowAttributeSetter(this), "y", attr.y, attr.y-diff/2).setDuration(233).start()
                    }
                }
            }.start()
            return
        }
        super.onDisplayPreferenceDialog(preference)
    }

    inner class WindowAttributeSetter(private val window: Window) {
    
    
        @Keep
        fun setY(y: Int) {
    
    
            val attr = window.attributes
            attr.y = y
            Log.d("MySF", "set y to $y")
            window.attributes = attr
        }
    }
}

  1. Keyboard don’t resize the screen when android:windowTranslucentStatus=true ↩︎

  2. Keyboard hiding EditText when android:windowTranslucentStatus=true ↩︎

Guess you like

Origin blog.csdn.net/u011570312/article/details/134201012