Ich hatte Probleme bei der Verwendung der neuen Materialdesign-Symbolleiste in der Unterstützungsbibliothek auf einem Einstellungsbildschirm.
Ich habe eine settings.xml-Datei wie folgt:
<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android">
<PreferenceCategory
Android:title="@string/AddingItems"
Android:key="pref_key_storage_settings">
<ListPreference
Android:key="pref_key_new_items"
Android:title="@string/LocationOfNewItems"
Android:summary="@string/LocationOfNewItemsSummary"
Android:entries="@array/new_items_entry"
Android:entryValues="@array/new_item_entry_value"
Android:defaultValue="1"/>
</PreferenceCategory>
</PreferenceScreen>
Die Zeichenfolgen werden an anderer Stelle definiert.
Sie können ein PreferenceFragment
als Alternative zu PreferenceActivity
verwenden. Hier ist also das Beispiel für das Umschließen von Activity
:
public class MyPreferenceActivity extends ActionBarActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pref_with_actionbar);
Android.support.v7.widget.Toolbar toolbar = (Android.support.v7.widget.Toolbar) findViewById(uk.japplications.jcommon.R.id.toolbar);
setSupportActionBar(toolbar);
getFragmentManager().beginTransaction().replace(R.id.content_frame, new MyPreferenceFragment()).commit();
}
}
Und hier ist die Layoutdatei (pref_with_actionbar):
<RelativeLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_height="@dimen/action_bar_height"
Android:layout_width="match_parent"
Android:minHeight="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:theme="@style/ToolbarTheme.Base"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
<FrameLayout
Android:id="@+id/content_frame"
Android:layout_below="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" />
</RelativeLayout>
Und zum Schluss das PreferenceFragment
:
public static class MyPreferenceFragment extends PreferenceFragment{
@Override
public void onCreate(final Bundle savedInstanceState){
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}
Ich hoffe das hilft jemandem.
Finden Sie bitte das GitHub Repo: hier
Ein bisschen zu spät zur Party, aber dies ist meine Lösung, die ich als Workaround verwende, um weiterhin PreferenceActivity
zu verwenden:
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 :
Gemäß den Kommentaren geben Gingerbread Devices NullPointerException in dieser Zeile zurück:
LinearLayout root = (LinearLayout)findViewById(Android.R.id.list).getParent().getParent().getParent();
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();
}
});
}
}
Probleme mit den oben genannten lassen Sie es mich wissen!
UPDATE 2: ABHILFE ZUM TÖNEN
Wie in vielen Dev Notes erwähnt, unterstützt PreferenceActivity
das Abtönen von Elementen nicht. Durch die Verwendung einiger interner Klassen können Sie dies jedoch erreichen. Bis diese Klassen entfernt sind. (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 Methode 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:
In AppCompat 22.1 wurden neue getönte Elemente eingeführt, sodass die internen Klassen nicht mehr verwendet werden müssen, um den gleichen Effekt wie beim letzten Update zu erzielen. Folgen Sie stattdessen diesen Anweisungen (überschreiben Sie immer noch 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;
}
NESTED PRÄFERENZBILDSCHIRME
Viele Leute haben Probleme damit, die Symbolleiste in ein verschachteltes <PreferenceScreen />
aber ich habe eine lösung gefunden !! - Nach vielem Ausprobieren!
Fügen Sie Ihrem SettingsActivity
Folgendes hinzu:
@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, warum PreferenceScreen
so schmerzhaft ist, liegt darin, dass sie auf einem Wrapper-Dialogfeld basieren. Daher müssen wir das Dialogfeldlayout erfassen, um die Symbolleiste hinzuzufügen.
Durch das Importieren von Toolbar
ist in Geräten vor Version 21 keine Erhöhung und Schattenbildung möglich. Wenn Sie also eine Erhöhung in Ihrem Toolbar
haben möchten, müssen Sie diese in ein AppBarLayout
einwickeln ] _:
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>
Nicht zu vergessen, das Hinzufügen der Design Support-Bibliothek als Abhängigkeit in build.gradle
Datei:
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'
Ich habe das gemeldete überlappende Problem untersucht und kann es nicht reproduzieren.
Der wie oben verwendete vollständige Code erzeugt Folgendes:
Wenn ich etwas vermisse, lass es mich bitte über dieses Repo wissen und ich werde es untersuchen.
Völlig neues Update.
Nach einigem Experimentieren habe ich die funktionierende AppCompat 22.1+ -Lösung für verschachtelte Einstellungsbildschirme gefunden.
Erstens müssen Sie, wie in vielen Antworten erwähnt (einschließlich einer hier), das neue AppCompatDelegate
verwenden. Verwenden Sie entweder die Datei AppCompatPreferenceActivity.Java
Aus den Support-Demos ( https://Android.googlesource.com/platform/development/+/58bf5b99e6132332afb8b44b4c8cedf5756ad464/samples/Support7Demos/src/com/example/Avroid/ /app/AppCompatPreferenceActivity.Java ) und erweitern Sie es einfach oder kopieren Sie die relevanten Funktionen in Ihr eigenes PreferenceActivity
. Ich werde hier den ersten Ansatz zeigen:
public class SettingsActivity extends AppCompatPreferenceActivity {
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.settings, target);
setContentView(R.layout.settings_page);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar bar = getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);
bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
bar.setTitle(...);
}
@Override
protected boolean isValidFragment(String fragmentName) {
return SettingsFragment.class.getName().equals(fragmentName);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Android.R.id.home:
onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
}
Das dazugehörige Layout ist recht einfach und üblich (layout/settings_page.xml
):
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_margin="0dp"
Android:orientation="vertical"
Android:padding="0dp">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
Android:elevation="4dp"
Android:theme="@style/..."/>
<ListView
Android:id="@id/Android:list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"/>
</LinearLayout>
Die Einstellungen selbst sind wie gewohnt definiert (xml/settings.xml
):
<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android">
<header
Android:fragment="com.example.SettingsFragment"
Android:summary="@string/..."
Android:title="@string/...">
<extra
Android:name="page"
Android:value="page1"/>
</header>
<header
Android:fragment="com.example.SettingsFragment"
Android:summary="@string/..."
Android:title="@string/...">
<extra
Android:name="page"
Android:value="page2"/>
</header>
...
</preference-headers>
Kein wirklicher Unterschied zu Lösungen im Netz bis zu diesem Punkt. Eigentlich können Sie dies auch dann verwenden, wenn Sie keine verschachtelten Bildschirme, keine Überschriften, sondern nur einen einzigen Bildschirm haben.
Wir verwenden ein gemeinsames PreferenceFragment
für alle tieferen Seiten, differenziert durch die extra
-Parameter in den Headern. Jede Seite enthält eine separate XML-Datei mit einem gemeinsamen PreferenceScreen
(xml/settings_page1.xml
Et al.). Das Fragment verwendet dasselbe Layout wie die Aktivität, einschließlich der Symbolleiste.
public class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTheme(R.style...);
if (getArguments() != null) {
String page = getArguments().getString("page");
if (page != null)
switch (page) {
case "page1":
addPreferencesFromResource(R.xml.settings_page1);
break;
case "page2":
addPreferencesFromResource(R.xml.settings_page2);
break;
...
}
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.settings_page, container, false);
if (layout != null) {
AppCompatPreferenceActivity activity = (AppCompatPreferenceActivity) getActivity();
Toolbar toolbar = (Toolbar) layout.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
ActionBar bar = activity.getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);
bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
bar.setTitle(getPreferenceScreen().getTitle());
}
return layout;
}
@Override
public void onResume() {
super.onResume();
if (getView() != null) {
View frame = (View) getView().getParent();
if (frame != null)
frame.setPadding(0, 0, 0, 0);
}
}
}
Abschließend eine kurze Zusammenfassung, wie dies tatsächlich funktioniert. Mit dem neuen AppCompatDelegate
können wir jede Aktivität mit AppCompat-Funktionen verwenden, nicht nur die, die sich von den Aktivitäten in AppCompat erstrecken. Dies bedeutet, dass wir das gute alte PreferenceActivity
in ein neues verwandeln und die Symbolleiste wie gewohnt hinzufügen können. Von diesem Punkt an können wir uns an die alten Lösungen für Voreinstellungsbildschirme und Kopfzeilen halten, ohne von der vorhandenen Dokumentation abzuweichen. Es gibt nur einen wichtigen Punkt: Verwenden Sie in der Aktivität nicht onCreate()
, da dies zu Fehlern führt. Verwenden Sie onBuildHeaders()
für alle Operationen wie das Hinzufügen der Symbolleiste.
Der einzige wirkliche Unterschied besteht darin, dass Sie bei verschachtelten Bildschirmen den gleichen Ansatz für die Fragmente verwenden können. Sie können ihre onCreateView()
auf dieselbe Weise verwenden, indem Sie Ihr eigenes Layout anstelle des Systemlayouts aufblasen und die Symbolleiste auf dieselbe Weise wie in der Aktivität hinzufügen.
Wenn Sie PreferenceHeaders verwenden möchten, können Sie den folgenden Ansatz verwenden:
import Android.support.v7.widget.Toolbar;
public class MyPreferenceActivity extends PreferenceActivity
Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup root = (ViewGroup) findViewById(Android.R.id.content);
LinearLayout content = (LinearLayout) root.getChildAt(0);
LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.activity_settings, null);
root.removeAllViews();
toolbarContainer.addView(content);
root.addView(toolbarContainer);
mToolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar);
}
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
// Other methods
}
layout/activity_settings.xml
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_height="?attr/actionBarSize"
Android:layout_width="match_parent"
Android:minHeight="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:theme="@style/AppTheme"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</LinearLayout>
Sie können hier jedes Layout verwenden, das Sie bevorzugen. Stellen Sie jedoch sicher, dass Sie es auch im Code Java) anpassen.
Und schließlich Ihre Datei mit Headern (xml/pref_headers.xml)
<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android">
<header
Android:fragment="com.example.FirstFragment"
Android:title="@string/pref_header_first" />
<header
Android:fragment="com.example.SecondFragment"
Android:title="@string/pref_header_second" />
</preference-headers>
Mit der Veröffentlichung der Android Support Library 22.1.0 und des neuen AppCompatDelegate finden Sie hier ein schönes Beispiel für eine Implementierung der PreferenceActivity mit Materialunterstützung mit Abwärtskompatibilität.
Update Funktioniert auch auf verschachtelten Bildschirmen.
Auch ich habe nach einer Lösung gesucht, um die v7 Support-Symbolleiste ( API 25 ) zur AppCompatPreferenceActivity (die automatisch erstellt wird) hinzuzufügen von AndroidStudio beim Hinzufügen einer SettingsActivity). Nachdem ich mehrere Lösungen gelesen und ausprobiert hatte, bemühte ich mich, die generierten PreferenceFragment-Beispiele auch mit einer Symbolleiste anzuzeigen.
Eine modifizierte Lösung, die irgendwie funktioniert hat, war von " Gabor ".
Einer der Vorbehalte, mit denen ich konfrontiert war, war, dass 'onBuildHeaders' nur einmal ausgelöst wurde. Wenn Sie ein Gerät (z. B. ein Telefon) zur Seite drehen, wird die Ansicht neu erstellt und die PreferenceActivity wird wieder ohne Symbolleiste angezeigt. Die PreferenceFragments behalten jedoch ihre.
Ich habe versucht, 'onPostCreate' zu verwenden, um 'setContentView' aufzurufen, während dies dazu beitrug, die Symbolleiste neu zu erstellen, wenn sich die Ausrichtung änderte. PreferenceFragments wurde dann leer gemacht.
Was ich mir bei fast jedem Tipp und jeder Antwort ausgedacht habe, konnte ich zu diesem Thema nachlesen. Ich hoffe, andere finden es auch nützlich.
Beginnen wir mit Java
Zuerst in (der generierten) AppCompatPreferenceActivity.Java habe ich 'setSupportActionBar' folgendermaßen geändert:
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
ActionBar bar = getDelegate().getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
}
Zweitens habe ich eine neue Klasse mit dem Namen AppCompatPreferenceFragment.Java erstellt (es ist derzeit ein nicht verwendeter Name, auch wenn dies möglicherweise nicht der Fall ist !):
abstract class AppCompatPreferenceFragment extends PreferenceFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_settings, container, false);
if (view != null) {
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar_settings);
((AppCompatPreferenceActivity) getActivity()).setSupportActionBar(toolbar);
}
return view;
}
@Override
public void onResume() {
super.onResume();
View frame = (View) getView().getParent();
if (frame != null) frame.setPadding(0, 0, 0, 0);
}
}
Dies ist der Teil von Gabors Antwort, der funktioniert hat.
Last , Um die Konsistenz zu gewährleisten, müssen wir einige Änderungen an SettingsActivity.Java vornehmen:
public class SettingsActivity extends AppCompatPreferenceActivity {
boolean mAttachedFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
mAttachedFragment = false;
super.onCreate(savedInstanceState);
}
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
@Override
public void onAttachFragment(Fragment fragment) {
mAttachedFragment = true;
super.onAttachFragment(fragment);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//if we didn't attach a fragment, go ahead and apply the layout
if (!mAttachedFragment) {
setContentView(R.layout.activity_settings);
setSupportActionBar((Toolbar)findViewById(R.id.toolbar_settings));
}
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends AppCompatPreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == Android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
Einige Codes wurden aus Gründen der Kürze aus der Aktivität herausgenommen. Die Schlüsselkomponenten hier sind ' onAttachedFragment ', ' onPostCreate ' und das 'GeneralPreferenceFragment' erweitert jetzt das custom ' AppCompatPreferenceFragment 'anstelle von PreferenceFragment.
Code Summary : Wenn ein Fragment vorhanden ist, fügt das Fragment das neue Layout ein und ruft die geänderte Funktion 'setSupportActionBar' auf. Wenn das Fragment nicht vorhanden ist, fügt SettingsActivity das neue Layout in 'onPostCreate' ein.
Nun zu [~ # ~] xml [~ # ~] (sehr einfach):
activity_settings.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<include
layout="@layout/app_bar_settings"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</LinearLayout>
app_bar_settings.xml :
<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/content_frame"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:context=".SettingsActivity">
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:theme="@style/AppTheme.NoActionBar.AppBarOverlay">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar_settings"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.NoActionBar.PopupOverlay" />
</Android.support.design.widget.AppBarLayout>
<include layout="@layout/content_settings" />
</Android.support.design.widget.CoordinatorLayout>
content_settings.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/content"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:paddingBottom="@dimen/activity_vertical_margin"
Android:paddingLeft="@dimen/activity_horizontal_margin"
Android:paddingRight="@dimen/activity_horizontal_margin"
Android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".SettingsActivity"
tools:showIn="@layout/app_bar_settings">
<ListView
Android:id="@Android:id/list"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" />
</RelativeLayout>
Endergebnis :
Die obigen Antworten scheinen zwar ausführlich zu sein, aber wenn Sie eine schnelle Lösung für die Verwendung der Symbolleiste mit der Unterstützungs-API 7 und höher wünschen, während Sie PreferenceActivity
erweitern, habe ich von diesem Projekt unten Hilfe erhalten.
https://github.com/AndroidDeveloperLB/ActionBarPreferenceActivity
activity_settings.xml
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical" >
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="@color/app_theme_light"
app:popupTheme="@style/Theme.AppCompat.Light"
app:theme="@style/Theme.AppCompat" />
<FrameLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:padding="@dimen/padding_medium" >
<ListView
Android:id="@Android:id/list"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</FrameLayout>
SettingsActivity.Java
public class SettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
addPreferencesFromResource(R.xml.preferences);
toolbar.setClickable(true);
toolbar.setNavigationIcon(getResIdFromAttribute(this, R.attr.homeAsUpIndicator));
toolbar.setTitle(R.string.menu_settings);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private static int getResIdFromAttribute(final Activity activity, final int attr) {
if (attr == 0) {
return 0;
}
final TypedValue typedvalueattr = new TypedValue();
activity.getTheme().resolveAttribute(attr, typedvalueattr, true);
return typedvalueattr.resourceId;
}
}
Ich habe eine neue (möglicherweise ordentlichere) Lösung, die AppCompatPreferenceActivity
aus den Support v7-Beispielen verwendet. Mit diesem Code habe ich mein eigenes Layout erstellt, das eine Symbolleiste enthält:
<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto" xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent" Android:layout_height="match_parent"
Android:fitsSystemWindows="true" tools:context="edu.adelphi.Adelphi.ui.activity.MainActivity">
<Android.support.design.widget.AppBarLayout Android:id="@+id/appbar"
Android:layout_width="match_parent" Android:layout_height="wrap_content"
Android:theme="@style/AppTheme.AppBarOverlay">
<Android.support.v7.widget.Toolbar Android:id="@+id/toolbar"
Android:layout_width="match_parent" Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/>
</Android.support.design.widget.AppBarLayout>
<FrameLayout Android:id="@+id/content"
Android:layout_width="match_parent" Android:layout_height="match_parent"/>
</Android.support.design.widget.CoordinatorLayout>
Dann änderte ich in meinem AppCompatPreferenceActivity
setContentView
, um ein neues Layout zu erstellen, und platziere das bereitgestellte Layout in meinem FrameLayout
:
@Override
public void setContentView(@LayoutRes int layoutResID) {
View view = getLayoutInflater().inflate(R.layout.toolbar, null);
FrameLayout content = (FrameLayout) view.findViewById(R.id.content);
getLayoutInflater().inflate(layoutResID, content, true);
setContentView(view);
}
Dann erweitere ich einfach AppCompatPreferenceActivity
, um setSupportActionBar((Toolbar) findViewById(R.id.toolbar))
aufzurufen und die Menüelemente in der Symbolleiste aufzublasen. Dabei bleiben die Vorteile einer PreferenceActivity
erhalten.
Lassen Sie es uns hier einfach und übersichtlich halten, ohne das eingebaute Layout zu beschädigen
import Android.support.design.widget.AppBarLayout;
import Android.support.v4.app.NavUtils;
import Android.support.v7.widget.Toolbar;
private void setupActionBar() {
Toolbar toolbar = new Toolbar(this);
AppBarLayout appBarLayout = new AppBarLayout(this);
appBarLayout.addView(toolbar);
final ViewGroup root = (ViewGroup) findViewById(Android.R.id.content);
final ViewGroup window = (ViewGroup) root.getChildAt(0);
window.addView(appBarLayout, 0);
setSupportActionBar(toolbar);
// Show the Up button in the action bar.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
}
Ich habe diese einfache Lösung gefunden, als ich daran gearbeitet habe. Zuerst müssen wir ein Layout für die Einstellungsaktivität erstellen.
activity_settings.xml
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context="com.my.package">
<Android.support.v7.widget.Toolbar
Android:id="@+id/tool_bar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="@dimen/appbar_elevation"
app:navigationIcon="?attr/homeAsUpIndicator"
app:navigationContentDescription="@string/abc_action_bar_up_description"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<ListView
Android:id="@Android:id/list"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_below="@+id/tool_bar" />
</RelativeLayout>
Stelle sicher, dass du eine Listenansicht mit Android:id="@Android:id/list"
Hinzufügst, sonst wirft es NullPointerException
Der nächste Schritt ist das Hinzufügen der Methode (Überschreiben) onCreate
in Ihrer Einstellungsaktivität
Settings.Java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
toolbar.setTitle(R.string.action_settings);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
Stellen Sie sicher, dass Sie Android.suppoer.v7.widget.Toolbar
Importieren. Dies sollte auf allen APIs über 16 (Jelly Bean und höher) ziemlich gut funktionieren.
Ich möchte die markierte Lösung von James Cross fortsetzen, da es danach ein Problem gibt, nur den aktiven verschachtelten Bildschirm (PreferenceFragment) zu schließen, um nicht auch die SettingsActivity zu schließen.
Tatsächlich funktioniert es auf allen verschachtelten Bildschirmen (daher verstehe ich die Lösung von Gábor, die ich erfolglos ausprobiert habe, nicht. Es funktioniert bis zu einem gewissen Punkt, aber es ist ein Durcheinander mehrerer Symbolleisten), weil der Benutzer auf einen Bildschirm mit untergeordneten Einstellungen klickt , nur das Fragment wird geändert (siehe <FrameLayout Android:id="@+id/content_frame" .../>
), nicht die Symbolleiste, die immer aktiv und sichtbar bleibt, sondern ein benutzerdefiniertes Verhalten sollte implementiert werden jedes Fragment entsprechend zu schließen.
In der Hauptklasse SettingsActivity
, die ActionBarActivity
erweitert, sollten die folgenden Methoden implementiert werden. Beachten Sie, dass private setupActionBar()
von onCreate()
aufgerufen wird
private void setupActionBar() {
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
//Toolbar will now take on default Action Bar characteristics
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
//If the last fragment was removed then reset the title of main
// fragment (if so the previous popBackStack made entries = 0).
if (getFragmentManager().getBackStackEntryCount() == 0) {
getSupportActionBar()
.setTitle(R.string.action_settings_title);
}
} else {
super.onBackPressed();
}
}
Für das title des ausgewählten verschachtelten Bildschirms sollten Sie die Referenz Ihrer Symbolleiste abrufen und den entsprechenden Titel mit toolbar.setTitle(R.string.pref_title_general);
(zum Beispiel) festlegen.
Es gibt keine Notwendigkeit, die Funktion getSupportActionBar()
in allen PreferenceFragment zu implementieren, da bei jedem Commit nur die Ansicht des Fragments geändert wird, nicht die Symbolleiste.
Es gibt keine Notwendigkeit, eine gefälschte ToolbarPreference-Klasse zu erstellen, die in jede preference.xml eingefügt wird (siehe Gábors Antwort).
Hier ist eine Bibliothek, die ich erstellt habe und die auf AOSP-Code basiert, der sowohl die Voreinstellungen als auch die Dialogfelder einfärbt, eine Aktionsleiste hinzufügt und alle Versionen von API 7 unterstützt:
https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
Nun, das ist heute noch ein Problem für mich (18. November 2015). Ich habe alle Lösungen aus diesem Thread ausprobiert, aber es gab zwei wichtige Dinge, die ich nicht lösen konnte:
Also habe ich eine Bibliothek mit einer komplizierteren Lösung erstellt. Grundsätzlich musste ich Stile intern auf die Voreinstellungen anwenden, wenn wir ein Gerät vor Lollipop verwendeten. Außerdem behandelte ich die verschachtelten Bildschirme mithilfe eines benutzerdefinierten Fragments (Wiederherstellung der gesamten verschachtelten Hierarchie unter Ausnutzung des PreferenceScreen Taste ).
Die Bibliothek ist diese: https://github.com/ferrannp/material-preferences
Und wenn Sie sich für den Quellcode interessieren (zu lange, um ihn hier zu veröffentlichen), ist dies im Grunde der Kern davon: https://github.com/ferrannp/material-preferences/blob/master/library/ src/main/Java/com/fnp/materialpreferences/PreferenceFragment.Java