【问题标题】:How to allow clicking on disabled preferences (or mimic disabled preferences functionality)?如何允许点击禁用的首选项(或模仿禁用的首选项功能)?
【发布时间】:2016-11-08 15:18:31
【问题描述】:

背景

某些应用功能需要权限。如果未授予权限,我们需要将其首选项“半”禁用(并且无论是否勾选都不会更改),并带有一条文本告诉它不能使用,因为没有足够的授予权限,所以它只是部分看起来被禁用(文本将保持黑色,警告为红色)。它看起来不像是正常的禁用偏好。

就像一个正常的禁用首选项一样,当它处于这种状态时,所有依赖于它的首选项都将被禁用且不可点击。

但是,与正常禁用的首选项不同,单击此类首选项后,它将转到授予所需权限的屏幕。

问题

有多种方法可以处理点击首选项,但我发现没有一种方法可以处理点击禁用的首选项。

由于各种其他首选项依赖于这样的首选项(以便它们根据是否启用/禁用来启用/禁用),我需要让它在需要时禁用,但允许点击它。

我尝试过的

我尝试了各种方法来处理点击:

  • PreferenceFragment 内的 onPreferenceTreeClick
  • 首选项本身的 setOnPreferenceClickListener
  • 试图覆盖首选项的 performClick,但它被认为是一件坏事,因为它被隐藏了
  • 覆盖偏好的 onClick。
  • 在首选项的 onCreateView 或 onBindView 中,对已创建的视图使用 setOnClickListener。
  • 包装首选项的 onCreateView 的视图,并在视图或包装它的新视图上使用 setOnClickListener。

当首选项被禁用时,所有这些都不会被调用,并且您尝试单击首选项。

问题

  1. 是否可以禁用首选项但仍处理对其的点击?

  2. 或者,是否可以扩展首选项依赖项的功能?使其他首选项依赖于此首选项,而不仅仅是基于它是否启用?这意味着只有在启用此功能且未处于半启用状态时才启用它们?

    目前,只有 CheckboxPreference 在应用程序上用作需要这种新状态的应用程序,因此很容易使其复选框看起来禁用,但让首选项本身保持启用状态(我只是使用 view.findViewById(android.R.id.checkbox) onCreateView 方法内)

【问题讨论】:

  • "是否可以禁用首选项但仍可处理对其的点击?" - 可能不是。我的猜测是他们将底层小部件标记为禁用,并且您无法接收禁用小部件的点击事件(因为它们已被禁用)。就个人而言,我会为依赖于权限的首选项使用单独的首选项屏幕,您可以在其中控制用户如何访问这些屏幕的 UI。
  • @CommonsWare 实际上,我在询问此问题后不久就找到了解决方法,但我仍然希望使其正常工作。请在下面查看我的答案。

标签: android android-preferences


【解决方案1】:

好的,我找到了解决方法:

class CheckboxPreferenceEx : android.preference.CheckBoxPreference {
    var alwaysAllowClickingEnabled: Boolean = false
    private val onPreferenceViewClickListener: View.OnClickListener

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)

    init {
        onPreferenceViewClickListener = View.OnClickListener {
            if (onPreferenceChangeListener != null && !isEnabled)
                if (onPreferenceChangeListener.onPreferenceChange(this@CheckboxPreferenceEx, !isChecked))
                    isChecked = !isChecked
            if (this@CheckboxPreferenceEx.isEnabled)
                this@CheckboxPreferenceEx.onClick()
        }
    }

    override fun onCreateView(parent: ViewGroup): View {
        val view = super.onCreateView(parent)
        setPreferenceTitleTextViewToHaveMultipleLines(view)
        //mTitleTextView = (TextView) view.findViewById(android.R.id.title);
        //mSummaryTextView = (TextView) view.findViewById(android.R.id.summary);
        return view
    }

    override fun onBindView(view: View) {
        super.onBindView(view)
        view.setOnClickListener(onPreferenceViewClickListener)
        val dependency = dependency
        if (!TextUtils.isEmpty(dependency) && !isEnabled) {
            //if the reason this preference is disabled is because of dependency, act as normal
            val dependencyPreference = preferenceManager.findPreference(dependency)
            if (!dependencyPreference!!.isEnabled || dependencyPreference is TwoStatePreference && !dependencyPreference.isChecked)
                return
        }
        if (alwaysAllowClickingEnabled) {
            //we chose to enable all except for the checkbox, which will still look disabled
            view.isEnabled = true
            setEnabledToViewAndItsDescendants(view, true)
        }
    }

    companion object {

        fun setPreferenceTitleTextViewToHaveMultipleLines(v: View) {
            if (v is TextView && v.getId() == android.R.id.title) {
                v.setSingleLine(false)
                return
            }
            if (v is ViewGroup) {
                for (i in 0 until v.childCount) {
                    val child = v.getChildAt(i)
                    setPreferenceTitleTextViewToHaveMultipleLines(child)
                }
            }
        }

        fun setEnabledToViewAndItsDescendants(v: View?, enabled: Boolean) {
            if (v == null)
                return
            v.isEnabled = enabled
            if (v is ViewGroup) {
                val viewGroups = ArrayList<ViewGroup>()
                viewGroups.add(v)
                while (!viewGroups.isEmpty()) {
                    val viewGroup = viewGroups.removeAt(0)
                    val childCount = viewGroup.childCount
                    for (i in 0 until childCount) {
                        val childView = viewGroup.getChildAt(i)
                        childView.isEnabled = enabled
                        if (childView is ViewGroup)
                            viewGroups.add(childView)
                    }
                }
            }
        }
    }

}

有这样的偏好,当我在它上面调用 setAlwaysAllowClickingEnabled(true) 时,会导致该偏好真正被禁用,但是当你点击它时,它会调用回调。

在我们的例子中,我们想让复选框保持禁用状态,但启用标题和摘要 TextView,但您可以根据自己的要求做任何事情。更新了代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-05
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    相关资源
    最近更新 更多