¿Cómo agregar la barra de acciones de la biblioteca de soporte a PreferenceActivity?


La compatibilidad de la barra de acciones se ha añadido a la biblioteca de soporte, revisión 18. Ahora tiene ActionBarActivity clase para crear actividades con Barra de acción en versiones anteriores de Android.

¿Hay alguna forma de agregar la Barra de acciones de la biblioteca de soporte a PreferenceActivity?

Anteriormente usé ActionBarSherlock y tiene SherlockPreferenceActivity.

Author: Roman, 2013-07-25

8 answers

EDITAR: En appcompat-v7 22.1.0 Google agregó la clase abstracta AppCompatDelegate como un delegado que puede usar para extender el soporte de AppCompat a cualquier actividad.

Úsalo así:

...
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
...

public class SettingsActivity extends PreferenceActivity {

    private AppCompatDelegate mDelegate;

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

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        getDelegate().onPostCreate(savedInstanceState);
    }

    public ActionBar getSupportActionBar() {
        return getDelegate().getSupportActionBar();
    }

    public void setSupportActionBar(@Nullable Toolbar toolbar) {
        getDelegate().setSupportActionBar(toolbar);
    }

    @Override
    public MenuInflater getMenuInflater() {
        return getDelegate().getMenuInflater();
    }

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);
    }

    @Override
    public void setContentView(View view) {
        getDelegate().setContentView(view);
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        getDelegate().setContentView(view, params);
    }

    @Override
    public void addContentView(View view, ViewGroup.LayoutParams params) {
        getDelegate().addContentView(view, params);
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        getDelegate().onPostResume();
    }

    @Override
    protected void onTitleChanged(CharSequence title, int color) {
        super.onTitleChanged(title, color);
        getDelegate().setTitle(title);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getDelegate().onConfigurationChanged(newConfig);
    }

    @Override
    protected void onStop() {
        super.onStop();
        getDelegate().onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getDelegate().onDestroy();
    }

    public void invalidateOptionsMenu() {
        getDelegate().invalidateOptionsMenu();
    }

    private AppCompatDelegate getDelegate() {
        if (mDelegate == null) {
            mDelegate = AppCompatDelegate.create(this, null);
        }
        return mDelegate;
    }
}

No más hacking. Código tomado de AppCompatPreferenceActivity.java .

 128
Author: Ľubomír Kučera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-22 17:26:28

Actualmente no hay manera de lograr con AppCompat. He abierto un micrófono interno.

 78
Author: Chris Banes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-26 08:53:44

He logrado crear una solución similar a la que usa Google Play Store. Enlace a la respuesta original

Por favor, encuentre el Repositorio de GitHub: Aquí


Muy similar a su propio código, pero se agregó xml para permitir el título del conjunto:

Seguir utilizando PreferenceActivity:

settings_toolbar.xml :

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    app:navigationContentDescription="@string/abc_action_bar_up_description"
    android:background="?attr/colorPrimary"
    app:navigationIcon="?attr/homeAsUpIndicator"
    app:title="@string/action_settings"
    />

SettingsActivity.java :

public class SettingsActivity extends PreferenceActivity {

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

        LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
        Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
        root.addView(bar, 0); // insert at top
        bar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }

}

Result :

ejemplo


ACTUALIZACIÓN (Compatibilidad con Pan de Jengibre) :

Como se señaló aquí , los dispositivos de pan de jengibre están devolviendo NullPointerException en esta línea:

LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();

ARREGLO:

SettingsActivity.java :

public class SettingsActivity extends PreferenceActivity {

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        Toolbar bar;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent();
            bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
            root.addView(bar, 0); // insert at top
        } else {
            ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
            ListView content = (ListView) root.getChildAt(0);

            root.removeAllViews();

            bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);


            int height;
            TypedValue tv = new TypedValue();
            if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
                height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
            }else{
                height = bar.getHeight();
            }

            content.setPadding(0, height, 0, 0);

            root.addView(content);
            root.addView(bar);
        }

        bar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

Cualquier problema con lo anterior hágamelo saber!


ACTUALIZACIÓN 2: SOLUCIÓN DE TINTADO

Como se ha señalado en muchas notas de desarrollo PreferenceActivity no admite el teñido de elementos, sin embargo, utilizando algunas clases internas puede lograr esto. Eso es hasta que se eliminen estas clases. (Trabaja usando AppCompat support-v7 v21. 0.3).

Añádanse las siguientes importaciones:

import android.support.v7.internal.widget.TintCheckBox;
import android.support.v7.internal.widget.TintCheckedTextView;
import android.support.v7.internal.widget.TintEditText;
import android.support.v7.internal.widget.TintRadioButton;
import android.support.v7.internal.widget.TintSpinner;

Luego anula el método onCreateView:

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    // Allow super to try and create a view first
    final View result = super.onCreateView(name, context, attrs);
    if (result != null) {
        return result;
    }

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        // If we're running pre-L, we need to 'inject' our tint aware Views in place of the
        // standard framework versions
        switch (name) {
            case "EditText":
                return new TintEditText(this, attrs);
            case "Spinner":
                return new TintSpinner(this, attrs);
            case "CheckBox":
                return new TintCheckBox(this, attrs);
            case "RadioButton":
                return new TintRadioButton(this, attrs);
            case "CheckedTextView":
                return new TintCheckedTextView(this, attrs);
        }
    }

    return null;
}

Result:

ejemplo 2


AppCompat 22.1

AppCompat 22.1 introdujo nuevos elementos tintados, lo que significa que ya no es necesario utilizar las clases internas para lograr el mismo efecto que la última actualización. En su lugar, siga esto (aún invalidando onCreateView):

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    // Allow super to try and create a view first
    final View result = super.onCreateView(name, context, attrs);
    if (result != null) {
        return result;
    }

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        // If we're running pre-L, we need to 'inject' our tint aware Views in place of the
        // standard framework versions
        switch (name) {
            case "EditText":
                return new AppCompatEditText(this, attrs);
            case "Spinner":
                return new AppCompatSpinner(this, attrs);
            case "CheckBox":
                return new AppCompatCheckBox(this, attrs);
            case "RadioButton":
                return new AppCompatRadioButton(this, attrs);
            case "CheckedTextView":
                return new AppCompatCheckedTextView(this, attrs);
        }
    }

    return null;
}

PREFERENCIA ANIDADA PANTALLAS

Muchas personas están experimentando problemas con la inclusión de la barra de herramientas en anidados <PreferenceScreen /> s sin embargo, he encontrado una solución!! - ¡Después de mucho ensayo y error!

Añade lo siguiente a tu SettingsActivity:

@SuppressWarnings("deprecation")
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
    super.onPreferenceTreeClick(preferenceScreen, preference);

    // If the user has clicked on a preference screen, set up the screen
    if (preference instanceof PreferenceScreen) {
        setUpNestedScreen((PreferenceScreen) preference);
    }

    return false;
}

public void setUpNestedScreen(PreferenceScreen preferenceScreen) {
    final Dialog dialog = preferenceScreen.getDialog();

    Toolbar bar;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent();
        bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
        root.addView(bar, 0); // insert at top
    } else {
        ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.content);
        ListView content = (ListView) root.getChildAt(0);

        root.removeAllViews();

        bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);

        int height;
        TypedValue tv = new TypedValue();
        if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
            height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
        }else{
            height = bar.getHeight();
        }

        content.setPadding(0, height, 0, 0);

        root.addView(content);
        root.addView(bar);
    }

    bar.setTitle(preferenceScreen.getTitle());

    bar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dialog.dismiss();
        }
    });
}

La razón por la que los PreferenceScreen son tan dolorosos es porque están basados como un diálogo de envoltura, por lo que necesitamos capturar el diseño del diálogo para agregarle la barra de herramientas.


Sombra de barra de herramientas

Por diseño importar el Toolbar no permite para la elevación y el sombreado en dispositivos anteriores a la v21, por lo que si desea tener elevación en su Toolbar debe envolverlo en un AppBarLayout:

`settings_toolbar.xml:

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

   <android.support.v7.widget.Toolbar
       .../>

</android.support.design.widget.AppBarLayout>

Sin olvidar añadir la biblioteca add the Design Support como dependencia en el archivo build.gradle:

compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.0'

Android 6.0

He investigado el problema de superposición reportado y no puedo reproducir el problema.

El código completo en uso como el anterior produce la siguiente:

introduzca la descripción de la imagen aquí

Si me estoy perdiendo algo por favor hágamelo saber a través de este repo y voy a investigar.

 24
Author: David Passmore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:28

Se encontró una implementación de PreferenceFragment basada en el fragmento support-v4:

Https://github.com/kolavar/android-support-v4-preferencefragment

Editar: Acabo de probarlo y funciona muy bien!

 12
Author: Ostkontentitan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-21 08:34:53

Integrar PreferenceActivity con ABC no es posible, al menos para mí. Probé las dos posibilidades que pude encontrar, pero ninguna funcionó:

Opción 1:

ActionBarPreferenceActivity extiende PreferenceActivity. Cuando usted hace esto usted consigue restringido por ActionBarActivityDelegate.createDelegate(ActionBarActivity activity). También es necesario implementar ActionBar.Callbacks que no es accesible

Opción 2:

ActionBarPreferenceActivity extiende ActionBarActivity. Este enfoque requiere reescribir un nuevo PreferenceActivity, PreferenceManager y puede ser PreferenceFragment lo que significa que necesita acceso a clases ocultas como com.android.internal.util.XmlUtils La solución a esto solo puede venir de los desarrolladores de Google que implementan un ActionBarWrapper que se puede agregar a cualquier actividad.

Si realmente necesita una actividad de preferencia, mi consejo por ahora es ActionBarSherlock.

Sin embargo, logré implementarlo aquí.

 3
Author: Maxwell Weru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-01 10:02:55

Fondo del problema:

El OP quiere saber cómo podemos poner MenuItem s en el ActionBar de PreferenceActivity para pre-Honeycomb porque la biblioteca de soporte de Android tiene un error que no permite que esto suceda.

Mi solución:

He encontrado una manera mucho más limpia, de lo que ya se propuso, para lograr el objetivo (y lo encontré en la Android Docs):

android:parentActivityName

El nombre de la clase del padre lógico de la actividad. El nombre aquí debe coincidir con el nombre de la clase dado a la atributo android: name del elemento correspondiente.

El sistema lee este atributo para determinar qué actividad debe ser iniciado cuando el uso presiona el botón Arriba en la barra de acciones. El sistema también puede utilizar esta información para sintetizar una pila posterior de actividades con TaskStackBuilder.

Para admitir los niveles de API 4 a 16, también puede declarar la actividad principal con un elemento que especifica un valor para "androide.apoyo.PARENT_ACTIVITY". Para ejemplo:

<activity
    android:name="com.example.app.ChildActivity"
    android:label="@string/title_child_activity"
    android:parentActivityName="com.example.myfirstapp.MainActivity" >
    <!-- Parent activity meta-data to support API level 4+ -->
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app.MainActivity" />
</activity>

Ahora haz lo que normalmente harías en tu onOptionsItemSelected(). Dado que es parte de Android Docs, no tiene efectos secundarios.

Feliz codificación. :)

Actualización:

Esta solución ya no funciona si estás apuntando a Lollipop. Si estás usando AppCompat, esta respuesta es lo que deberías estar buscando.

 3
Author: Sufian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:55

Pude obtener android.app.Actionbar usando getActionBar(). Devolvió un valor null al principio... luego fui al manifiesto y cambié el tema a:

android:theme="@style/Theme.AppCompat"

Entonces pude tener la barra de acción de nuevo. Asumo que esto solo funcionará para ciertos niveles de construcción. Así que es posible que desee hacer una comprobación para el número de compilación o comprobar si el valor devuelto es null.

Estará bien para mí porque la aplicación en la que estoy trabajando es para ICS/4.0+.

 1
Author: RCB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-22 20:14:57

Ahora se ha publicado la respuesta oficial para este problema. Es la biblioteca Soporte de Preferencias v7/v14.

Consulte ¿Cómo usar la biblioteca de Soporte de preferencias v7/v14? para la discusión cómo usarlo.

 0
Author: Randy Sugianto 'Yuku',
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:17