J'utilise des en-têtes de préférence pour créer une activité de paramètres à l'aide de PreferenceActivity
. J'essaie de diviser les en-têtes en catégories/groupes, comme celui-ci (il existe des catégories Sans fil et réseaux, Appareil, Personnel, ...):
Quoi qu'il en soit, même que Android Developers concerne cette façon de créer une activité de préférence, je n'ai trouvé aucun moyen de créer la même activité de préférence comme sur l'image. Le seul que j'ai réussi faire est une simple liste d'en-têtes de préférence.
La seule chose que j'ai trouvée est ceci , mais cela fonctionne un peu ... étrange. Cela ne semble donc pas être une option.
Ma question est donc la suivante: comment créer PreferenceActivity
en utilisant des en-têtes de préférence avec possibilité de diviser les en-têtes en catégories et avec la possibilité d'utiliser des interrupteurs principaux marche/arrêt?
Une partie de mon code:
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>
ParamètresActivité :
@Override
public void onBuildHeaders(List<Header> target) {
super.onBuildHeaders(target);
loadHeadersFromResource(R.xml.preference_headers, target);
}
Je ne poste pas de fragments de ressources, je pense que ce n'est pas nécessaire.
La meilleure solution semble être la création de trois blocs de code différents - un pour pré-Honeycomb, un pour post-Honeycomb et un pour tablettes.
L'utilisation des en-têtes de préférence n'est efficace que sur les tablettes, elles restent donc uniquement sur les tablettes. Aucun regroupement n'est utilisé ici.
Les en-têtes de préférence sur post-Honeycomb sont un peu inutiles, donc le meilleur est l'utilisation de PreferenceScreen
typique dans un PreferenceFragment
. Les groupes peuvent être créés facilement par PreferenceCategory
.
Et enfin, pour la pré-Honeycomb, la méthode obsolète sans utiliser PrefrenceFragment
est la seule façon.
Malheureusement, il y a beaucoup de duplication de code, mais la bibliothèque UnifiedPreference
mentionnée dans la réponse de Leandros est boguée - elle ignore totalement PreferenceFragment
donc elle est inutile (du moins pour moi).
Ceci est un exemple de catégorie de préférence, vous pouvez utiliser la catégorie de préférence et définir le fragment respectif et y parvenir, faites-moi savoir si j'ai mal compris votre cas.
Voici un exemple de disposition
<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>
Pour développer la réponse de T. Folsom , voici mon implémentation:
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/values / dimens.xml
<resources>
<dimen name="header_icon_width">28dp</dimen>
</resources>
dans votre 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;
}
}
Avec tout ce code en place, créer des en-têtes est tout simplement:
<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android" >
<header Android:title="atitle" />
</preference-headers>
J'espère que cela aide quelqu'un. Je sais qu'il m'a fallu un certain temps pour bien travailler.
C'est en fait assez simple. D'après ce que j'ai trouvé, la racine PreferenceActivity
elle-même ne prend pas en charge l'ajout de titres de catégorie/section, il semble que vous ne pouvez ajouter que Header
s - ce qui n'est pas très intéressant.
Donc, ce que vous devez d'abord faire, c'est ne pas faire de gros travaux dans votre PreferenceActivity
lui-même et passer directement au chargement d'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);
}
}
Une fois que vous avez fait cela, vous pouvez maintenant faire tout le travail dans votre PreferenceFragment
, et la grande nouvelle est que vous pouvez maintenant utiliser des catégories!
Votre fichier R.xml.prefs devrait ressembler à ceci:
<?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>
Créez simplement un PreferenceCategory
pour chaque nouvelle catégorie que vous souhaitez ajouter.