动态更改android首选项的widgetlayout资源

问题描述 投票:0回答:4

我在首选项屏幕内创建了一个首选项条目,如下所示:

<PreferenceScreen>
    <Preference
        android:title="title"
        android:key="key"
        android:widgetLayout="@layout/someview"/>
</PreferenceScreen>

这里我设置了一个

widgetlayout
资源,它应该显示在首选项的右侧(就像复选框首选项的复选框)。我还可以在我的
PreferenceActivity.onCreate()
代码中设置此资源,如下所示:

Preference myPreference = findPreference("key");
myPreference.setWidgetLayoutResource(R.layout.someview);

两种方法都可以正常工作,因此我可以在首选项右侧看到我的资源。 但是,我无法访问此资源(someview)以在运行时更改其属性。

手动设置资源 ID、从资源中夸大它或

findViewById
似乎都不起作用 - 我有无效的资源/资源 ID 未找到异常。似乎偏好活动稍后会导致资源膨胀。

有人遇到同样的问题吗?关于如何在运行时更改

widgetlayout
资源属性有什么想法吗?

这里有一个类似的问题,但没有回答

android android-preferences preferenceactivity
4个回答
13
投票

我似乎也有同样的问题,我尝试了这样的方法:

1) 创建自定义
Preference
并覆盖
onBindView()
:

public class ProgressBarPreference extends Preference {

    private ProgressBar mProgressBar;

    // constructors

    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar);
    }

    public ProgressBar getProgressBar() {
        return mProgressBar;
    }

}

2) 将此首选项添加到屏幕 xml:

<package.ProgressBarPreference
    android:key="key"
    android:summary="summary"
    android:title="title"
    android:widgetLayout="@layout/preference_widget_progressbar" />

preference_widget_progressbar.xml

<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/progressBar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center" />

或致电

setWidgetLayoutResource()

3) 当
onPreferenceTreeClick()
:

时获取ProgressBar
if (preference instanceof ProgressBarPreference) {
    ProgressBar progressBar = ((ProgressBarPreference) preference).getProgressBar();
    // TODO something
}

然而,已经一年多了!


2
投票

我对 joinAero 的情况有部分解决方法。如果目标只是在小部件中显示或隐藏不确定的进度条,则技巧是在代码中设置和清除小部件布局资源。

1) 定义包含 ProgressBar 的小部件布局。无需分配 ID。首选项_widget_progressbar.xml:

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

2)不要在settings.xml中指定小部件

<package.ProgressBarPreference
    android:key="key"
    android:summary="summary"
    android:title="title" />

3)当你想显示进度条时,将widget资源设置为preference_widget_progressbar。要清除它,请将其设置为 0。需要调用

notifyChanged()
来更新屏幕。

public void showProgressBar(boolean isVisible) {
    // Show or hide the entire widget (which contains only a ProgressBar)
    setWidgetLayoutResource(isVisible ? R.layout.preference_widget_progressbar: 0);
    notifyChanged();    // Update screen
}

获取指向实际 ProgressBar 的指针非常困难,特别是当首选项位于库项目中时。我按照

这篇文章
使用getIdentifier()取得了一些成功,但这种方法实际上隐藏了整个小部件,而在进度条上设置可见性则留下了一个空白的小部件可见。


1
投票

这里有一个解决方法:

创建小部件布局并设置 onClick 属性,

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/icon"
    android:layout_width="48dp"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:background="?android:attr/selectableItemBackground"
    *android:onClick="onMyKeyClicked"*
    android:scaleType="centerInside"
    android:src="@drawable/ic_action_info" />

然后在您的首选项中设置小部件布局,

<ListPreference
    android:defaultValue="1"
    android:entries="@array/my_entries"
    android:entryValues="@array/my_values"
    android:key="my_key"
    android:title="@string/pref_my_key_title"
    android:widgetLayout="@layout/pref_layout_my_key" />

然后在你的活动中有一个类似的方法,

public void onMyKeyClicked(View v) {
    Toast.makeText(this, "My key widget clicked",
       Toast.LENGTH_SHORT).show();
}

因此,对于带有小部件的每个首选项,您都会有一个将 onClick 属性设置为活动中唯一方法的布局。你觉得怎么样?


0
投票

我找到了解决此问题的方法,而无需创建自定义首选项。

此解决方案的一个好处是,您可以将相同的小部件资源与不同的侦听器实现(即“setOnClickListener”)一起使用。

下面的示例创建了两个 EditTextPreferecnes,每个都指向相同的小部件布局。然后使用 addOnChildAttachStateChangeListener 根据需要设置小部件。需要侦听器是因为首选项 Recycler 视图中首选项的视图绑定是最后发生的事情之一或 onResume() 之后发生的事情之一。

此外,请确保使用非零 ID。

琴弦:

<resources>
    <!-- Preference Titles -->
    <string name="prefs_header">Prefs With Widgets</string>

    <!-- Preferences -->
    <string name="pref_key_a">pref_key_a</string>
    <string name="pref_key_b">pref_key_b</string>
</resources>

小部件布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ImageButton
        android:id="@+id/imageButton"
        style="@android:style/Widget.Holo.ImageButton"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:contentDescription="@string/messages_header"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@android:drawable/stat_sys_download" />
</androidx.constraintlayout.widget.ConstraintLayout>

首选布局:

<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
    <PreferenceCategory
        app:iconSpaceReserved="false"
        app:title="Prefs With Widgets">
        <EditTextPreference
            app:iconSpaceReserved="false"
            app:key="@string/pref_key_a"
            app:title="Test Button A"
            app:useSimpleSummaryProvider="true"
            app:widgetLayout="@layout/my_widget" />
        <EditTextPreference
            app:iconSpaceReserved="false"
            app:key="@string/pref_key_b"
            app:title="Test Button B"
            app:useSimpleSummaryProvider="true"
            app:widgetLayout="@layout/my_widget" />
    </PreferenceCategory>
</PreferenceScreen>

科特林:

class SettingsFragment : PreferenceFragmentCompat() {
    private lateinit var _onChildAttachListener : RecyclerView.OnChildAttachStateChangeListener
    private lateinit var _editTextA : EditTextPreference
    private lateinit var _editTextB : EditTextPreference

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

        setPreferencesFromResource(R.xml.root_preferences, rootKey)

        _editTextA = preferenceScreen.findPreference(getString(R.string.pref_key_a))!!
        _editTextB = preferenceScreen.findPreference(getString(R.string.pref_key_b))!!

        _editTextA.setViewId(PREF_A_ID)
        _editTextB.setViewId(PREF_B_ID)

        _onChildAttachListener = object : RecyclerView.OnChildAttachStateChangeListener {
            override fun onChildViewAttachedToWindow(view: View) {
                if(PREF_A_ID == view.id){
                    view.findViewById<ImageButton>(R.id.imageButton).setOnClickListener {
                        Toast.makeText(context, "Button A", Toast.LENGTH_SHORT).show()
                    }
                }
                if(PREF_B_ID == view.id){
                    view.findViewById<ImageButton>(R.id.imageButton).setOnClickListener {
                        Toast.makeText(context, "Button B", Toast.LENGTH_SHORT).show()
                    }
                }
            }
            override fun onChildViewDetachedFromWindow(view: View) {
                // Do nothing..
            }
        }
    }

    override fun onResume() {
        listView.addOnChildAttachStateChangeListener(_onChildAttachListener)
        super.onResume()
    }

    override fun onDestroy() {
        listView.removeOnChildAttachStateChangeListener(_onChildAttachListener)
        super.onDestroy()
    }

    companion object {
        // Note: Set ID's to anything but 0
        const val PREF_A_ID = 1
        const val PREF_B_ID = 2
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.