본문 바로가기
모바일개발(Mobile Dev)/안드로이드개발(Android)

ActionBar and PreferenceActivity headers

by 테크한스 2016. 9. 18.
반응형

Written by https://xisberto.wordpress.com/2014/11/08/how-to-combine-actionbar-and-preferenceactivity-headers-with-appcompat/



How to combine ActionBar and PreferenceActivity headers with AppCompat

Update: This is deprecated. Use the new AppCompatDelegate, it’s way better and easier. Follow the instructions on the Android Developers blog.

Since the introduction of the Support libraries on Android, PreferenceActivity was kept apart, and its new APIs didn’t receive support for older Android versions. Currently, to create a Preferences screen, you have to:

This lead to a situation where you had almost the complete functionality, but no ActionBar for the older versions, and two Activities to handle this.

I was satisfied with the situation, but found some problems with the headers. Then I found this answer on a StackOverflow thread. The trick with the Toolbar worked, and then I take a further step and improved it.

There’s a Github project with this code, I will put some exerts here.

Extend PreferenceActivity

You will create a class extending PreferenceActivity. This will be the only Activity you will need for your Preferences. During the onCreate, apply the solution from the StackOverflow linked above:

 ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
 View content = root.getChildAt(0);
 LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.activity_prefs, null);

 root.removeAllViews();
 toolbarContainer.addView(content);
 root.addView(toolbarContainer);

What this code does:

  1. Gets a reference to the Activity’s content (android.R.id.content)
  2. Inflates a layout made of a LinearLayout and a Toolbar (from the appcompat support library)
  3. Removes all views from the root view
  4. Adds the Activity’s content (android.R.id.content) to the inflated layout
  5. Adds the inflated layout to the root view

After this, we can

Setup the Toolbar

mToolBar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar);
    mToolBar.setTitle(getTitle());
    mToolBar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
    mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            finish();
        }
    });

This code set the Toolbar title to the Activiy’s title and adds a up navigation icon that finishes the Activity. The drawable used is part of the appcompat library.

Setup the PreferenceFragment

We can configure the PreferenceFragment as explained on the API Guides, and make it load the preferences screens according to the Extra defined on the header’s XML.

res/xml/headers.xml:

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    <header
        android:title="@string/header_general"
        android:fragment="net.xisberto.preferencescompat.PrefsFragment" >
            <extra
                android:name="category"
                android:value="category_general" />
    </header>
    <header
        android:title="@string/header_advanced"
        android:fragment="net.xisberto.preferencescompat.PrefsFragment" >
            <extra
                android:name="category"
                android:value="category_advanced" />
    </header>
</preference-headers>

src/net.xisberto.preferencescompat/PrefsFragment.java:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class PrefsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String category = getArguments().getString("category");
        if (category != null) {
            if (category.equals(getString(R.string.category_general))) {
                addPreferencesFromResource(R.xml.prefs_general);
            } else if (category.equals(getString(R.string.category_advanced))) {
                addPreferencesFromResource(R.xml.prefs_advanced);
            }
        }
    }
}
Preferences on Lollipop

Preferences on Lollipop

.

Adding support to older versions

For the versions before Honeycomb (3.0), we use the PreferenceActivity’s addPreferencesFromResource. This will be marked as deprecated, but it’s ok.

This code can be called during the Activity’s OnCreate method.

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
    String action = getIntent().getAction();
    if (action == null) {
        addPreferencesFromResource(R.xml.headers_legacy);
    } else if (action.equals(getString(R.string.category_general))) {
        mToolBar.setTitle(getString(R.string.header_general));
        addPreferencesFromResource(R.xml.prefs_general);
    } else if (action.equals(getString(R.string.category_advanced))) {
        mToolBar.setTitle(getString(R.string.header_general));
        addPreferencesFromResource(R.xml.prefs_advanced);
    }
 }

This code analyses the Action posted to the Activity. A null Action will show a PreferenceScreen that emulates the preference-headers above, with Preferencesthat call Intents.

Preferences on Gingerbread

Preferences on Gingerbread

Final Toughts

On tablets, the selected header will be colored according to the colorAccentdefined on your theme extending Theme.AppCompat. Look at the styles.xml for a very simple theme.

tablet_prefs

This code lets two things unresolved:

  1. There’s no shadow on the Toolbar. This can be resolved on the activity_prefs layout.
  2. On pre-Honeycomb tablets (there are a few of them), will be no two-pane layout, since the legacy code doesn’t support it.

If you need another explanation don’t be afraid of commenting, but take also a time to look on the Github project.



반응형