我在首选项屏幕内创建了一个首选项条目,如下所示:
<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
资源属性有什么想法吗?
这里有一个类似的问题,但没有回答
我似乎也有同样的问题,我尝试了这样的方法:
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;
}
}
<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()
。
onPreferenceTreeClick()
:if (preference instanceof ProgressBarPreference) {
ProgressBar progressBar = ((ProgressBarPreference) preference).getProgressBar();
// TODO something
}
然而,已经一年多了!
我对 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()
取得了一些成功,但这种方法实际上隐藏了整个小部件,而在进度条上设置可见性则留下了一个空白的小部件可见。
这里有一个解决方法:
创建小部件布局并设置 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 属性设置为活动中唯一方法的布局。你觉得怎么样?
我找到了解决此问题的方法,而无需创建自定义首选项。
此解决方案的一个好处是,您可以将相同的小部件资源与不同的侦听器实现(即“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
}
}