web-dev-qa-db-ja.com

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

環境設定画面のサポートライブラリにある新しいマテリアルデザインツールバーの使用で問題が発生しました。

私は次のように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>

文字列は別の場所で定義されます。

114
James Cross

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

これが誰かの助けになることを願っています。

105
James Cross

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 :

example


UPDATE(ジンジャーブレッドの互換性):

コメントによると、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:

example 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ファイルの依存関係としてDesign Supportライブラリを追加することを忘れないでください:

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

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

上記のように使用中の完全なコードは以下を生成します

enter image description here

何か不足している場合は、 this repo でお知らせください。調査します。

108
David Passmore

完全に新しい更新

いくつかの実験で、ネストされた設定画面用の動作するAppCompat 22.1+ソリューションを見つけたようです。

まず、多くの回答(ここを含む)で言及されているように、新しいAppCompatDelegateを使用する必要があります。サポートデモのAppCompatPreferenceActivity.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>

この時点まで、ネット上のソリューションと実質的な違いはありません。実際、ネストされた画面がなく、ヘッダーがなく、単一の画面だけでも、これを使用できます。

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

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()を同じ方法で使用して、システムのレイアウトではなく独自のレイアウトを拡張し、アクティビティと同じ方法でツールバーを追加できます。

48
Gábor

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>
18
Sven Dubbeld

Android Support Library 22.1.0および新しいAppCompatDelegateのリリースでは、後方互換性のあるマテリアルサポートを備えたPreferenceActivityの実装のニースサンプルを見つけることができます。

Updateネストされた画面でも動作します。

https://Android.googlesource.com/platform/development/+/Marshmallow-mr3-release/samples/Support7Demos/src/com/example/Android/supportv7/app/AppCompatPreferenceActivity.Java

17
MrBrightside

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

修正された解決策は、「Gabor」からのものでした。

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

「onPostCreate」を使用して「setContentView」を呼び出してみましたが、これは向きが変更されたときにツールバーを再作成するために機能し、PreferenceFragmentsは空白になりました。

私が考え出したものは、ほぼすべてのヒントと答えで、このテーマについて読むことができました。他の人にもそれが役立つことを願っています。

Javaから始めます

Firstin(generated)AppCompatPreferenceActivity.Java私は 'setSupportActionBar'を次のように変更しました:

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

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

最終結果

SettingsActivity

GeneralPreferenceFragment

6
SilverX

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

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
midhunhk

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

<?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を変更して新しいレイアウトを作成し、提供されたレイアウトを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
Bryan

ここでは、組み込みのレイアウトを壊さずに、シンプルできれいにしましょう

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

この作業中にこの簡単な解決策を見つけました。最初に、設定アクティビティのレイアウトを作成する必要があります。

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(Jelly bean以上)を超えるすべてのAPIでほぼ機能するはずです。

4
Apurva

ジェームズクロスのマークされたソリューションを継続したいと思います。その後、SettingsActivityも閉じない方法で、アクティブなネストされた画面(PreferenceFragment)のみを閉じるという問題があるためです。

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

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

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

すべてのPreferenceFragmentにgetSupportActionBar()を実装するには必要なしがあります。これは、ツールバーではなく、コミットのたびにフラグメントのビューのみが変更されるためです。

不要があり、各preference.xmlに追加する偽のToolbarPreferenceクラスを作成します(Gáborの答えを参照)。

1
Davideas

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

https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary

1

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

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

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

ライブラリは次のとおりです。 https://github.com/ferrannp/material-preferences

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

1
Ferran Negre