Keine ActionBar in PreferenceActivity nach dem Upgrade auf Support Library v21


83

Nach dem Upgrade auf die Support Library v21 ist meine ActionBar in meiner PreferenceActivityverschwunden.

Habe ich einige Attribute in meinem Thema verpasst, um es wieder zu aktivieren? Ich hatte ähnliche Probleme mit einer schwarzen ActionBar .

Ich habe auch versucht, es ein wenig hackisch hinzuzufügen, indem ich Toolbardem Root-Layout ein hinzugefügt habe , aber das hat nicht wie erwartet funktioniert.


Sie sollten Preference Fragment verwenden: developer.android.com/reference/android/preference/…
Jared Burrows

1
@JaredBurrows Sie können PreferenceFragment vor 3.0 nicht verwenden
tyczj

1
Ich benutze sie auch. AFIK Ich muss eine Verknüpfung zu einer PreferenceActivity herstellen, die die PreferenceFragments verwendet. Tycyj weist jedoch darauf hin, dass ich sie auch für die Unterstützung von Legacy benötige.
rekire

1
Die Symbolleiste ist nur eine Ansicht. Sie können es überall hinzufügen.
Jared Burrows

1
Sie können das Beispiel überprüfen, das ich hier gemacht habe: github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
Android-Entwickler

Antworten:


170

Das GitHub Repo finden Sie hier


Sehr ähnlich zu Ihrem eigenen Code, aber XML hinzugefügt, um den festgelegten Titel zu ermöglichen:

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

Beispiel


UPDATE (Lebkuchen-Kompatibilität):

Wie hier ausgeführt , geben Gingerbread Devices in dieser Zeile NullPointerException zurück:

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

FIX:

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.JELLY_BEAN) {
            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();
            }
        });
    }
}

Alle Probleme mit den oben genannten lassen Sie es mich wissen!


UPDATE 2: TUNING WORKAROUND

Wie in vielen Entwicklungsnotizen PreferenceActivityerwähnt, unterstützt das Abtönen von Elementen nicht. Wenn Sie jedoch einige interne Klassen verwenden, können Sie dies erreichen. Bis diese Klassen entfernt werden. (Funktioniert mit appCompat support-v7 v21.0.3).

Fügen Sie die folgenden Importe hinzu:

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;

Überschreiben Sie dann die onCreateViewMethode:

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

Beispiel 2


AppCompat 22.1

AppCompat 22.1 führte neue getönte Elemente ein, sodass die internen Klassen nicht mehr verwendet werden müssen, um den gleichen Effekt wie beim letzten Update zu erzielen. Folgen Sie stattdessen diesem (immer noch überschreibenden 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.JELLY_BEAN) {
        // 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;
}

NESTED PREFERENCE SCREENS

Viele Leute haben Probleme mit der Aufnahme der Symbolleiste in verschachtelte <PreferenceScreen />s, aber ich habe eine Lösung gefunden !! - Nach viel Versuch und Irrtum!

Fügen Sie Folgendes hinzu 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();
        }
    });
}

Der Grund dafür PreferenceScreenist, dass sie als Wrapper-Dialogfeld basieren. Daher müssen wir das Dialogfeld-Layout erfassen, um die Symbolleiste hinzuzufügen.


Symbolleistenschatten

Durch das Importieren von Designs ist das ToolbarAufheben und Abschatten in Geräten vor Version 21 nicht möglich. Wenn Sie also eine Höhe auf Ihrem Gerät haben möchten, müssen ToolbarSie diese in Folgendes einschließen AppBarLayout:

`settings_toolbar.xml:

<android.support.design.widget.AppBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

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

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

Nicht zu vergessen, dass Sie die Design Support-Bibliothek als Abhängigkeit in der build.gradleDatei hinzufügen :

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

Ich habe das gemeldete überlappende Problem untersucht und kann das Problem nicht reproduzieren.

Der oben verwendete vollständige Code erzeugt Folgendes:

Geben Sie hier die Bildbeschreibung ein

Wenn mir etwas fehlt, lass es mich bitte über dieses Repo wissen und ich werde es untersuchen.


Schön: Ich habe den ersten Ansatz gewählt (Lebkuchen ist nicht auf meinem Ziel). Danke dir!
JJ86

In diesem Beispiel scheint die Aufwärtsschaltfläche bei Lebkuchen defekt zu sein.
Idunnololz

1
Vielen Dank für Ihre großartige Antwort. Ich habe Ihnen vor einigen Tagen den akzeptierten Status gegeben. Ich habe gerade den
Tönungsteil

1
Ich muss mich korrigieren. Die android:themeProblemumgehung korrigiert nur die schwarze Textfarbe in der Symbolleiste für Android 5.0+. Mit der neuen Support-Bibliothek scheint sich etwas geändert zu haben (ich verwende 22.2.0).
Tony

4
android.R.id.list 's Elternteil ist FrameLayout in android N
zys

45

Verwenden Sie AppCompatActivity & PreferenceFragment, um das Problem zu lösen:

AppCompatActivity:

public class SettingsActivity extends AppCompatActivity {

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}}

PreferenceFragment:

public class SettingsFragment extends PreferenceFragment {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.settings_preferences);
}}

1
Die ActionBarActivity ist veraltet.
rekire

@rekire seine android.support.v7.app.ActionBarActivity
Abdullah

4
Erweitern Sie einfach AppCompatActivity anstelle von ActionBarActivity.
SammyT

1
Arbeitete für mich und viel einfacher als die oben genannten.
Aaron Blenkush

1
Für einfache Einstellungsbildschirme ist dies bei weitem die am einfachsten zu implementierende Lösung.
Chris Cirefice

7

Am Ende habe ich die Symbolleiste selbst mit diesem einfachen Code hinzugefügt:

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

Hier ist meine Einstellungen_toolbar.xml:

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    app:navigationContentDescription="@string/abc_action_bar_up_description"
    android:background="?attr/colorPrimary"
    app:navigationIcon="?attr/homeAsUpIndicator"
    app:theme="@style/Theme.Toolbar" />

Ich denke, ich habe es in onCreate ()
rekire

6

Eine bessere Lösung als das Rollen Ihrer eigenen Aktionsleiste ist die Verwendung der AppCompatDelegate- Klasse, mit der Sie eine tatsächliche Aktionsleiste aus der Support-Bibliothek einfügen können . Hier ist ein Beispielcode, der aus der Antwort von Ľubomír Kučera auf diese Frage stammt .

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

4
aka AppCompatPreferenceActivity aus offiziellen v7-Beispielen.
Avinash R

4

Hallo, ich bin es nicht, wenn Sie dieses Problem noch haben. Aber ich denke, ich werde veröffentlichen, was ich getan habe, um dieses Problem zu lösen, und hoffe, dass es jemandem hilft.

1) Zunächst einmal haben Sie möglicherweise bemerkt, dass PreferenceActivity ListActivity erweitert, was sich wiederum von Activity aus erstreckt.

Laut den Kommentaren im Entwicklerblog ( http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html ) müssen alle Ihre Aktivitäten von ActionBarActivity erben, um v21 verwenden zu können . Da ist also dein Problem.

2) Die Schritte, die ich zum Auflösen verwendet habe, sind:

a) Make sure that you set the Theme of your PreferenceActivity to inherits one ot the Theme.AppCompat Themes.

b) Make your class PreferenceActivity extends ActionBarActivity.

c) Use the PreferenceFragment as your container for all your preferences.

Dies sollte das Problem beheben.

Prost!


4
"Machen Sie Ihre Klasse PreferenceActivity erweitert ActionBarActivity" - aber wie?
Vbence

Überprüfen Sie diesen Link hier: code.hootsuite.com/…
AfrikAndroid

1
Danke, ich denke das kommt so nah wie möglich. Der eigentliche Schmerz ist, dass PreferenceActivity eine integrierte Navigation über loadHeadersFromResource hat. Mit Fragmenten müssen Sie die Navigation selbst erstellen.
Vbence

0

Ich habe etwas Ähnliches wie eine akzeptierte Frage gemacht, aber ich verwende mein Layout auch ( MainActivityauch) für andere Aktivitäten , sodass ich nicht einfach einen Pfeil darin fest codieren kann.

Was hat bei mir funktioniert:

private void setupActionBar() {
    LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
    Toolbar toolbar = (Toolbar)LayoutInflater.from(this).inflate(R.layout.app_bar, root, false);
    root.addView(toolbar, 0);
    setSupportActionBar(toolbar);
    ActionBar ab = getSupportActionBar();
    ab.setDisplayHomeAsUpEnabled(true);
}

0

Ich hatte das gleiche Problem. Versuchen Sie einfach, das Thema der Aktivität in das zu ändern, in dem sich eine ActionBar befindet. Das Hinzufügen der folgenden Zeile zum Aktivitäts-Tag von SettingsActivity hat für mich funktioniert:

android:theme="Theme.AppCompat.DayNight.DarkActionBar"


-1

Ein einfacher Weg, den ich herausgefunden habe, ist das Überschreiben:

@android:style/Theme.Material.Light.DarkActionBar

In deinem Stil:

<style name="SettingsTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
    <item name="android:colorPrimary">@color/sunshine_blue</item>
    <item name="android:colorPrimaryDark">@color/sunshine_dark_blue</item>
</style>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.