Add a Toolbar to a PreferenceActivity

When trying to move a playground to Material Design, I stumbled upon the new Toolbar widget, which is supposed to replace the ActionBar (well, that’s my understanding from all the posts I’ve read). Thing is, the Toolbar is designed to be added to an Activity. To do that, the Activity class has a new method public void setActionBar (Toolbar toolbar) since API 21.

The problem

Adding the Toolbar to an activity is easy and documented in all sources implementing material design on github. However, Adding an action bar to a PreferenceActivity, is nowhere to be found. You can add a Toolbar alright, but PreferenceActivity has no setActionBar() method available.

My solution

My approach was to replicate the functionality of the ActionBar, particularly the menu interactions. What I needed was a way to display a menu (an About menu in my case) and trigger the relevant action on click.

I’ll split the implementation in two parts; the layout components and the Java implementation.

Layout

The layout has four parts:

  1. The menu: This is quite simple as I only require an About component:

    You may want to extend it to suit your needs.

  2. The toolbar: It has the empty toolbar:

  3. The preferences layout: It includes the toolbar and a ListView for the preferences:

  4. The Preferences components: In my case, I have a headers with multiple fragments:

The java implementation

As you can figure out from the above XML files, I intend to use a programmatic approach to enabling this functionality. It will involve a listener to the menu actions. To make my life easier, I’ll make my class implement the relevant listener:

Using butterknife, I’ll have a reference to the toolbar

All the UI is done in onPostCreate() (parts of it are from Jake Wharton’s U+2020). First, I’m setting up the preferences and enable ButterKnife:

Then I’m inflating the menu in the toolbar and register the listened to the toolbar itself:

Then, I’m implementing the listener method:

This way, when the About menu is clicked, the application will display a screen with about information, using Mike Penz’s awesome AboutLibraries.

This is it. You can customise the menu and its listener. You can probably include the toolbar layout in the preferences layout too but I haven’t tried it.

Alternatives

Depending on the complexity of your preferences, you may choose to bypass the PreferenceActivity class altogether and use Activity instead (like here, here, or here). This approach is definitely cleaner and easier, but it doesn’t offer the perks of PreferenceActivity with multiple fragments.

Another, hack-ier solution would be to implement your own PreferenceActivity similar to this implementation. I tried this variant but stopped after a couple of hours’ work.


A little experiment: If you find this post and ad below useful, please check the ad out :-)




10 thoughts on “Add a Toolbar to a PreferenceActivity

      1. I don’t see how this can work.While it displays the headers ok, clicking on any of those headers displays a blank screen as the PreferenceActivity class attempts to display the PreferenceFragment into R.id.prefs which doesn’t exist in R.layout.preferences. And you can’t just add R.id.prefs as it is private and is looking for it in the ‘android’ scope, so you can add it either.

        1. Hmm. The setupSimplePreferencesScreen() from Vogella is supposed to replace the headers with the actual content of the fragments (each in its own PreferenceCategory), not the headers themselves. To display the headers and have them display the fragment content when clicked you don’t need all this. You can just implement the code executed when #isSimplePreferences is false. However, if I remember correctly, the fragments themselves won't have the Toolbar.

  1. Solution worked well but I keep getting this error:

    Caused by: java.lang.IllegalArgumentException: No view found for id 0x1020359 (android:id/prefs) for fragment ThemePrefFragment

    when trying to open a Fragment from the headers. Any idea why?

    1. I’m not 100% sure what could cause this without a closer look at the code/full stack trace. When I got the same error a while ago it was because of using copy/paste and had a different layout. Maybe this or this can be of some help.

  2. I am also getting the no view found for (android:id/prefs) error when I click on a header link.
    It would be nice to see how the fragment EffectsPreferenceFragment coded to handle this. Although I used the AppCompatDelegate instead. The resulting code is quite similar.

    I think your code is working maybe because you do not have onCreate method and you are issuing setContentView in onPostCreate.

    I passed the no view found error for android:id/prefs now but I have new problems. Are you sure this code works? :D

    1. It’s been a while since I looked at this… I remember reading somewhere that onPostCreate() is called at the right time and onCreate() doesn’t have the right information.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to top