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
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 uses com.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 a widget_frame
Layout on the right hand side.
By calling "PreferenceScreen.setIcon(..)
" you can set the drawable to place in the icon image view. By calling PreferenceScreen.setWidgetLayoutResource("...")
you can set the layout to place in the widget_frame
layout, in my case I put an ImageView layout containing my image.
Here is my Java code.
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);
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's preference.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
<ImageView
android:id="@+android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
to
<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"/>
I then specified my copy of preference.xml
for the PreferenceScreen's layout. So my java is now
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);
I 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.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame" ...>
.....
</LinearLayout>
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.
<?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>