2013-02-01 18 views
21

Sto utilizzando le intestazioni delle preferenze per creare attività delle impostazioni utilizzando PreferenceActivity. Sto cercando di dividere le intestazioni in categorie/gruppi, come questo (ci sono le categorie Wireless Networks &, periferiche, personale, ...):Come creare gruppi di intestazioni di preferenza in Android PreferenceActivity?

In ogni caso, anche questo sito Android Developers è di circa in questo modo di creare attività di preferenza, non sono riuscito a trovare in alcun modo come creare le stesse attività delle preferenze come hanno nell'immagine. L'unica cosa che sono riuscito a fare è un semplice elenco di intestazioni delle preferenze.

L'unica cosa che ho trovato è this, ma funziona un po '... strano. Quindi non sembra un'opzione.

Quindi la mia domanda è: come creare PreferenceActivity utilizzando le intestazioni di preferenza con possibilità di dividere intestazioni in categorie e con possibilità di utilizzare interruttori on/off master?

Alcuni del mio codice:

preference_headers.xml:

<?xml version="1.0" encoding="utf-8"?> 
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> 
    <header 
     android:fragment="cz.vse.myevents.activity.SettingsActivity$EventsFragment" 
     android:title="@string/settings_events" 
     android:icon="@android:drawable/ic_menu_agenda" /> 
    <header 
     android:fragment="cz.vse.myevents.activity.SettingsActivity$OrganizationsFragment" 
     android:title="@string/settings_subscribed_organizations" 
     android:icon="@android:drawable/ic_menu_view" /> 
</preference-headers> 

SettingsActivity:

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

io non sto inviando frammenti risorse, penso che sia inutile.

risposta

5

Sembra che la soluzione migliore sia la creazione di tre diversi blocchi di codice: uno per pre-Honeycomb, uno per Post-Honeycomb e uno per tablet.

L'utilizzo delle intestazioni delle preferenze è efficace solo sui tablet, quindi rimangono solo sui tablet. Nessun raggruppamento è usato qui.

Le intestazioni di preferenza su post-Honeycomb sono piuttosto inutili, quindi il migliore è l'utilizzo del tipico PreferenceScreen in un PreferenceFragment. I gruppi possono essere resi facilmente da PreferenceCategory.

E infine, per il pre-Honeycomb, il modo deprecato senza utilizzare PrefrenceFragment è l'unico modo.

Purtroppo c'è molta duplicazione del codice, ma la libreria UnifiedPreference menzionata nella risposta di Leandros è buggy: ignora completamente lo PreferenceFragment quindi è inutile (almeno per me).

+0

Vedere la mia risposta qui http://stackoverflow.com/a/20806812/1139784 su come ridurre parte della duplicazione del codice. –

6

Penso che quello che hai trovato in Xavier Gouchet site è il modo in cui dobbiamo farlo. Ho guardato il codice sorgente nell'app delle impostazioni di Android e this is ciò che Gouchet ha estratto. L'ho adattato per i miei scopi (escludendo l'interruttore di abilitazione audio) e ho ottenuto l'intestazione di categoria con la linea di divisione.

Spero che l'API di Android per le impostazioni sarà migliorata per supportare presto le categorie. Non dovrebbe essere così difficile.

+1

Più di un anno dopo e ancora niente. Sembra quasi ridicolo che la schermata delle impostazioni di base che tutti vedono non abbia un modo semplice per aggiungere categorie. – Mgamerz

+0

link non valido e la risposta non fornisce informazioni reali. –

-1

implementazione settings_headers.xml AOSP:

<preference-headers 
     xmlns:android="http://schemas.android.com/apk/res/android"> 


    <!-- WIRELESS and NETWORKS --> 
    <header android:title="@string/header_category_wireless_networks" /> 

    <!-- Wifi --> 
    <header 
     android:id="@+id/wifi_settings" 
     android:fragment="com.android.settings.wifi.WifiSettings" 
     android:title="@string/wifi_settings_title" 
     android:icon="@drawable/ic_settings_wireless" /> 

    <!-- Bluetooth --> 
    <header 
     android:id="@+id/bluetooth_settings" 
     android:fragment="com.android.settings.bluetooth.BluetoothSettings" 
     android:title="@string/bluetooth_settings_title" 
     android:icon="@drawable/ic_settings_bluetooth2" /> 

    <!-- Data Usage --> 
    <header 
     android:id="@+id/data_usage_settings" 
     android:fragment="com.android.settings.DataUsageSummary" 
     android:title="@string/data_usage_summary_title" 
     android:icon="@drawable/ic_settings_data_usage" /> 

    <!-- Operator hook --> 
    <header 
     android:fragment="com.android.settings.WirelessSettings" 
     android:id="@+id/operator_settings"> 
     <intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" /> 
    </header> 

    <!-- Other wireless and network controls --> 
    <header 
     android:id="@+id/wireless_settings" 
     android:title="@string/radio_controls_title" 
     android:breadCrumbTitle="@string/wireless_networks_settings_title" 
     android:fragment="com.android.settings.WirelessSettings" 
     android:icon="@drawable/empty_icon" /> 

    <!-- Ethernet --> 
    <header 
     android:id="@+id/ethernet_settings" 
     android:title="@string/eth_radio_ctrl_title" 
     android:icon="@drawable/ic_settings_ethernet" 
     android:fragment="com.android.settings.ethernet.EthernetSettings"/> 

    <!-- DEVICE --> 
    <header android:title="@string/header_category_device" /> 

    <!-- Sound --> 
    <header 
     android:id="@+id/sound_settings" 
     android:icon="@drawable/ic_settings_sound" 
     android:fragment="com.android.settings.SoundSettings" 
     android:title="@string/sound_settings" /> 

    <!-- Display --> 
    <header 
     android:id="@+id/display_settings" 
     android:icon="@drawable/ic_settings_display" 
     android:fragment="com.android.settings.DisplaySettings" 
     android:title="@string/display_settings" /> 

    <!-- Storage --> 
    <header 
     android:id="@+id/storage_settings" 
     android:fragment="com.android.settings.deviceinfo.Memory" 
     android:icon="@drawable/ic_settings_storage" 
     android:title="@string/storage_settings" /> 

    <!-- Battery --> 
    <header 
     android:id="@+id/battery_settings" 
     android:fragment="com.android.settings.fuelgauge.PowerUsageSummary" 
     android:icon="@drawable/ic_settings_battery" 
     android:title="@string/power_usage_summary_title" /> 

    <!-- Application Settings --> 
    <header 
     android:fragment="com.android.settings.applications.ManageApplications" 
     android:icon="@drawable/ic_settings_applications" 
     android:title="@string/applications_settings" 
     android:id="@+id/application_settings" /> 

    <!-- TEMPORARY FACTORY STARTER WILL BE REMOVED WITH UPDATED SETTINGS --> 
    <header 
     android:icon="@drawable/ic_settings_applications" 
     android:title="Factory" 
     android:id="@+id/application_settings" > 
     <intent android:action="android.intent.action.MAIN" 
       android:targetPackage="com.jamdeo.tv.sample.factory" 
       android:targetClass="com.jamdeo.tv.sample.factory.TvFactoryMainActivity" /> 
    </header> 

    <!-- Manufacturer hook --> 
    <header 
     android:fragment="com.android.settings.WirelessSettings" 
     android:id="@+id/manufacturer_settings"> 
     <intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" /> 
    </header> 


    <!-- PERSONAL --> 
    <header android:title="@string/header_category_personal" /> 

    <!-- Data Sync. The settings activity will ensure this is resolved to an 
     activity on the system image, otherwise it will remove this 
     preference. --> 
    <header 
     android:fragment="com.android.settings.accounts.ManageAccountsSettings" 
     android:icon="@drawable/ic_settings_sync" 
     android:title="@string/sync_settings" 
     android:id="@+id/sync_settings" /> 

    <!-- Location --> 
    <header 
     android:fragment="com.android.settings.LocationSettings" 
     android:icon="@drawable/ic_settings_location" 
     android:title="@string/location_settings_title" 
     android:id="@+id/location_settings" /> 

    <!-- Security --> 
    <header 
     android:fragment="com.android.settings.SecuritySettings" 
     android:icon="@drawable/ic_settings_security" 
     android:title="@string/security_settings_title" 
     android:id="@+id/security_settings" /> 

    <!-- Language --> 
    <header 
     android:id="@+id/language_settings" 
     android:fragment="com.android.settings.inputmethod.InputMethodAndLanguageSettings" 
     android:icon="@drawable/ic_settings_language" 
     android:title="@string/language_settings" /> 

    <!-- Backup and reset --> 
    <header 
     android:fragment="com.android.settings.PrivacySettings" 
     android:icon="@drawable/ic_settings_backup" 
     android:title="@string/privacy_settings" 
     android:id="@+id/privacy_settings" /> 


    <!-- SYSTEM --> 
    <header android:title="@string/header_category_system" /> 

    <!-- Dock --> 
    <header 
     android:id="@+id/dock_settings" 
     android:fragment="com.android.settings.DockSettings" 
     android:icon="@drawable/ic_settings_dock" 
     android:title="@string/dock_settings" /> 

    <!-- Date & Time --> 
    <header 
     android:id="@+id/date_time_settings" 
     android:fragment="com.android.settings.DateTimeSettings" 
     android:icon="@drawable/ic_settings_date_time" 
     android:title="@string/date_and_time_settings_title" /> 

    <!-- Accessibility feedback --> 
    <header 
     android:id="@+id/accessibility_settings" 
     android:fragment="com.android.settings.AccessibilitySettings" 
     android:icon="@drawable/ic_settings_accessibility" 
     android:title="@string/accessibility_settings" /> 

    <!-- Development --> 
    <header 
     android:id="@+id/development_settings" 
     android:fragment="com.android.settings.DevelopmentSettings" 
     android:icon="@drawable/ic_settings_development" 
     android:title="@string/development_settings_title" /> 

    <!-- About Device --> 
    <header 
     android:id="@+id/about_settings" 
     android:fragment="com.android.settings.DeviceInfoSettings" 
     android:icon="@drawable/ic_settings_about" 
     android:title="@string/about_settings" /> 

</preference-headers> 

Basta usare <header> solo con l'attributo android:title.

+3

Questo non funziona: solo un'altra intestazione che non crea nulla e non mostra alcuna divisione di gruppo. Penso che nel tuo esempio mancano alcune cose programmatiche. – James

+0

Ho esaminato il codice sorgente dell'attività delle impostazioni, c'è molto che devi fare per ottenere lo stesso risultato. Ho finito con il proxy sull'adapter delle impostazioni e ho restituito una vista diversa per i miei titoli. – rekire

+0

Come menzionato da @James, non funziona. Non sprecate il vostro tempo. – tomrozb

7

Questo è un esempio di categoria di preferenza, è possibile utilizzare la categoria di preferenza e impostare il rispettivo frammento e ottenere questo risultato, fatemi sapere se ho frainteso il vostro caso.

Ecco il layout campione

<PreferenceCategory android:title="Heading1"> 
     <Preference 
      android:title="title1" 
      android:summary="summary1" 
      android:key="keyName"/> 

     <Preference 
      android:title="title2" 
      android:summary="summary2" 
      android:key="keyName"/> 
</PreferenceCategory> 

<PreferenceCategory android:title="Heading2"> 
     <Preference 
      android:title="title3" 
      android:summary="summary3" 
      android:key="keyName"/> 
</PreferenceCategory> 
+0

Crea titoli all'interno del frammento (riquadro delle proprietà).La domanda riguarda la creazione di titoli nella sezione di intestazioni (creata da 'loadHeadersFromResource'). – vbence

2

Per approfondire la risposta da T. Folsom, qui è la mia realizzazione:

res/layout/preference_header_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="?android:attr/activatedBackgroundIndicator" 
    android:baselineAligned="false" 
    android:gravity="center_vertical" 
    android:minHeight="48dp" 
    android:paddingRight="?android:attr/scrollbarSize" > 

    <LinearLayout 
     android:layout_width="@dimen/header_icon_width" 
     android:layout_height="wrap_content" 
     android:layout_marginLeft="6dip" 
     android:layout_marginRight="6dip" > 

     <ImageView 
      android:id="@+id/icon" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_gravity="center" /> 
    </LinearLayout> 

    <RelativeLayout 
     android:layout_width="0dip" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="6dip" 
     android:layout_marginLeft="2dip" 
     android:layout_marginRight="6dip" 
     android:layout_marginTop="6dip" 
     android:layout_weight="1" > 

     <TextView 
      android:id="@+android:id/title" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:ellipsize="marquee" 
      android:fadingEdge="horizontal" 
      android:singleLine="true" 
      android:textAppearance="?android:attr/textAppearanceMedium" /> 

     <TextView 
      android:id="@+android:id/summary" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_below="@android:id/title" 
      android:ellipsize="end" 
      android:maxLines="2" 
      android:textAppearance="?android:attr/textAppearanceSmall" /> 
    </RelativeLayout> 

</LinearLayout> 

res/valori/dimens.xml

<resources> 

    <dimen name="header_icon_width">28dp</dimen> 

</resources> 

nella classe PreferenceActivity:

@Override 
protected void onCreate(Bundle savedInstanceState) { 

    if (savedInstanceState != null) { 
     /* 
     * the headers must be restored before the super call in order 
     * to be ready for the call to setListAdapter() 
     */ 
     if (savedInstanceState.containsKey("headers")) { 
      setHeaders((ArrayList<Header>)savedInstanceState.getSerializable("headers")); 
     } 
    } 

    // as suggest by https://stackoverflow.com/questions/15551673/android-headers-categories-in-preferenceactivity-with-preferencefragment 
    if(onIsMultiPane()) getIntent().putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, PreferencesFragment.class.getName()); 

    super.onCreate(savedInstanceState); 

    ... 

} 

@Override 
protected void onResume() { 
    super.onResume(); 

    // https://stackoverflow.com/questions/15551673/android-headers-categories-in-preferenceactivity-with-preferencefragment 
    // Select the displayed fragment in the headers (when using a tablet) : 
    // This should be done by Android, it is a bug fix 
    if(getHeaders() != null) { 

     final String displayedFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); 
     if (displayedFragment != null) { 
      for (final Header header : getHeaders()) { 
       if (displayedFragment.equals(header.fragment)) { 
        switchToHeader(header); 
        break; 
       } 
      } 
     } 
    } 

    ... 

} 

/** 
* Populate the activity with the top-level headers. 
*/ 
@Override 
public void onBuildHeaders(List<Header> target) { 
    // we have to save the headers as the API call getHeaders() is hidden. 
    setHeaders(target); 
    loadHeadersFromResource(R.xml.settings_headers, target); 
} 

private List<Header> headers; 

private void setHeaders(List<Header> headers) { 
    this.headers = headers; 
} 

private List<Header> getHeaders() { 
    return headers; 
} 

@Override 
protected void onSaveInstanceState(Bundle outState) { 
    outState.putSerializable("headers", (ArrayList<PreferenceActivity.Header>)headers); 
    super.onSaveInstanceState(outState); 
} 

@Override 
public void setListAdapter(ListAdapter adapter) { 
    if (adapter == null) { 
     super.setListAdapter(null); 
    } else { 
     super.setListAdapter(new HeaderAdapter(this, getHeaders())); 
    } 
} 

private static class HeaderAdapter extends ArrayAdapter<Header> { 
    static final int HEADER_TYPE_CATEGORY = 0; 
    static final int HEADER_TYPE_NORMAL = 1; 
    private static final int HEADER_TYPE_COUNT = HEADER_TYPE_NORMAL + 1; 

    private static class HeaderViewHolder { 
     ImageView icon; 
     TextView title; 
     TextView summary; 
    } 

    private LayoutInflater mInflater; 

    static int getHeaderType(Header header) { 
     if (header.fragment == null && header.intent == null) { 
      return HEADER_TYPE_CATEGORY; 
     } else { 
      return HEADER_TYPE_NORMAL; 
     } 
    } 

    @Override 
    public int getItemViewType(int position) { 
     Header header = getItem(position); 
     return getHeaderType(header); 
    } 

    @Override 
    public boolean areAllItemsEnabled() { 
     return false; // because of categories 
    } 

    @Override 
    public boolean isEnabled(int position) { 
     return getItemViewType(position) != HEADER_TYPE_CATEGORY; 
    } 

    @Override 
    public int getViewTypeCount() { 
     return HEADER_TYPE_COUNT; 
    } 

    @Override 
    public boolean hasStableIds() { 
     return true; 
    } 

    public HeaderAdapter(Context context, List<Header> objects) { 
     super(context, 0, objects); 

     mInflater = (LayoutInflater) context 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     HeaderViewHolder holder; 
     Header header = getItem(position); 
     int headerType = getHeaderType(header); 
     View view = null; 

     if (convertView == null) { 
      holder = new HeaderViewHolder(); 
      switch (headerType) { 
      case HEADER_TYPE_CATEGORY: 
       view = new TextView(getContext(), null, 
         android.R.attr.listSeparatorTextViewStyle); 
       holder.title = (TextView) view; 
       break; 

      case HEADER_TYPE_NORMAL: 
       view = mInflater.inflate(R.layout.preference_header_item, 
         parent, false); 
       holder.icon = (ImageView) view.findViewById(R.id.icon); 
       holder.title = (TextView) view 
         .findViewById(android.R.id.title); 
       holder.summary = (TextView) view 
         .findViewById(android.R.id.summary); 
       break; 
      } 
      view.setTag(holder); 
     } else { 
      view = convertView; 
      holder = (HeaderViewHolder) view.getTag(); 
     } 

     // All view fields must be updated every time, because the view may 
     // be recycled 
     switch (headerType) { 
     case HEADER_TYPE_CATEGORY: 
      holder.title.setText(header.getTitle(getContext() 
        .getResources())); 
      break; 
     case HEADER_TYPE_NORMAL: 
      holder.icon.setImageResource(header.iconRes); 
      holder.title.setText(header.getTitle(getContext() 
        .getResources())); 
      CharSequence summary = header.getSummary(getContext() 
        .getResources()); 
      if (!TextUtils.isEmpty(summary)) { 
       holder.summary.setVisibility(View.VISIBLE); 
       holder.summary.setText(summary); 
      } else { 
       holder.summary.setVisibility(View.GONE); 
      } 
      break; 
     } 

     return view; 
    } 

} 

Con tutto questo codice in luogo, la creazione di intestazioni è semplicemente:

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > 
    <header android:title="atitle" /> 
</preference-headers> 

Spero che questo aiuti qualcuno. So che mi ci è voluto del tempo per funzionare correttamente.

1

Questo è in realtà piuttosto semplice. Da quello che ho trovato, la radice PreferenceActivity non supporta l'aggiunta di titoli di categoria/sezione, sembra che tu possa solo aggiungere Header s - che non è molto interessante.

Così che cosa è necessario prima fare è non fare alcun sollevamento di carichi pesanti nella vostra PreferenceActivity se stessa e andare direttamente in carica un PreferenceFragment:

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

    setTitle("Settings"); 

    // Display the fragment as the main content. 
    getFragmentManager().beginTransaction() 
      .replace(android.R.id.content, new PreferencesFragment()) 
      .commit(); 

} 

public static class PreferencesFragment extends PreferenceFragment { 

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

     addPreferencesFromResource(R.xml.prefs); 
    } 
} 

Una volta fatto questo si può ora fare tutto il lavoro in il tuo PreferenceFragment, e la bella notizia è che ora puoi usare le categorie!

Il file R.xml.prefs dovrebbe essere simile a questo:

<?xml version="1.0" encoding="utf-8"?> 
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > 
    <PreferenceCategory 
     android:summary="Login credentials" 
     android:title="Login credentials" > 
     <EditTextPreference 
      android:key="username" 
      android:summary="Username" 
      android:title="Username" /> 
     <EditTextPreference 
      android:key="password" 
      android:summary="Password" 
      android:title="Password" /> 
    </PreferenceCategory> 

    <PreferenceCategory 
     android:summary="Settings" 
     android:title="Settings" > 
     <CheckBoxPreference 
      android:key="persist" 
      android:summary="Yes/No" 
      android:title="Keep me signed in" /> 

    </PreferenceCategory> 
</PreferenceScreen> 

Basta creare un PreferenceCategory per ogni nuova categoria che si desidera aggiungere.

Problemi correlati