How to add a Header and Preference Object to PreferenceActivity not using an XML file but Java?
Asked Answered
A

4

7

I have PreferenceFragment and a PreferenceActivity from which I add headers from a XML file on this way:

PreferenceActivity

@Override
public void onBuildHeaders(List<Header> target) {  
    if(DEBUG) Log.i("PreferenceActivity", "onBuildHeaders() -> LogicAnalizerPrefs");
    if(android.os.Build.VERSION.SDK_INT >= 12) {
        loadHeadersFromResource(R.xml.preference_header_logicanalizer, target);
    }
}

PreferenceFragment:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if(DEBUG) Log.i("PreferenceFragment", "onCreate() -> LogicAnalizerPrefsFragment");
        int res = getActivity().getResources().getIdentifier(getArguments().getString("logicprefsheaders"), "xml", getActivity().getPackageName());
        addPreferencesFromResource(res);
    }

And the XML file where I have the headers is:

R.xml.preference_header_logicanalizer:

<header
        android:fragment="com.protocolanalyzer.andres.LogicAnalizerPrefsFragment"
        android:icon="@drawable/settings"
        android:title="General" >
        <extra
            android:name="logicprefsheaders"
            android:value="logicgeneral" />
    </header>
    <header
        android:fragment="com.protocolanalyzer.andres.LogicAnalizerPrefsFragment"
        android:icon="@drawable/settings"
        android:title="Canal 1" >
        <extra
            android:name="logicprefsheaders"
            android:value="c1analizerprefs" />
    </header>
    <header
        android:fragment="com.protocolanalyzer.andres.LogicAnalizerPrefsFragment"
        android:icon="@drawable/settings"
        android:title="Canal 2" >
        <extra
            android:name="logicprefsheaders"
            android:value="c2analizerprefs" />
    </header>
    <header
        android:fragment="com.protocolanalyzer.andres.LogicAnalizerPrefsFragment"
        android:icon="@drawable/settings"
        android:title="Canal 3" >
        <extra
            android:name="logicprefsheaders"
            android:value="c3analizerprefs" />
    </header>
    <header
        android:fragment="com.protocolanalyzer.andres.LogicAnalizerPrefsFragment"
        android:icon="@drawable/settings"
        android:title="Canal 4" >
        <extra
            android:name="logicprefsheaders"
            android:value="c4analizerprefs" />
    </header>

And this is one of my xml files which is used to display one of the preferences when a Header is clicked:

c1analizerprefs.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <PreferenceCategory android:title="@string/AnalyzerProtocolTitle1" >
        <ListPreference
            android:defaultValue="0"
            android:entries="@array/protocolList"
            android:entryValues="@array/protocolValues"
            android:key="protocol1"
            android:summary="@string/AnalyzerProtocolSummary"
            android:title="@string/AnalyzerProtocolTitle1" />
        <ListPreference
            android:defaultValue="1"
            android:entries="@array/channelNames"
            android:entryValues="@array/protocolValues"
            android:key="SCL1"
            android:summary="@string/AnalyzerSCLSummary"
            android:title="@string/AnalyzerSCLTitle" />

        <EditTextPreference
            android:defaultValue="9600"
            android:title="@string/AnalyzerBaudTitle"
            android:key="BaudRate1"
            android:summary="@string/AnalyzerBaudSummary"
            android:inputType="number" />
    </PreferenceCategory>

</PreferenceScreen>

So in a large screen I have this result as expected and I use only one PreferenceFragment to add my 4 headers.

But my four Preferences defined in the XML like c1analizerprefs.xml are almost the same the only change is a number (For example: Pref. 1, Pref. 2, ...) so I want to add them in Java so I can use a for() to add 4 or more Preferences easily changing the number of repetitions because the text is always the same I only change a number so on this way I don't need to create one XML file for each preference, I create them dynamically in Java.

How can I add a Preference to a Header in Java instead of using a XML file? In PreferenceFragment I only have addPreferencesFromResource() or addPreferencesFromIntent(). Is any way to add a Preference Object?

Adamec answered 1/4, 2013 at 18:53 Comment(0)
W
4

Adding headers dynamically will not be easy. As android documentation states:

Blockquote Typical implementations will use loadHeadersFromResource(int, List) to fill in the list from a resource.

If you still want to go with a dynamic solution, you might want to take a look at the source code of loadHeadersFromResource (for example, here http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceActivity.java#PreferenceActivity.loadHeadersFromResource(int%2Cjava.util.List) )

To sum up,

  1. you need to create a PreferenceActivity.Header object,

  2. prepare it for usage by setting its various properties that can be found in documentation: http://developer.android.com/reference/android/preference/PreferenceActivity.Header.html,

  3. and finally add that created header to the list: target.add(header); (target is the argument that is passed to onBuildHeaders)

Waers answered 10/4, 2013 at 13:42 Comment(1)
Just a side note, I wouldn't consider myself an expert and I find it fairly easy.Sanguine
S
6

Just in case someone is actually looking for some code...

The following example loads some headers from XML and then appends to them programatically.

1st override onBuildHeaders inside your PreferenceActivity:

@Override
public void onBuildHeaders(List<Header> target) {
    loadHeadersFromResource(R.xml.preference_headers, target);

    // Add layer as a new settings header
    Header header = new Header();
    header.title = "More Settings";
    header.summary = "Change even more settings";
    header.fragment = SettingsFragment.class.getName();

    Bundle b = new Bundle();
    b.putString("category", "MoreSettings");
    header.fragmentArguments = b;
    target.add(header);
}

Then override onHeaderClick inside your PreferenceActivity. Note that you pass the header's fragmentArguments to the fragment so you can detect which header was clicked (category):

@Override
public void onHeaderClick(Header header, int position) {    
    this.startPreferencePanel(SettingsFragment.class.getName(), header.fragmentArguments, header.titleRes, header.title, null, 0);
}

Then inside your PreferenceFragment override onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (savedInstanceState == null) {
        mCategory = getArguments().getString("category");
    }
    else {
        // Orientation Change
        mCategory = savedInstanceState.getString("category");
    }

    if (mCategory.equals("Map")) {
        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences_map);
    }
    if (mCategory.equals("MoreSettings")) {
        // Load the preferences from an XML resource
        PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(getActivity());
        // add prefrences using preferenceScreen.addPreference()
        this.setPreferenceScreen(preferenceScreen);
    }
}

In case you want to see the xml for predefined headers.

res/xml/preference_headers.xml

<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    <header 
        android:fragment="com.appName.fragments.SettingsFragment"
        android:title="@string/pref_category_map_title"
        android:summary="@string/pref_category_map_sum" >
        <!-- key/value pairs can be included as arguments for the fragment. -->
        <extra android:name="category" android:value="Map" />
    </header>
</preference-headers>

res/xml/preferences_map.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <CheckBoxPreference
        android:key="pref_zoomToCurrentLocationOnStart"
        android:title="@string/pref_zoomToCurrentLocationOnStart_title"
        android:summary="@string/pref_zoomToCurrentLocationOnStart_sum"
        android:defaultValue="true" />
    <CheckBoxPreference
        android:key="pref_myLocation"
        android:title="@string/pref_myLocation_title"
        android:summary="@string/pref_myLocation_sum"
        android:defaultValue="true" />
</PreferenceScreen>
Sanguine answered 15/1, 2014 at 15:37 Comment(0)
W
4

Adding headers dynamically will not be easy. As android documentation states:

Blockquote Typical implementations will use loadHeadersFromResource(int, List) to fill in the list from a resource.

If you still want to go with a dynamic solution, you might want to take a look at the source code of loadHeadersFromResource (for example, here http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceActivity.java#PreferenceActivity.loadHeadersFromResource(int%2Cjava.util.List) )

To sum up,

  1. you need to create a PreferenceActivity.Header object,

  2. prepare it for usage by setting its various properties that can be found in documentation: http://developer.android.com/reference/android/preference/PreferenceActivity.Header.html,

  3. and finally add that created header to the list: target.add(header); (target is the argument that is passed to onBuildHeaders)

Waers answered 10/4, 2013 at 13:42 Comment(1)
Just a side note, I wouldn't consider myself an expert and I find it fairly easy.Sanguine
T
1

Hopefully I haven't misunderstood your question:

getPreferenceScreen().addPreference( preference );
Toomin answered 8/4, 2013 at 3:10 Comment(5)
If I understand it, on that way I add a Preference not a Header (goo.gl/PZQNQ) that call a Fragment when it is clicked :)Adamec
I have no idea what you just saidToomin
What I need to do is to add Headers in my PreferenceActivity to show a Dual Panel View on tablets and single panel view on smartphones. It is done using an XML file with <header> tag which you assign a Fragment to be called when the header is clicked, but I want to add the headers in Java not from an XML file using addPreferencesFromResource(). For example instead addPreferencesFromResource() something like addHeader(new Header());Adamec
"Is any way to add a Preference Object?" - You need to reword your original question to ask for ways to add a Header instead of a Preference.Toomin
Yeah I don't know how to say it because if I add a Preference in Java I have to add Headers in Java also and the other way around. So I need to add them both.Adamec
J
0

Great answer by @goodies4uall

I will merely add (since i cannot yet edit posts) that you need not do anything fancy in onHeaderClick().

If you wish to add a header outside of onBuildHeaders() the best way to do it is to invalidate them and allow onBuildHeaders() to add the new one when it next fires (invalidateHeaders will cause onBuildHeaders to fire again), like so:

private boolean flagToAddMyNewHeader = false;

public void someEventFiredThatRequiresANewHeader() {
    flagToAddMyNewHeader = true;
    invalidateHeaders();
}

And then your onBuildHeaders:

@Override
public void onBuildHeaders(List<Header> target) {
    loadHeadersFromResource(R.xml.preference_headers, target);

    if (flagToAddMyNewHeader) {
        flagToAddMyNewHeader = false;

        Header header = new Header();
        header.titleRes = R.string.my_new_header_title;
        header.iconRes = R.drawable.my_new_header_icon;
        header.fragment = MyNewHeaderFragment.class.getName();

        Bundle b = new Bundle();
        b.putString("category", "MyNewHeader");
        header.fragmentArguments = b;

        // inserts my new header as the 2nd entry
        target.add(1, header);
    }
}
Jara answered 20/2, 2016 at 5:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.