自定义 PreferenceScreen 的布局
Customizing the layout of a PreferenceScreen
我的要求
注意:我需要支持Android API 15及以上
在我的 PreferenceFragment 中,我将 PreferenceScreen 动态添加到 PreferenceCategory。
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
myCategory.addPreference(as);
当设置 Activity 呈现这些 PreferenceScreens 时,它们的行中只有一个标题,请参见下图。
我想自定义此行中显示的内容。理想情况下,我希望有一个标题,下面有一个摘要,title/summary 左侧有一个图标,某些行的图标在右侧。请参阅下面的模型图像。
PreferenceScreen.setWidgetLayoutResource(int widgetLayoutResId)
我知道我可以使用 "setWidgetLayoutResource" 在我的设置中使用以下代码在行布局的右侧添加一个图标(以及 "setSummary" 的摘要)activity
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
as.setWidgetLayoutResource(R.layout.as_widget);
myCategory.addPreference(as);
其中 "as_widget.xml" 是
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_favorite"/>
这将产生如下所示的 UI
这让我更接近我想要的,但仍然不是我想要的(缺少行开头的图标)。
PreferenceScreen.setLayoutResource(int layoutResId)
我相信如果我使用这个,那么我可以控制整行的渲染。我在 Whosebug 上看到过这样的例子,比如
- Setting preference layout and changing the attribute in it
- Creating a custom layout for preferences
根据我的理解,您指定的布局文件必须具有以下内容
- 其根视图,id 为“@android:id/widget_frame”
- ID 为 android:id="@+android:id/title" 的视图(这是
PreferenceScreen.setTitle 中指定的字符串被放置)
- ID 为 android:id="@+android:id/summary" 的视图(这是
PreferenceScreen.setSummary中指定的字符串被放置)
然而,当我尝试执行此操作时,Android Studio 突出显示“@+android:id/summary”并显示错误“无法解析符号‘@+android:id/summary'。当应用程序运行时,我的行呈现为完全空白。
我的java是
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
as.setLayoutResource(R.layout.as_row_layout);
myCategory.addPreference(as);
而我的布局是
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<ImageView
android:id="@+id/icon1"
android:src="@drawable/ic_action_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="@+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignLeft="@android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="4" />
</RelativeLayout>
<ImageView
android:id="@+id/icon2"
android:src="@drawable/ic_action_favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
扩展首选项屏幕
我查看了扩展的 PreferenceScreen 以覆盖它的呈现方式,但看起来这个 class 现在已经成为最终版本,所以互联网上所有这样做的例子都不能使用。
我已经设法让它工作了。
Preference
class 使用 com.android.internal.R.layout.preference
作为布局。这包含左侧图标的 ImageView,然后是标题和摘要文本视图,最后是右侧的 widget_frame
布局。
通过调用“PreferenceScreen.setIcon(..)
”,您可以将可绘制对象设置为放置在图标图像视图中。通过调用 PreferenceScreen.setWidgetLayoutResource("...")
,您可以将布局设置为放置在 widget_frame
布局中,在我的例子中,我放置了一个包含我的图像的 ImageView 布局。
这是我的 Java 代码。
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
// add an icon to the PreferenceScreen,
// this is rendered on the left hand side of the row
accountScreen.setIcon(R.drawable.my_pref_icon);
// specify the layout to inflate into the widget area on the
// right hand side of the row, this layout is just my image
as.setWidgetLayoutResource(R.layout.as_widget);
myCategory.addPreference(as);
这会生成如下所示的布局
此布局的问题是图标没有与下面没有图标的首选项文本左对齐。
这也可以通过指定 PreferenceScreen
的布局来解决。我将 Android 的 preference.xml
复制到我的项目中(为我的用例适当地重命名它)并且我将 ImageView 更改为具有 0dp 的左填充和边距。
来自
<ImageView
android:id="@+android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
到
<ImageView
android:id="@+android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="0dp"
android:layout_marginLeft="0dp"/>
然后我为 PreferenceScreen 的布局指定了我的 preference.xml
副本。所以我的 java 现在是
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
// add an icon to the PreferenceScreen,
// this is rendered on the left hand side of the row
accountScreen.setIcon(R.drawable.my_pref_icon);
// specify the layout to inflate into the widget area on the
// right hand side of the row, this layout is just my image
as.setWidgetLayoutResource(R.layout.as_widget);
// specify the layout for the preference screen row when it is
// rendered as a row in a preference activity/fragment
as.setLayoutResource(R.layout.preference_row_layout);
myCategory.addPreference(as);
我认为我最初尝试使用 PreferenceScreen.setLayoutResource
失败的原因是我指定的布局不正确。不正确的布局具有 整个布局 的 ID 为 @android:id/widget_frame
,即
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame" ...>
.....
</LinearLayout>
正确的布局不需要主布局的 ID,但需要包含 ID 为 @+android:id/icon
、[=28 的 child views =]、@+android:id/summary
、@+android:id/widget_frame
,即
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
....>
<ImageView android:id="@+android:id/icon" ....>
....
<TextView android:id="@+android:id/title" ...>
....
<TextView android:id="@+android:id/summary" ...>
....
<LinearLayout android:id="@+android:id/widget_frame" ..>
....
</LinearLayout>
您还可以通过覆盖 Preference.onCreateView(parent)
来自定义首选项的布局。下面的示例使用匿名内部 class 来设置红色首选项。
screen.addPreference(
new Preference(context) {
@Override
protected View onCreateView(ViewGroup parent) {
View view = super.onCreateView(parent);
view.setBackgroundColor(Color.RED);
return view;
}
});
我的要求
注意:我需要支持Android API 15及以上
在我的 PreferenceFragment 中,我将 PreferenceScreen 动态添加到 PreferenceCategory。
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
myCategory.addPreference(as);
当设置 Activity 呈现这些 PreferenceScreens 时,它们的行中只有一个标题,请参见下图。
我想自定义此行中显示的内容。理想情况下,我希望有一个标题,下面有一个摘要,title/summary 左侧有一个图标,某些行的图标在右侧。请参阅下面的模型图像。
PreferenceScreen.setWidgetLayoutResource(int widgetLayoutResId)
我知道我可以使用 "setWidgetLayoutResource" 在我的设置中使用以下代码在行布局的右侧添加一个图标(以及 "setSummary" 的摘要)activity
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
as.setWidgetLayoutResource(R.layout.as_widget);
myCategory.addPreference(as);
其中 "as_widget.xml" 是
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_favorite"/>
这将产生如下所示的 UI
这让我更接近我想要的,但仍然不是我想要的(缺少行开头的图标)。
PreferenceScreen.setLayoutResource(int layoutResId)
我相信如果我使用这个,那么我可以控制整行的渲染。我在 Whosebug 上看到过这样的例子,比如
- Setting preference layout and changing the attribute in it
- Creating a custom layout for preferences
根据我的理解,您指定的布局文件必须具有以下内容
- 其根视图,id 为“@android:id/widget_frame”
- ID 为 android:id="@+android:id/title" 的视图(这是 PreferenceScreen.setTitle 中指定的字符串被放置)
- ID 为 android:id="@+android:id/summary" 的视图(这是 PreferenceScreen.setSummary中指定的字符串被放置)
然而,当我尝试执行此操作时,Android Studio 突出显示“@+android:id/summary”并显示错误“无法解析符号‘@+android:id/summary'。当应用程序运行时,我的行呈现为完全空白。
我的java是
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
as.setLayoutResource(R.layout.as_row_layout);
myCategory.addPreference(as);
而我的布局是
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<ImageView
android:id="@+id/icon1"
android:src="@drawable/ic_action_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="@+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignLeft="@android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="4" />
</RelativeLayout>
<ImageView
android:id="@+id/icon2"
android:src="@drawable/ic_action_favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
扩展首选项屏幕
我查看了扩展的 PreferenceScreen 以覆盖它的呈现方式,但看起来这个 class 现在已经成为最终版本,所以互联网上所有这样做的例子都不能使用。
我已经设法让它工作了。
Preference
class 使用 com.android.internal.R.layout.preference
作为布局。这包含左侧图标的 ImageView,然后是标题和摘要文本视图,最后是右侧的 widget_frame
布局。
通过调用“PreferenceScreen.setIcon(..)
”,您可以将可绘制对象设置为放置在图标图像视图中。通过调用 PreferenceScreen.setWidgetLayoutResource("...")
,您可以将布局设置为放置在 widget_frame
布局中,在我的例子中,我放置了一个包含我的图像的 ImageView 布局。
这是我的 Java 代码。
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
// add an icon to the PreferenceScreen,
// this is rendered on the left hand side of the row
accountScreen.setIcon(R.drawable.my_pref_icon);
// specify the layout to inflate into the widget area on the
// right hand side of the row, this layout is just my image
as.setWidgetLayoutResource(R.layout.as_widget);
myCategory.addPreference(as);
这会生成如下所示的布局
此布局的问题是图标没有与下面没有图标的首选项文本左对齐。
这也可以通过指定 PreferenceScreen
的布局来解决。我将 Android 的 preference.xml
复制到我的项目中(为我的用例适当地重命名它)并且我将 ImageView 更改为具有 0dp 的左填充和边距。
来自
<ImageView
android:id="@+android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
到
<ImageView
android:id="@+android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="0dp"
android:layout_marginLeft="0dp"/>
然后我为 PreferenceScreen 的布局指定了我的 preference.xml
副本。所以我的 java 现在是
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
// add an icon to the PreferenceScreen,
// this is rendered on the left hand side of the row
accountScreen.setIcon(R.drawable.my_pref_icon);
// specify the layout to inflate into the widget area on the
// right hand side of the row, this layout is just my image
as.setWidgetLayoutResource(R.layout.as_widget);
// specify the layout for the preference screen row when it is
// rendered as a row in a preference activity/fragment
as.setLayoutResource(R.layout.preference_row_layout);
myCategory.addPreference(as);
我认为我最初尝试使用 PreferenceScreen.setLayoutResource
失败的原因是我指定的布局不正确。不正确的布局具有 整个布局 的 ID 为 @android:id/widget_frame
,即
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame" ...>
.....
</LinearLayout>
正确的布局不需要主布局的 ID,但需要包含 ID 为 @+android:id/icon
、[=28 的 child views =]、@+android:id/summary
、@+android:id/widget_frame
,即
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
....>
<ImageView android:id="@+android:id/icon" ....>
....
<TextView android:id="@+android:id/title" ...>
....
<TextView android:id="@+android:id/summary" ...>
....
<LinearLayout android:id="@+android:id/widget_frame" ..>
....
</LinearLayout>
您还可以通过覆盖 Preference.onCreateView(parent)
来自定义首选项的布局。下面的示例使用匿名内部 class 来设置红色首选项。
screen.addPreference(
new Preference(context) {
@Override
protected View onCreateView(ViewGroup parent) {
View view = super.onCreateView(parent);
view.setBackgroundColor(Color.RED);
return view;
}
});