サポート付きの設定画面の作成(v21)ツールバー


116

設定画面のサポートライブラリにある新しいマテリアルデザインツールバーを使用できませんでした。

以下のようにsettings.xmlファイルがあります:

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

文字列は他の場所で定義されています。


stackoverflow.com/a/27455363/2247612この回答には、サポートライブラリの完璧なソリューションがあります
harishannam

回答:


110

GitHubリポジトリを見つけてください:ここに


パーティーには少し遅れますが、これは私が使用し続ける回避策として使用している私の解決策です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 :

例


更新(ジンジャーブレッド互換性):

コメントのとおり、Gingerbread Devicesはこの行でNullPointerExceptionを返しています。

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

上記の問題があれば教えてください!


更新2:着色の回避策

多くの開発ノートで指摘されているようにPreferenceActivity、要素の色付けはサポートされていませんが、いくつかの内部クラスを利用することでこれを実現できます。これらのクラスが削除されるまでです。(appCompat support-v7 v21.0.3を使用して動作します)。

次のインポートを追加します。

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;

次に、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:

例2


AppCompat 22.1

AppCompat 22.1では新しい色付きの要素が導入されました。つまり、前回の更新と同じ効果を得るために内部クラスを利用する必要がなくなりました。代わりにこれに従ってください(まだオーバーライドしています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;
}

ネストされた設定画面

多くの人がツールバーをネストに含めることで問題を経験しています<PreferenceScreen />が、解決策を見つけました!! -試行錯誤の末!

次のものをに追加します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();
        }
    });
}

これPreferenceScreenが大変なのは、ラッパーダイアログをベースにしているため、ツールバーを追加するためにダイアログレイアウトをキャプチャする必要があるためです。


ツールバーの影

設計により、インポートでToolbarはv21より前のデバイスでの高度とシャドウイングが許可されないため、高度を設定したいToolbar場合は、でラップする必要があります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>

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

報告された重複する問題を調査しましたが、問題を再現できません。

上記のように使用されている完全なコードは、以下を生成します。

ここに画像の説明を入力してください

何か不足している場合は、このレポでお知らせください。調査いたします。


それはgingebreadでnullpointer例外を与えます、ルートはnullです。
andQlimax 14

あなたのソリューションは素晴らしい働きをします。ただし、このアプローチには問題があります。5.0未満のマテリアルテーマを取得するために(ドキュメントから)必須であるActionBarActivityを拡張せずにそのままで、(例を示すためにのみ)colorAccentが5.0未満のデバイスのチェックボックスに適用されません。これは本当の痛みのようです。おそらく、設定アクティビティを削除し、線形レイアウトを使用して設定画面をシミュレートする必要があります。それ以外の場合、APIレベル8から21のデバイスでマテリアルテーマを使用する方法がわかりません。設定フラグメントは"のみ"> 11 :(
andQlimax

1
@andQlimax私は色合いの問題の解決策で回答を更新しました
David Passmore

3
@DavidPassmore私にとっては、設定リストがツールバーに重なっています
Shashank Srivastava

1
@ShashankSrivastavaこれは、Android 6を使用している場合に反映されます。私はこの解決策に取り組んでいます。更新していただきありがとうございます。
David Passmore

107

PreferenceFragment代わりにを使用できますPreferenceActivity。だから、ここにラッピングの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();
    }
}

そして、これがレイアウトファイル(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>

そして最後にPreferenceFragment

public static class MyPreferenceFragment extends PreferenceFragment{
    @Override
    public void onCreate(final Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.settings);
    }
}

これが誰かの役に立つことを願っています。


39
私はこのアプローチを試しました。問題は、ツールバーが子設定画面に表示されないことです。
Madhur Ahuja 2014年

2
私は彼がルート設定XMLに埋め込まれたPreferenceScreenについて話していると思います。
Lucas S.

5
私はアプローチが好きでしたが、残念ながらターゲットAPIがAPI 11未満の場合は機能しません
midhunhk

12
どちらでも機能します。実際には、材料で設計されたツールバー付きのネストされた設定画面を作成する方法はないようです。を使用しActionBarActivityてツールバーと関連機能を取得する場合onBuildHeaders()、アクティビティでオーバーライドする必要はなく、実際の設定サポートもありません。古いを使用する場合はPreferenceActivity、ツールバーおよび関連する機能を持っている、あなたは(はい、あなたが持つことができていないToolbarとレイアウトをしかし、あなたは呼び出すことはできませんsetSupportActionBar()。そうし、どちらかの優先ヘッダーまたはネストされた好みの画面で、我々はこだわっているようだ。
ガーボル

1
私はガボールのコメントに同意します。このソリューションは一般的に機能しません。ツールバーのエミュレーション(ActionBarはありませんが、気にする人)を備えた次の優れたものと、AppCompatDelegateがオンボードでリリースされた新しいサポートライブラリがあります。
Eugene Wechsler

48

完全に新しいアップデート。

いくつかの実験で、ネストされた設定画面用のAppCompat 22.1+ソリューションが機能していることがわかりました。

まず、多くの回答(ここを含む)で言及されているように、新しいを使用する必要がありますAppCompatDelegateAppCompatPreferenceActivity.javaサポートデモのファイル(https://android.googlesource.com/platform/development/+/58bf5b99e6132332afb8b44b4c8cedf5756ad464/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java)を使用するか、単に拡張するそれから、または関連する関数を独自のものにコピーしますPreferenceActivity。ここで最初のアプローチを示します。

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

付随するレイアウトはかなりシンプルで通常のものです(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>

設定自体は通常どおりに定義されます(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>

この時点まで、ネット上のソリューションとの違いはありません。実際には、画面がネストされておらず、ヘッダーがなく、1つの画面しかない場合でも、これを使用できます。

ヘッダーのパラメーターPreferenceFragmentによって区別されるすべてのより深いページに共通のものを使用しextraます。各ページには、共通のPreferenceScreen内部(などxml/settings_page1.xml)を持つ個別のXMLがあります。フラグメントは、ツールバーを含め、アクティビティと同じレイアウトを使用します。

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

最後に、これが実際に機能する方法の簡単な要約。新しいAppCompatDelegateものでは、AppCompatの実際のアクティビティから拡張されたものだけでなく、AppCompatの機能を備えたあらゆるアクティビティを使用できます。これは、古き良き時代PreferenceActivityを新しいものに変え、いつものようにツールバーを追加できることを意味します。その時点から、既存のドキュメントから逸脱することなく、設定画面とヘッダーに関する古い解決策に固執することができます。重要なポイントが1つだけありonCreate()ます。エラーが発生するため、アクティビティでは使用しないでください。onBuildHeaders()ツールバーの追加など、すべての操作に使用します。

唯一の本当の違いは、ネストされた画面で機能するのは、フラグメントに対して同じアプローチを使用できることです。onCreateView()同じ方法を使用して、システムレイアウトの代わりに独自のレイアウトを拡張し、アクティビティと同じ方法でツールバーを追加できます。


2
なんとすばらしい回避策でしょう。これは、子孫のPreferenceScreenにマテリアルツールバーを表示する唯一の解決策です。よくやった。
String

私は、アイコンのAPPCOMPATライブラリからリソースを使用:R.drawable.abc_ic_ab_back_mtrl_am_alpha
Ridcully

この解決策では、ツールバーがコンテンツと共にスクロールすると思いますか?これは、内部のListViewの単なるアイテムだからです。
tasomaniac 2015

この更新された新しいソリューションではありません。それは期待どおりに機能します。
ガーボル

奇妙なことに、このソリューションはのPreferenceFragmentCompat代わりにを認識しないようですPreferenceFragment。の代わりにpreference-headerwith xmlns:app="http://schemas.android.com/apk/res-auto" を設定しても、新しい設定画面は読み込まれません。下位互換性の問題がある...提案?app:fragmentandroid:fragment
fattire

18

PreferenceHeadersを使用する場合は、次の方法を使用できます。

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>

ここでは、好きなレイアウトを使用できます。Javaコードでも調整してください。

そして最後に、ヘッダーを含むファイル(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>

root.addView(toolbar); どうして?root.addView(toolbarContainer);
Crossle Song、2014

名前を変更しているときに変数を逃しました。修正しました。
Sven Dubbeld 2014年

1
すばらしい答えです。ここで重要なのはandroid.R.id.content、代わりに設定リスト自体にListViewwith を渡すために使用していたことを考えるとandroid.R.id.list(フラグメントなし、ヘッダーなしの方法を使用している場合でもそうです)。
davidcsb 2014

2
ビューの階層構造をいじったり(ビューの削除/追加)したりするのではなく、Androidのコードをチェックして、必要なものを確認する方が良いと思います。この方が安全だと思います。ファイル "preference_list_content"をチェックアウトすることをお勧めします。
Android開発者

2
これがこのスレッドでの最良の答えです。この記事の著者は、それを私が使用した完全なリファレンス実装に拡張しました。実際、これはアプリの高度な設定をサポートするための唯一の実用的なソリューションです。
Eugene Wechsler、2015

17

Androidサポートライブラリ22.1.0と新しいAppCompatDelegateのリリースにより、下位互換性のあるマテリアルサポートを備えたPreferenceActivityの実装の優れたサンプルを見つけることができます。

更新 ネストされた画面でも機能します。

https://android.googlesource.com/platform/development/+/marshmallow-mr3-release/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java


1
ああ、それは素晴らしいニュースです!したがって、この新しい観点では、「extend PreferenceActivity」に基づくソリューションは「extend ActionBarActivity」に基づくソリューションよりも優れているようです。
Eugene Wechsler

1
@EugeneWechslerはい、確かに、ActionBarActivityは現在非推奨になっています。
MrBrightside 2015

ネストされた画面でもこのソリューションを機能させますか?より良い例はありますか?
トーマス

@Tomasまだ試していませんが、ネストされた画面でも機能するはずです。うまくいったら教えてください。
MrBrightside、2015年

どうもありがとう !Galaxy Nexus(4.3)とネストされた画面を備えたエミュレーター(lollipop)で私のために働いています。
Tim Autin

6

上記の回答は複雑なように見えますが、拡張APIを使用してツールバーをサポートAPI 7以降で使用するためのクイックフィックスソリューションが必要な場合は、PreferenceActivity以下のこのプロジェクトから助けを得ました。

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

6

私もv7サポートツールバー(API 25)をAppCompatPreferenceActivity(SettingsActivityを追加するとAndroidStudioによって自動的に作成される)に追加するソリューションを探していました。いくつかのソリューションを読んでそれぞれを試した後、生成されたPreferenceFragmentの例をツールバーで表示するのにも苦労しました。

一種の動作した修正されたソリューションは「Gabor」からのものでした。

私が直面した警告の1つは、「onBuildHeaders」が一度だけ起動することでした。デバイス(電話など)を横向きにすると、ビューが再作成され、PreferenceActivityはツールバーなしで残りますが、PreferenceFragmentsはそれらを保持します。

「onPostCreate」を使用して「setContentView」を呼び出してみましたが、向きが変わったときにツールバーが再作成されましたが、PreferenceFragmentsは空白でレンダリングされました。

私が考え出したのは、このトピックについて読むことができるすべてのヒントと答えです。他の人にも役立つと思います。

まずはJavaから

最初に(生成された)AppCompatPreferenceActivity.javaで「setSupportActionBar」を次のように変更しました。

public void setSupportActionBar(@Nullable Toolbar toolbar) {
    getDelegate().setSupportActionBar(toolbar);
    ActionBar bar = getDelegate().getSupportActionBar();
    bar.setHomeButtonEnabled(true);
    bar.setDisplayHomeAsUpEnabled(true);
}

2番目にAppCompatPreferenceFragment.javaという名前の新しいクラスを作成しました(現在は未使用の名前ですが、そうではない可能性があります)。

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

これは、ガボールの答えの中でうまくいった部分です。

最後に、一貫性を確保するために、SettingsActivity.javaにいくつかの変更を加える必要があります。

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

簡潔にするため、一部のコードはアクティビティから除外されています。ここでの主要なコンポーネントは ' onAttachedFragment '、 ' onPostCreate 'であり、 'GeneralPreferenceFragment' がPreferenceFragmentではなくカスタムの ' AppCompatPreferenceFragment 'を拡張するようになりました。

コードの概要:フラグメントが存在する場合、フラグメントは新しいレイアウトを挿入し、変更された 'setSupportActionBar'関数を呼び出します。フラグメントが存在しない場合、SettingsActivityは 'onPostCreate'に新しいレイアウトを挿入します

次に、XML(非常に単純)に移ります

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>

最終結果

設定アクティビティ

GeneralPreferenceFragment


有望に見えますが、私にはうまくいきません。imgur.com/lSSVCIo(Pixel Cエミュレーター)。
Thomas Vos


5

AppCompatPreferenceActivitySupport v7サンプルのを使用する新しい(おそらくよりきれいな)ソリューションがあります。このコードを入手して、ツールバーを含む独自のレイアウトを作成しました。

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

次に、で、新しいレイアウトを作成するAppCompatPreferenceActivityように変更setContentViewし、提供されたレイアウトをmy内に配置しました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);
}

次に、を拡張してAppCompatPreferenceActivity、を呼び出しsetSupportActionBar((Toolbar) findViewById(R.id.toolbar))、ツールバーのメニュー項目も拡張できるようにします。すべての利点を維持しながらPreferenceActivity


5

組み込みのレイアウトを壊すことなく、シンプルでクリーンな状態を維持しましょう

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

、私のために動作しませんでしたroot.getChildAt(0);リターンをnull
Eido95

4

これに取り組んでいるときに私はこの簡単な解決策を見つけました。まず、設定アクティビティのレイアウトを作成する必要があります。

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>

を使用してリストビューを追加してください。追加しandroid:id="@android:id/list"ない場合はスローされますNullPointerException

次のステップはonCreate、設定アクティビティに(オーバーライド)メソッドを追加することです

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

必ずインポートしてくださいandroid.suppoer.v7.widget.Toolbar。これは、16を超えるすべてのAPI(Jelly Bean以降)でほぼ機能します。


1

James Crossのマークされたソリューションを続けたいと思います。それ以降、SettingsActivityも閉じないように、アクティブなネストされた画面(PreferenceFragment)のみを閉じるという問題があるためです。

実際、それはすべてのネストされた画面で機能します(つまり、成功せずに試したGáborの解決策を理解していません。ある時点まで機能しますが、複数のツールバーの混乱です)。ユーザーがサブ設定画面をクリックすると、<FrameLayout android:id="@+id/content_frame" .../>常にアクティブで表示されているツールバーではなく、フラグメントのみが変更されます(を参照)。ただし、カスタム動作を実装して、それに応じて各フラグメントを閉じる必要があります。

SettingsActivity拡張するメインクラスではActionBarActivity、次のメソッドを実装する必要があります。プライベートsetupActionBar()が呼び出されることに注意してくださいonCreate()

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

選択したネストされた画面のタイトルについては、ツールバーの参照を取得し、適切なタイトルをtoolbar.setTitle(R.string.pref_title_general);(たとえば)に設定する必要があります。

ありません必要実装するためのgetSupportActionBar()フラグメントの表示のみではなく、ツールバー、コミットごとに変更されるため、すべてのPreferenceFragmentには、

各preference.xmlに追加するために偽のToolbarPreferenceクラスを作成する必要はありません(Gáborの回答を参照)。


1

AOSPコードに基づいて作成したライブラリは次のとおりです。これは、設定とダイアログの両方に色を付け、アクションバーを追加し、API 7のすべてのバージョンをサポートします。

https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary


コードを見ると、ネストされた設定では機能しません...?
Tim Rae

@TimRae私があなたが話していることをテストしたかどうかはわかりません。どういう意味か説明してください。正確に使用しようとしているシナリオは何ですか?
Androidデベロッパー

このようなPreferenceScreen内部がある場合PreferenceScreen
Tim Rae

そんなものは使ったことがない。ドキュメントを読む::developer.android.com/reference/android/preference/…、画面間の移動に役立つことがわかります。私も追加した方がいいって?確認してみるよ 。ありがとうございました。また、次回はGithubでご利用ください(要望・課題)。
Android開発者

ええ、1つの画面の設定が多すぎる場合に便利です...このスレッドには、ネストされた画面に言及する場所がすでにいくつかあるので、ここでコメントするのが適切だと思います
Tim Rae

1

さて、これは今日(2015年11月18日)私にとってまだ問題です。私はこのスレッドからすべての解決策を試しましたが、解決できない2つの主なことがありました。

  • ネストされた設定画面がツールバーなしで表示された
  • Lollipop以前のデバイスでは、環境設定にマテリアルの外観がありませんでした

そのため、より複雑なソリューションを備えたライブラリを作成することになりました。基本的に、Lollipop以前のデバイスを使用している場合、スタイルを設定に内部的に適用する必要があり、カスタムフラグメントを使用してネストされた画面も処理しました(PreferenceScreen キーを利用してすべてのネストされた階層を復元します)。

ライブラリはこれです:https : //github.com/ferrannp/material-preferences

そして、あなたがソースコードに興味があるなら(ここにそれを投稿するには長すぎる)、これは基本的にそれのコアです:https//github.com/ferrannp/material-preferences/blob/master/library/src/main/ java / com / fnp / materialpreferences / PreferenceFragment.java

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.