25

I found a workaround to actually enable the ActionBar home button on the nested PreferenceScreen... however it doesn't call OnOptionsItemSelected in my PreferenceActivity. Anyone know a way to actually use the home button on a nested PreferenceScreen?

Modification of post 35 here:

http://code.google.com/p/android/issues/detail?id=4611

@Override
    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
    {
        super.onPreferenceTreeClick(preferenceScreen, preference);
        if (preference!=null)
            if (preference instanceof PreferenceScreen)
                if (((PreferenceScreen)preference).getDialog()!=null)
                    ((PreferenceScreen)preference).getDialog().getActionBar().setHomeButtonEnabled(true);
        return false;
    }
jsstp24n5
  • 594
  • 1
  • 6
  • 13

1 Answers1

46

I had this problem recently and this is how I solved it. Firstly to access the PreferenceScreen I use the exact same method you mentioned above.

@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
    super.onPreferenceTreeClick(preferenceScreen, preference);

    // If the user has clicked on a preference screen, set up the action bar
    if (preference instanceof PreferenceScreen) {
        initializeActionBar((PreferenceScreen) preference);
    }

    return false;
}

From here I looked into what a PreferenceScreen is, and I was saddened to find out it is just wrapper of a Dialog. Moving forward, I then set the actionbar display options and attempt find the home button area. This unfortunately wasn't too easy to get, but with the help of the hierarchy viewer I managed to gain access by finding the home icon and then its parent views. Once we have access to the containing LinearLayout, we can attach an onClickListener where we dismiss the PreferenceScreen's dialog, which calls PreferenceScreen's onDismissListener and returns us to the previous screen.

/** Sets up the action bar for an {@link PreferenceScreen} */
public static void initializeActionBar(PreferenceScreen preferenceScreen) {
    final Dialog dialog = preferenceScreen.getDialog();

    if (dialog != null) {
        // Inialize the action bar
        dialog.getActionBar().setDisplayHomeAsUpEnabled(true);

        // Apply custom home button area click listener to close the PreferenceScreen because PreferenceScreens are dialogs which swallow
        // events instead of passing to the activity
        // Related Issue: https://code.google.com/p/android/issues/detail?id=4611
        View homeBtn = dialog.findViewById(android.R.id.home);

        if (homeBtn != null) {
            OnClickListener dismissDialogClickListener = new OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialog.dismiss();
                }
            };

            // Prepare yourselves for some hacky programming
            ViewParent homeBtnContainer = homeBtn.getParent();

            // The home button is an ImageView inside a FrameLayout
            if (homeBtnContainer instanceof FrameLayout) {
                ViewGroup containerParent = (ViewGroup) homeBtnContainer.getParent();

                if (containerParent instanceof LinearLayout) {
                    // This view also contains the title text, set the whole view as clickable
                    ((LinearLayout) containerParent).setOnClickListener(dismissDialogClickListener);
                } else {
                    // Just set it on the home button
                    ((FrameLayout) homeBtnContainer).setOnClickListener(dismissDialogClickListener);
                }
            } else {
                // The 'If all else fails' default case
                homeBtn.setOnClickListener(dismissDialogClickListener);
            }
        }    
    }
}
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
jimmithy
  • 6,360
  • 2
  • 31
  • 29
  • 1
    Thank you, I've just checked and this works. I'd like to see this answer as accepted as I've not found another working solution. – eigenein Jun 16 '13 at 11:04
  • 1
    Does passing the dismissDialogClickListener to the setOnClickListener method on the actual homeBtn View not work? – jsstp24n5 Jul 10 '13 at 02:07
  • 1
    It does, but the selectable area is only the image in that case. By using the parent, the selectable area is the same as the default android action bar so it replicates the pressed state etc. I amended my above answer to provide a default case. – jimmithy Jul 10 '13 at 02:31
  • A comment from Flynn81 in this thread shows that as of 4.2.2 the default case is for title and icon. Before that it was just the icon so that was what was confusing to me :) http://stackoverflow.com/questions/7981394/how-can-i-detect-a-click-on-the-actionbar-title – jsstp24n5 Jul 10 '13 at 03:05
  • What to do when setDisplayShowHomeEnabled is set to false (i.e. app icon is hidden)? – Miša Peić Aug 19 '13 at 16:40
  • As long as setDisplayHomeAsUpEnabled is set as true in initializeActionBar(), it should show the up carat as needed. – jimmithy Aug 19 '13 at 18:49
  • Sorry, my question was incomplete. This is the code: dialog.getActionBar().setDisplayHomeAsUpEnabled(true); dialog.getActionBar().setDisplayShowHomeEnabled(false); ... and up carat is shown, but clickListener is not working. – Miša Peić Aug 20 '13 at 10:05
  • 2
    setDisplayHomeAsUpEnabled shows the up carat, but setting setDisplayShowHomeEnabled as false disables the clickable region. You should be able to hide the icon in other ways such as setDisplayUseLogoEnabled(false), and if that doesn't work there are plenty of alternatives if you give StackOverflow a quick search :) – jimmithy Aug 20 '13 at 13:28
  • getActionBar() returns null in appcompat-v7 21. Any solution? – Petrakeas Dec 08 '14 at 12:32
  • 2
    @Petrakeas @TalkLittle see my answer here for a possible solution `:)` http://stackoverflow.com/a/27455363/566127 – David Passmore Jun 10 '15 at 12:47
  • Thank you so much, life saver. Wasted all day trying to get a hold of that nested screen action bar. – Gubatron Jul 29 '15 at 00:21
  • @jimmithy what would be the license for your snippet (beside the default CC-BY-SA of SO) ? – Philippe Ombredanne Sep 16 '16 at 16:30
  • 1
    @PhilippeOmbredanne I consider it under the beerware license, as long as all claimants didn't exercise at once. – jimmithy Sep 16 '16 at 20:07
  • @jimmithy : you are a prince, albeit may be a drunk prince! – Philippe Ombredanne Sep 16 '16 at 23:17