My requirements
Note: I need to support Android API 15 and onwards.
In my PreferenceFragment I am dynamically adding PreferenceScreen's to a PreferenceCategory.
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
myCategory.addPreference(as);
When the settings Activity renders these PreferenceScreens are rendered with just a title in it's row, see the image below.
I want to customize what is shown in this row. Ideally I would like to have a title with a summary below, an icon to the left of the title/summary and on certain rows an icon on the right hand side. See the mockup image below.
PreferenceScreen.setWidgetLayoutResource(int widgetLayoutResId)
I know I can use "setWidgetLayoutResource" to add an icon to the right of the row layout (and a summary with "setSummary") using the following code in my settings activity
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
as.setWidgetLayoutResource(R.layout.as_widget);
myCategory.addPreference(as);
where "as_widget.xml" is
<?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"/>
this will produce UI like the following
This gets me closer to what I would like but still not exactly what I would like (missing the icon at the beginning of the row).
PreferenceScreen.setLayoutResource(int layoutResId)
I believe if I use this, then I can control the rendering of the whole row. I have seen examples of this on stackoverflow, such as
From my understanding the layout file you specify has to have the following
- its root View with the id "@android:id/widget_frame"
- a view with the id android:id="@+android:id/title" (this is where the string specified in PreferenceScreen.setTitle is placed)
- a view with the id android:id="@+android:id/summary" (this is where the string specified in PreferenceScreen.setSummary is placed)
However when I try and do this, Android Studio highlights "@+android:id/summary" with the error "Can not resolve symbol '@+android:id/summary'. When the application runs my rows are rendered completely blank.
My java is
PreferenceScreen as = mgr.createPreferenceScreen(context);
as.setTitle(name);
as.setSummary(summary);
as.setLayoutResource(R.layout.as_row_layout);
myCategory.addPreference(as);
And my layout is
<?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>
Extending PreferenceScreen
I looked at extended PreferenceScreen to overwrite how it renders, but it appears this class has now been made final so all examples on the internet that do it that way can not be used.
I have managed to get this working.
The
Preference
class usescom.android.internal.R.layout.preference
as its layout. This contains an ImageView for an icon on the left hand side, then the title and summary textviews and finally awidget_frame
Layout on the right hand side.By calling "
PreferenceScreen.setIcon(..)
" you can set the drawable to place in the icon image view. By callingPreferenceScreen.setWidgetLayoutResource("...")
you can set the layout to place in thewidget_frame
layout, in my case I put an ImageView layout containing my image.Here is my Java code.
This produces a layout like the following
The problem with this layout is that the icons do not left align with the text of the preferences below which have no icons.
This can be resolved by specifying the layout for the
PreferenceScreen
as well. I copied Android'spreference.xml
into my project (renaming it appropriately for my usecase) and I changing the ImageView to have a left padding and margin of 0dp.From
to
I then specified my copy of
preference.xml
for the PreferenceScreen's layout. So my java is nowI believe the reason my original attempt at using
PreferenceScreen.setLayoutResource
was not working was because the layout I specified was incorrect. The incorrect layout had the whole layout with an id of@android:id/widget_frame
, i.e.The correct layout does not need an id for the main layout, but needs to contain child views with ids of
@+android:id/icon
,@+android:id/title
,@+android:id/summary
,@+android:id/widget_frame
, i.e.You can also customise the layout of a Preference by overriding
Preference.onCreateView(parent)
. The example below uses an anonymous inner class to make red preferences.