2013-02-01 14 views
21

Używam nagłówków preferencji do tworzenia aktywności ustawień za pomocą PreferenceActivity. Staram się dzielić na kategorie nagłówki/grup, jak ten (istnieją kategorie Wireless & Sieci, urządzenia osobiste, ...):Jak utworzyć grupy nagłówków preferencji w Android PreferenceActivity?

Zresztą nawet, że strona jest o Android Developers w ten sposób tworzenia działania preferencji nie mogłem znaleźć sposobu, aby utworzyć takie same preferencje, jakie mają na obrazie. Jedyne, co udało mi się zrobić, to prosta lista nagłówków preferencji.

Jedyne, co znalazłem, to this, ale to działa trochę ... dziwnie. To nie wydaje się być opcją.

Moje pytanie brzmi: jak stworzyć PreferenceActivity przy użyciu nagłówków preferencji z możliwością dzielenia nagłówków na kategorie i z możliwością użycia przełączników nadrzędnych?

Niektóre z mojego kodu:

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); 
} 

nie jestem opublikowania fragmentów zasobów, że to niepotrzebne.

Odpowiedz

5

Wydaje się, że najlepszym rozwiązaniem jest stworzenie trzech różnych bloków kodu - jednego dla pre-Honeycomb, jednego dla Post-Honeycomb i jednego dla tabletów.

Użycie nagłówków preferencji działa tylko na tabletach, więc pozostają one tylko na tabletach. Nie stosuje się tutaj grupowania.

Preferencyjne nagłówki na końcu po usunięciu segmentu plastra miodu są bezużyteczne, więc najlepsze jest użycie typowego PreferenceScreen w PreferenceFragment. Grupy można łatwo tworzyć przez PreferenceCategory.

I na koniec, w przypadku wcześniejszych plasterków o strukturze plastra miodu, wycofany sposób bez użycia PrefrenceFragment jest jedynym sposobem.

Niestety jest dużo kodu powielania, ale biblioteka UnifiedPreference wspomniano w odpowiedzi przez Leandros jest buggy - ignoruje PreferenceFragment całkowicie więc jest bezużyteczny (przynajmniej dla mnie).

+0

Zobacz moją odpowiedź tutaj http://stackoverflow.com/a/20806812/1139784 o zmniejszeniu niektórych powielania kodu. –

6

Myślę, że to, co znaleźliście pod numerem site Xaviera Goucheta, to sposób, w jaki musimy to zrobić. Spojrzałem na kod źródłowy w aplikacji ustawień Androida i na to, co Gouchet wyjął. Dostosowałem go do moich celów (pomijając przełącznik włączania dźwięku) i otrzymałem nagłówek kategorii z linią dzielącą.

Mam nadzieję, że interfejs API Androida dla ustawień zostanie wkrótce wzbogacony o kategorie pomocy technicznej. To nie powinno być takie trudne.

+1

Ponad rok później i wciąż nic. Wydaje się niedorzecznością, że podstawowy ekran ustawień, który widzą wszyscy, nie ma łatwego sposobu dodawania kategorii. – Mgamerz

+0

Dead link, a odpowiedź nie dostarcza prawdziwych informacji. –

-1

AOSP realizacja settings_headers.xml:

<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> 

Wystarczy użyć <header> tylko z atrybutem android:title.

+3

To nie działa - po prostu tworzony jest kolejny nagłówek, który nic nie robi i nie pokazuje żadnego podziału grupy. Myślę, że w twoim przykładzie brakuje pewnych elementów programowych. – James

+0

Zajrzałem do kodu źródłowego działania ustawień, jest wiele rzeczy, które trzeba zrobić, aby uzyskać ten sam wynik. Zakończyłem proxy adaptera ustawień i zwróciłem inny widok dla nagłówków. – rekire

+0

Jak wspomniano w @James, to nie działa. Nie marnuj swojego czasu. – tomrozb

7

To jest przykład kategorii preferencji, możesz użyć kategorii preferencji i ustawić odpowiedni fragment i osiągnąć to, daj mi znać, jeśli źle zrozumiałem twoją sprawę.

Oto próby, graficzny wzór

<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

Powoduje to utworzenie tytułów wewnątrz fragmentu (panelu właściwości).Pytanie dotyczy tworzenia tytułów w sekcji nagłówków (utworzonych przez 'loadHeadersFromResource'). – vbence

2

opracować na odpowiedź od T. Folsom, tutaj jest moje wykonanie:

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/wartości/dimens.xml

<resources> 

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

</resources> 

w swojej klasie 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; 
    } 

} 

Ze wszystkimi tego kodu w miejscu, tworzenie nagłówków jest prosta:

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

Nadzieja to pomaga kogoś. Wiem, że zajęło mi trochę czasu, aby działać poprawnie.

1

To jest całkiem proste. Z tego, co odkryłem, sam root nie obsługuje dodawania tytułów do kategorii/sekcji, wydaje się, że możesz dodać tylko s - co nie jest zbyt interesujące.

Więc co trzeba najpierw zrobić nie robić żadnych podnoszenia ciężkich w PreferenceActivity się i iść prosto do załadowania 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); 
    } 
} 

Po wykonaniu tego można teraz wykonać całą pracę w Twój PreferenceFragment, a wspaniałą wiadomością jest to, że możesz teraz używać kategorii !

Plik R.xml.prefs powinien wyglądać mniej więcej tak:

<?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> 

Wystarczy utworzyć PreferenceCategory dla każdej nowej kategorii, którą chcesz dodać.

Powiązane problemy