【问题标题】:Keep the actionbar displayed in when changing PreferenceScreen更改 PreferenceScreen 时保持操作栏显示
【发布时间】:2015-06-04 02:56:37
【问题描述】:

我正在尝试在我的偏好屏幕中显示一个操作栏。 为此,我在 SettingActivity 中添加了以下代码

public class PreferencesActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.preferences_activity);
        getFragmentManager().beginTransaction()
                .replace(R.id.container, new PreferencesFragment()).commit();

            getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP);
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }
}

然后是我在 PreferencesFragment 中的其余代码。 这很好用,但只要我按下 PreferenceScreen 首选项,操作栏就会隐藏。如果我回到首选项主屏幕,我可以再次看到它。 知道如何保持操作栏显示(并使用 PreferenceScreen 标签更新)吗?

编辑:查看 PreferenceScreen 代码,当单击 PreferenceScreen 时,它看起来像是打开了一个全屏对话框。因为我的偏好有一个标题,所以对话框也应该显示一个标题......但它没有

    // Set the title bar if title is available, else no title bar
    final CharSequence title = getTitle();
    Dialog dialog = mDialog = new Dialog(context, context.getThemeResId());
    if (TextUtils.isEmpty(title)) {
        dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    } else {
        dialog.setTitle(title);
    }

【问题讨论】:

  • 你是说ActionBar吗?
  • @user1026605 解决过这个问题吗?
  • 我刚刚添加了一个赏金;)所以不,我仍在寻找解决方案
  • 无法理解您的问题,请向我们展示两个屏幕的图片或其他内容
  • 你不明白哪一部分?我只希望在我导航到我的首选项时保持显示操作栏(又名:按下 PreferenceScreen)

标签: android android-actionbar preferenceactivity preferencefragment


【解决方案1】:

我创建了PreferenceCompatActivity,它是旧PreferenceActivity 的兼容AndroidX 的替代品。

它在内部使用兼容片段。请务必仅使用 androidx.preference.XXX 类而不是 android.preference.XXX 类。

public class PreferenceCompatActivity extends AppCompatActivity implements AppCompatCallback, PreferenceFragmentCompat.OnPreferenceStartScreenCallback {

    private PreferenceFragmentCompat fragment;

    public void addPreferencesFromResource(@XmlRes int preferencesResId) {
        fragment = new RootPreferencesFragment(preferencesResId);
        getSupportFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commitNow();
    }

    public PreferenceManager getPreferenceManager() {
        return fragment.getPreferenceManager();
    }

    public PreferenceScreen getPreferenceScreen() {
        return fragment.getPreferenceScreen();
    }

    public Preference findPreference(CharSequence key) {
        return fragment.findPreference(key);
    }

    @Override
    public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) {
        LowerPreferencesFragment lowerFragment = new LowerPreferencesFragment(pref);
        getSupportFragmentManager().beginTransaction().replace(android.R.id.content, lowerFragment).addToBackStack("lower").commit();
        return true;
    }

    public static class RootPreferencesFragment extends PreferenceFragmentCompat {

        private int preferencesResId;

        public RootPreferencesFragment(int preferencesResId) {
            this.preferencesResId = preferencesResId;
        }

        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
            addPreferencesFromResource(preferencesResId);
        }
    }

    public static class LowerPreferencesFragment extends PreferenceFragmentCompat {

        private PreferenceScreen prefs;

        public LowerPreferencesFragment() {
        }

        public LowerPreferencesFragment(PreferenceScreen prefs) {
            this.prefs = prefs;
        }

        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
            if (prefs != null) {
                setPreferenceScreen(prefs);
                prefs = null;
            }
        }
    }
}

see this gist

【讨论】:

    【解决方案2】:

    由于谷歌直到现在才修复它,实际上有一个更简单的解决方案:

    1. 将您的 SettingsActivity 类设置为仅从“Activity”扩展。

      public class SettingsActivity extends Activity { ...

    2. 在 v21/styles 文件夹中为 SettingsActivty 创建一个新主题,并将父级设置为“Theme.Material.*”

      <style name="CustomThemeSettings" parent="android:Theme.Material"> <item name="android:colorPrimary">@color/...</item> <item name="android:colorPrimaryDark">@color/...</item> <item name="android:colorAccent">@color/...</item> </style>

    3. 在 Manifest.xml 文件中设置新主题:

      <activity android:name=".SettingsActivity" android:label="@string/title_activity_settingsactivity" android:theme="@style/CustomThemeSettings" > </activity>

    4. 它只是工作:)

    5. (可选)如果您想为旧设备提供 Material Design 支持
      您可以将 SettingsActivity 放在 v21+ 文件夹中并创建另一个 具有父 AppCompat 的旧设备的 SettingsActivity。

    【讨论】:

      【解决方案3】:

      有同样的问题。嵌套的 PreferenceScreens 没有 ActionBar。单步执行代码后,似乎是由AppCompatActivityPreferenceScreen 之间的冲突引起的。

      一方面,AppCompatActivity 提供了自己的操作栏,因此需要一个从 Theme.AppCompat 降级的主题,该主题在某处指定 windowNoTitle = true(无法精确定位)。另一方面——PreferenceScreen 使用平台Dialog 和活动主题(而不是子主题,例如dialogTheme)。可能是一个错误。

      如果您不关心 Theme.AppCompat,这里有一个适用于 API 21+ 的简单解决方法:

      • 使用android.preference.PreferenceActivity 作为活动的基类
      • 为该活动创建一个主题:

        <!-- This theme is used to show ActionBar on sub-PreferenceScreens -->
        <style name="PreferenceTheme" parent="">
          <item name="android:windowActionBar">true</item>
          <item name="android:windowNoTitle">false</item>
        </style>
        
      • AndroidManifest.xml 中为此活动指定android:theme="@style/PreferenceTheme"

      您将获得的更像是一个标准的窗口标题,而不是一个完整的 ActionBar。我还没有弄清楚如何添加一个工作后退按钮等。

      如果您想与AppCompatActivity 和相关主题保持兼容,您需要在活动窗口上请求FEATURE_NO_TITLE。否则,您最终会在顶层PreferenceScreen 中看到两个操作栏(内置在顶部,支持在底部)。

      【讨论】:

        【解决方案4】:

        我终于设法找到了一种方法来做到这一点。 这有点难看,但确实有效。

        首先我在我的preferences.xml 文件中的每个PreferenceScreen 定义中添加一个相同的Intent(确保更新额外参数的值)

                <PreferenceScreen
                    android:key="pref1"
                    android:summary="Summary1"
                    android:title="Title1" >
                    <intent
                        android:action="android.intent.action.VIEW"
                        android:targetPackage="my.package"
                        android:targetClass="my.package.activity.PreferencesActivity" >
                        <extra android:name="page" android:value="pref1" />
                    </intent>
        ...
        
        </PreferenceScreen>
        

        顺便说一句 my.package.activity.PreferencesActivity 是我当前的偏好活动

        然后我在 Manifest 中添加一个意图过滤器

                <activity
                    android:name=".activity.PreferencesActivity"
                    android:configChanges="keyboardHidden|orientation|screenSize"
                    android:label="@string/settings" >
                    <intent-filter android:label="Pref" >
                        <action android:name="android.intent.action.VIEW" />
                        <category android:name="android.intent.category.PREFERENCE" />
                    </intent-filter>
          </activity>
        

        我在 PreferenceActivity 中添加了一些代码来处理这个

           @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.preferences_activity);
        
                this.fragment = new PreferencesFragment();
                this.fragment.setActivityIntent(getIntent());
                getFragmentManager().beginTransaction()
                        .replace(R.id.container, this.fragment).commit();
            }
        

        最后我在我的 PreferencesFragment 类中添加以下代码

            public void setActivityIntent(final Intent activityIntent) {
         if (activityIntent != null) {
                                if (Intent.ACTION_VIEW.equals(activityIntent.getAction())) {
        
                                if (intent.getExtras() != null) {
                                    final String page = intent.getExtras().getString("page");
                                    if (!TextUtils.isEmpty(page)) {
                                        openPreferenceScreen(page);
                                    }
                                }
                            }
            }
        
        private void openPreferenceScreen(final String screenName) {
            final Preference pref = findPreference(screenName);
            if (pref instanceof PreferenceScreen) {
                final PreferenceScreen preferenceScreen = (PreferenceScreen) pref;
                ((PreferencesActivity) getActivity()).setTitle(preferenceScreen.getTitle());
                setPreferenceScreen((PreferenceScreen) pref);
            }
        }
        

        【讨论】:

        • 稍作修改后这对我有用:PreferencesFragmentPreferenceManager 直到调用 onCreate() 才会创建,因此尝试在 @ 中查找并导航到正确的屏幕987654329@ 将失败。相反,我使用setActivityIntent() 提取并存储PreferenceScreen 的名称以供使用,然后在onCreate() 中调用openPreferenceScreen() 导航到它。
        • 我提出了一个缺陷,请投赞成票:code.google.com/p/android/issues/detail?id=207718
        • 我刚试过这个,每当我尝试打开子屏幕时,它都会打开我原来的 PreferenceFragment 的另一个副本。
        【解决方案5】:

        注意:仅适用于 API>=14

        Source1Source2

        PreferenceActivity1.java

        public class PreferenceActivity1 extends android.preference.PreferenceActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref1);
        
        }
        
        @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();
                }
            });
        }
        }
        

        PreferenceActivity2.java

        public class PreferenceActivity2 extends android.preference.PreferenceActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref2);
        }
        @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();
                }
            });
        }
        }
        

        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/app_name"
        />
        

        pref1.xml(xml)

        <?xml version="1.0" encoding="utf-8"?>
        <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
        android:theme="@android:style/Theme.Light" >
        
        <PreferenceCategory android:title="Main Preferences" >
            <CheckBoxPreference
                android:key="wifi enabled"
                android:title="WiFi" />
        </PreferenceCategory>
        
        <PreferenceScreen
            android:key="key1"
            android:summary=""
            android:title="Wifi Settings" >
            <intent
                android:action="android.intent.action.VIEW"
                android:targetClass="com.example.PreferenceActivity2"
                android:targetPackage="com.example" />
        </PreferenceScreen>
        
        </PreferenceScreen>
        

        pref2.xml(xml)

        <?xml version="1.0" encoding="utf-8"?>
        <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
        android:theme="@android:style/Theme.Light" >
        
        <PreferenceCategory android:title="Wifi Settings" >
            <CheckBoxPreference
                android:key="prefer wifi"
                android:title="Prefer WiFi" />
        </PreferenceCategory>
        
        </PreferenceScreen>
        

        清单

        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name" >
            <activity
                android:name="com.example.PreferenceActivity1"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity
                android:name="com.example.PreferenceActivity2"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
        </application>
        

        结果

        【讨论】:

        • 正如我的问题中所解释的,问题不在于在首选项“主屏幕”上显示操作栏。当您按下 WiFi 设置时会发生什么?操作栏是否仍然显示?顺便说一句,我的最小 SDK 是 14
        • 无法使用默认的 ActionBar 使其工作?
        • 我有很多设置嵌入到具有多个级别的 PreferenceScreen 的单个资源文件中。根据我的喜好使用多个活动/资源文件不是一种选择。
        • addPreferencesFromResource API 在您从 Activity 中使用它的方式中已被弃用。来自 API 11,您推荐来自 API 14。
        【解决方案6】:

        正如您在问题中提到的,全屏 Dialog 可能是个问题。

        尝试将Dialog 样式更改为:

        <style name="Theme.Holo.Dialog">
        

        或具有这些属性的样式:

        <item name="windowActionBar">true</item>
        <item name="windowNoTitle">false</item>
        

        Here 您可以阅读如何获取对Dialog 的引用。

        【讨论】:

          【解决方案7】:

          但只要我按下 PreferenceScreen 首选项,操作栏就会隐藏。如果我返回首选项主屏幕,我可以再次看到它。

          我猜你在点击首选项时正在启动一个新活动

          您的 Preference 片段应如下所示

              public static class PreferencesFragment extends PreferenceFragment {
          
              public PlaceholderFragment() {
              }
          
              @Override
              public void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  addPreferencesFromResource(R.xml.your_preferences);
              }
          }
          

          然后按如下方式对 your_preferences 进行采样

          <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_height="fill_parent"
          android:layout_width="fill_parent" >
          
          <PreferenceCategory
              android:title="@string/pref_category_title">
              <PreferenceScreen
                  android:title="@string/title"
                  android:summary="@string/summary">
          
                  <intent
                      android:targetClass="com.your.package.Youractivity "
                      android:targetPackage="com.your.package"/>
          
              </PreferenceScreen>
              <PreferenceScreen
                  android:title="@string/another_title">
                  <intent
                      android:targetClass="com.your.package.activity2"
                      android:targetPackage="com.your.package.activity"/>
              </PreferenceScreen>
          </PreferenceCategory>
          

          最后,Youractivity 应该从 ActionBarActivity 扩展的主要内容

              public class Youractivity extends ActionBarActivity {
          }
          

          上面的代码对我有用。

          【讨论】:

          • 不,我不是。我只是使用标准的preference.xml res文件,以及一些标准的PreferenceScreen pref,如我的问题中所述。我没有从 PreferenceScreen 开始另一个活动。我只是在 PreferenceScreen 标签中嵌入了其他首选项
          【解决方案8】:

          我制作了一个在首选项活动中确实有一个操作栏的应用。我似乎看不到这样做的关键,尽管我确实记得我花了一些时间才把它弄好。

          看起来我们的代码很相似。唯一引起我注意的是这个导入:import android.support.v7.app.ActionBarActivity;

          如果有帮助请告诉我

          public class SettingsActivity extends ActionBarActivity {
          
          
              @Override
              public void onCreate(Bundle savedInstanceState) {
          
                  super.onCreate(savedInstanceState);
          
                  getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragment() ).commit();
              } // End of onCreate
          
          
          
              static public class PrefsFragment extends PreferenceFragment {
          
                  @Override
                  public void onCreate(Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
          
                      addPreferencesFromResource(R.xml.preferences);  // Load the preferences from an XML resource
          
          
                  }
          
              }  // end of PrefsFragment
          
          }
          

          补充:你的styles.xml中有这个吗?

          <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
          </style>
          

          【讨论】:

          • 正如我的问题中所解释的,我已经在设置主屏幕中显示了操作栏。问题是,一旦我按下“PreferenceScreen”首选项,它就会消失。我想保留它并使用已按下的 PreferenceScreen 的名称更新操作栏显示
          • @Bruno Carrier,PreferenceFragment 支持 API 级别 Honey Comb
          • 是的,但它的工作方式并不完全相同。请参阅此帖子以获得完整的答案:stackoverflow.com/questions/10186697/…
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多