• 安卓沉浸状态栏下 PreferenceFragment 弹出的输入对话框无法跟随键盘上移的解决办法


    背景介绍

    在不沉浸状态栏时,当PreferenceFragmentCompat中有EditTextPreference时,点击该条目呼出的输入对话框将跟随键盘上移,但一旦在styles.xml中设置

    <item name="android:windowTranslucentStatus">trueitem>
    <item name="android:windowTranslucentNavigation">trueitem>
    
    • 1
    • 2

    也就是沉浸状态栏或导航栏后,再呼出对话框时则无法上移。

    历史回顾

    这是一个2013年的陈年老bug1,从谷歌引入沉浸状态栏这个特性至今,该bug从未被修复,并且在stackoverflow也有不少帖子2,大致是通过手动上移控件的方式解决问题。

    我的问题

    这些帖子大多是针对自定义View上的EditText,所以自定义比较轻松,集大成者莫过于这个GitHub的回答,几乎可以适应一切布局,但在系统包装好的PreferenceFragmentCompat下,这个代码仅能检测到键盘呼出后的高度改变,却无法自动上移输入框。

    解决办法

    在综合上面的资料之后,结合PreferenceFragmentCompat的特性,我写出了最终解法,可能不是完美的办法,但是工作正常。

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

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

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

  • 相关阅读:
    灰狼优化算法(Matlab完整代码实现)
    leetcode做题笔记167. 两数之和 II - 输入有序数组
    Prometheus :(一)基本概念
    ELK部署Redis+Keepalived高可用环境
    低代码工作流程管理系统:提升企业运营效率的利器
    爬取动态网页数据的软件-抓取动态网页数据的工具
    iOS开发Swift-12-列表UI,TableViewController,动态响应Button勾选-待办事项App(1)
    redis哨兵练习
    影刀Rpa 、英佑科技面试总结
    HarmonyOS开发:ArkTs常见数据类型(一)
  • 原文地址:https://blog.csdn.net/u011570312/article/details/134201012