Toolbar is hidden in nested PreferenceScreen

前端 未结 4 616
一生所求
一生所求 2021-02-02 13:36

I use PreferenceFragment in ActionBarActivity from support-v7 library.
In the Activity I have Toolbar. Everything goes okay, until I o

相关标签:
4条回答
  • 2021-02-02 14:15

    As the issue comes from the part that you are still in the same activity/fragment and the nested pref screen is just a dialog you can do the following:

    • You can set preference click listener
    • Get the root view from the dialog: (PreferenceScreen)preference).getDialog().getWindow() .getDecorView().getRootView());

    • Recursively search until find a stub view (there is one, unfortunately I do not know the android.R.id.xxxxx) and set what layout you need as title which will look like the toolbar(You can inflate toolbar):

      private Toolbar toolbar;
      
          public void findViewStub(ViewGroup viewGroup) {
          int childCount = viewGroup.getChildCount();
          for (int i = 0; i < childCount; i++) {
              View childView = viewGroup.getChildAt(i);
              if( childView instanceof ViewStub){
                  ((ViewStub)childView).setLayoutResource(R.layout.your_title_layout);
                 toolbar =  ((ViewStub)childView).inflate();
              }
              if (childView instanceof ViewGroup) {
                  findViewStub((ViewGroup) childView);
              }
          }
      
        }
      
      toolbar.setNavigationIcon();
      toolbar.setNavigationOnClickListener();
      toolbar.setTitle();
      
    • In the layout you can put only a toolbar. And set the back icon. Register for click on it and having reference to the fragment, on click you can dismiss the dialog. You have set title and etc.

    0 讨论(0)
  • 2021-02-02 14:20

    I found the solution on my own. I used a small work-around of all this nested PreferenceScreen's. I simply made a separation to different xml-preference files, created an additional Fragment which extends PreferenceFragment and there I show an appropriate nested preference screen.
    Maybe somebody would found this useful.

    Github sources link.

    Some code examples below:

    main_preferences.xml

    <?xml version="1.0" encoding="utf-8"?>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <PreferenceCategory android:title="Main category" >
    
            <EditTextPreference
                android:defaultValue="defaultValue"
                android:key="key_global_setting"
                android:title="Global title" />
    
        </PreferenceCategory>
    
        <PreferenceCategory android:title="Nested screens" >
    
            <Preference
                android:key="NESTED_KEY1"
                android:persistent="false"
                android:title="Nested screen #1" />
    
            <Preference
                android:key="NESTED_KEY2"
                android:persistent="false"
                android:title="Nested screen #2" />
    
        </PreferenceCategory>
    
    </PreferenceScreen> 
    

    nested_screen1_preferences.xml

    <?xml version="1.0" encoding="utf-8"?>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
        android:title="Nested screen #1" >
    
        <CheckBoxPreference
            android:defaultValue="false"
            android:key="nested_screen_1_1"
            android:title="Nested screen 1.1 check box" />
    
        <CheckBoxPreference
            android:defaultValue="true"
            android:key="nested_screen_1_2"
            android:title="Nested screen 1.2 check box" />
    </PreferenceScreen>
    

    nested_screen2_preferences.xml

    <?xml version="1.0" encoding="utf-8"?>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
        android:title="Nested screen #2">
    
        <CheckBoxPreference
            android:defaultValue="true"
            android:key="nested_screen2"
            android:title="Nested screen 2 check box" />
    </PreferenceScreen>
    

    SettingsActivity.java

    public class SettingsActivity extends ActionBarActivity implements MyPreferenceFragment.Callback {
    
        private static final String TAG_NESTED = "TAG_NESTED";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_settings);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            if (toolbar != null) {
                setSupportActionBar(toolbar);
                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            }
    
            if (savedInstanceState == null) {
                getFragmentManager().beginTransaction()
                        .add(R.id.contentSettings, new MyPreferenceFragment())
                        .commit();
            }
        }
    
        @Override
        public void onBackPressed() {
            // this if statement is necessary to navigate through nested and main fragments
            if (getFragmentManager().getBackStackEntryCount() == 0) {
                super.onBackPressed();
            } else {
                getFragmentManager().popBackStack();
            }
        }
    
        @Override
        public void onNestedPreferenceSelected(int key) {
            getFragmentManager().beginTransaction().replace(R.id.contentSettings, NestedPreferenceFragment.newInstance(key), TAG_NESTED).addToBackStack(TAG_NESTED).commit();
        }    
    }
    

    MyPreferenceFragment.java

    // The main preference fragment class
    public class MyPreferenceFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener {
    
        private Callback mCallback;
    
        private static final String KEY_1 = "NESTED_KEY1";
        private static final String KEY_2 = "NESTED_KEY2";
    
        @Override
        public void onAttach(Activity activity) {
    
            super.onAttach(activity);
    
            if (activity instanceof Callback) {
                mCallback = (Callback) activity;
            } else {
                throw new IllegalStateException("Owner must implement Callback interface");
            }
        }
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // Load the preferences from an XML resource
            addPreferencesFromResource(R.xml.main_preferences);
    
            // add listeners for non-default actions
            Preference preference = findPreference(KEY_1);
            preference.setOnPreferenceClickListener(this);
    
            preference = findPreference(KEY_2);
            preference.setOnPreferenceClickListener(this);
        }
    
        @Override
        public boolean onPreferenceClick(Preference preference) {
            // here you should use the same keys as you used in the xml-file
            if (preference.getKey().equals(KEY_1)) {
                mCallback.onNestedPreferenceSelected(NestedPreferenceFragment.NESTED_SCREEN_1_KEY);
            }
    
            if (preference.getKey().equals(KEY_2)) {
                mCallback.onNestedPreferenceSelected(NestedPreferenceFragment.NESTED_SCREEN_2_KEY);
            }
    
            return false;
        }
    
        public interface Callback {
            public void onNestedPreferenceSelected(int key);
        }
    }
    

    NestedPreferencesFragment.java

    public class NestedPreferenceFragment extends PreferenceFragment {
    
        public static final int NESTED_SCREEN_1_KEY = 1;
        public static final int NESTED_SCREEN_2_KEY = 2;
    
        private static final String TAG_KEY = "NESTED_KEY";
    
        public static NestedPreferenceFragment newInstance(int key) {
            NestedPreferenceFragment fragment = new NestedPreferenceFragment();
            // supply arguments to bundle.
            Bundle args = new Bundle();
            args.putInt(TAG_KEY, key);
            fragment.setArguments(args);
            return fragment;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
    
            checkPreferenceResource();
        }
    
        private void checkPreferenceResource() {
            int key = getArguments().getInt(TAG_KEY);
            // Load the preferences from an XML resource
            switch (key) {
                case NESTED_SCREEN_1_KEY:
                    addPreferencesFromResource(R.xml.nested_screen1_preferences);
                    break;
    
                case NESTED_SCREEN_2_KEY:
                    addPreferencesFromResource(R.xml.nested_screen2_preferences);
                    break;
    
                default:
                    break;
            }
        }
    
    }
    
    0 讨论(0)
  • 2021-02-02 14:23

    In my solution you only need one AppCompatActivity and one PreferenceFragement, but several XML files, each having only one level of PreferenceScreens.

    XML file list

    • top level PreferenceScreen
    • second level PreferenceScreen 0
    • second level PreferenceScreen 1
    • second level PreferenceScreen 2
    • ...

    This code is for one sub-level (for simplicity and to get the idea), but you can easily extend it to have arbitrary sub-levels of PreferenceScreens.

    SettingsFragment.java

    public class SettingsFragment extends PreferenceFragment
    {
        private int xmlId;
    
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            xmlId = R.xml.preferences;
            addPreferencesFromResource(xmlId);
        }
    
        public void changePrefScreen(int xmlId, int titleId)
        {
            this.xmlId = xmlId;
            ((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(getActivity().getResources().getString(titleId));
            getPreferenceScreen().removeAll();
            addPreferencesFromResource(xmlId);
        }
    
        // will be called by SettingsActivity (Host Activity)
        public void onUpButton()
        {
            if(xmlId == R.xml.preferences) // in top-level
            {
                // Switch to MainActivity
                Intent intent = new Intent(getActivity(), MainActivity.class);
                startActivity(intent);
            }
            else // in sub-level
            {
                changePrefScreen(R.xml.preferences, R.string.settings);
            }
        }
    
        @Override
        public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
        {
            String key = preference.getKey();
    
            //
            // Top level PreferenceScreen
            //
            if(key.equals("top_key_0"))
            {
                changePrefScreen(R.xml.download_preference_screen, R.string.download_database); // descend into second level
            }
    
            // ...
    
            //
            // Second level PreferenceScreens
            //
            if (key.equals("second_level_key_0"))
            {
               // do something...
            }
    
            // ...
         }
    

    SettingsActivity.java

    public class SettingsActivity extends AppCompatActivity
    {
        SettingsFragment settingsFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
    
            settingsFragment = new SettingsFragment();
    
            // Display the fragment as the main content.
            getFragmentManager().beginTransaction()
                    .replace(android.R.id.content, settingsFragment)
                    .commit();
        }
    
        //
        // Handle what happens on up button
        //
        @Override
        public boolean onOptionsItemSelected(MenuItem item) 
        {
            switch (item.getItemId()) 
            {
                case android.R.id.home:
                    settingsFragment.onUpButton();
                    return true;
            }
            return true;
        }
    
        // ...
    }
    

    Technically it should work for all Android versions for which the PreferenceFragment is available.

    0 讨论(0)
  • 2021-02-02 14:26

    Here comes my solution, which is inspired by the original answer but not that complicated. Maybe it'll help someone...

    layout/settings.xml:

        <RelativeLayout 
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
    
            <include
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                layout="@layout/toolbar" />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/content"
                android:layout_below="@+id/toolbar"/>
    
        </RelativeLayout>
    

    Classes:

    public class SettingsActivity extends ActionBarActivity {
      @Override
      protected void onCreate( Bundle savedInstanceState ) {
        setContentView( R.layout.settings );
        super.onCreate( savedInstanceState ); 
        initializeSupportActionBar();
        getFragmentManager().beginTransaction().replace( R.id.content, new MainFragment() ).commit();
      }
    
      @Override
      public void onBackPressed() {
        if( !getFragmentManager().popBackStackImmediate() ) super.onBackPressed();
      }
    }
    
    public class MainFragment extends PreferenceFragment {
    
      public MainFragment() {}
    
      @Override
      public void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );
        addPreferencesFromResource( R.xml.pref_main );
        // "nested" is the <Preference android:key="nested" android:persistent="false"/>`
        findPreference( "nested" ).setOnPreferenceClickListener( new OnPreferenceClickListener() {
          @Override public boolean onPreferenceClick( Preference preference ) {
            getFragmentManager().beginTransaction().replace( R.id.content, new NestedFragment() ).addToBackStack( NestedFragment.class.getSimpleName() ).commit();
            return true;
          }
        } );
      }
    
    public class NestedFragment extends PreferenceFragment {
      ...
    }
    

    I tested it on 4.3 and 5.0.2 and no limitation on nesting levels applies

    0 讨论(0)
提交回复
热议问题