Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding toolbar to PreferenceActivity via AppCompatPreferenceActivity causes overlapping

Tags:

android

I had gone through How to add toolbars to AppCompatPreferenceActivity?

I'm using appcompat-v7:23.0.1 and support-v4:23.0.1

Before using AppCompayPreferenceActivity, my PreferenceActivity looks the following without toolbar.

enter image description here

Without Toolbar

public class JStockPreferenceActivity extends PreferenceActivity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
            // Display the fragment as the main content.
            JStockPreferenceFragment jStockPreferenceFragment = JStockPreferenceFragment.newInstance();
            jStockPreferenceFragment.setArguments(this.getIntent().getExtras());
            this.getFragmentManager().beginTransaction().replace(android.R.id.content, jStockPreferenceFragment).commit();
    }
}

After using AppCompayPreferenceActivity, with some Toolbar initialization code, the outcome looks as the following

enter image description here

The outcome isn't as expected :-

  1. The Toolbar overlaps with PreferenceFragment
  2. When touching on Toolbar, the event will be consumed by PreferenceFragment. This means, when you touch on toolbar, "Table header" preference will be touched instead.

With Toolbar

public class JStockPreferenceActivity extends AppCompatPreferenceActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
            // Display the fragment as the main content.
            JStockPreferenceFragment jStockPreferenceFragment = JStockPreferenceFragment.newInstance();
            jStockPreferenceFragment.setArguments(this.getIntent().getExtras());
            this.getFragmentManager().beginTransaction().replace(android.R.id.content, jStockPreferenceFragment).commit();
        }
        initToolbar();
    }

    private void initToolbar() {
        Toolbar toolbar;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            ViewGroup root = (ViewGroup) findViewById(android.R.id.list).getParent().getParent().getParent();
            toolbar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.toolbar, root, false);
            root.addView(toolbar, 0);
        } else {
            toolbar = null;
        }

        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }
}

My toolbar is

toolbar.xml

<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"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:elevation="4dp"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" >

    <!-- android:elevation="4dp" is used due to http://www.google.com/design/spec/what-is-material/elevation-shadows.html#elevation-shadows-elevation-android- -->

</android.support.v7.widget.Toolbar>

I was wondering, what I had did wrong, which causes Toolbar overlapped with PreferenceFragment

like image 692
Cheok Yan Cheng Avatar asked Oct 19 '22 01:10

Cheok Yan Cheng


1 Answers

After some research and getting advice from Ian Lake, I manage to make it work by

  1. Change from AppCompatPreferenceActivity, to AppCompatActivity+PreferenceFragmentCompat

The following solution is workable for API 10 and above.


JStockPreferenceActivity.java

public class JStockPreferenceActivity extends AppCompatActivity {

    @SuppressWarnings("deprecation")
    @SuppressLint("NewApi")
    @Override
    public void onCreate(Bundle savedInstanceState) {            
        super.onCreate(savedInstanceState);

        setContentView(R.layout.jstock_preference_activity);

        initToolbar();

        if (savedInstanceState == null) {
            // Display the fragment as the main content.
            JStockPreferenceFragment jStockPreferenceFragment = JStockPreferenceFragment.newInstance();
            jStockPreferenceFragment.setArguments(this.getIntent().getExtras());
            this.getSupportFragmentManager().beginTransaction().replace(R.id.content, jStockPreferenceFragment).commit();
        }
    }

JStockPreferenceFragment.java

public class JStockPreferenceFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener, PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {

    public static JStockPreferenceFragment newInstance() {
        return new JStockPreferenceFragment();
    }

However, by doing so, there is a shortcoming. Your previous custom DialogPreference no longer work. To solve this, you need to

  1. Replace DialogPreference with PreferenceDialogFragmentCompat.
  2. Replace DialogPreference in XML with ListPreference. (I'm not exactly sure whether ListPreference as replacement is a right way. It works anyway)
  3. Manually show PreferenceDialogFragmentCompat, in PreferenceFragmentCompat's onPreferenceDisplayDialog.

JStockPreferenceFragment.java

public class JStockPreferenceFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener, PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {

    public static JStockPreferenceFragment newInstance() {
        return new JStockPreferenceFragment();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Showing custom dialog preference.
    private void showPreferenceDialogFragmentCompat(PreferenceDialogFragmentCompat preferenceDialogFragmentCompat) {
        preferenceDialogFragmentCompat.setTargetFragment(this, 0);
        preferenceDialogFragmentCompat.show(this.getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG");
    }

    private void showCurrencySymbolPreferenceDialogFragmentCompat(Preference preference) {
        CurrencySymbolPreferenceDialogFragmentCompat currencySymbolPreferenceDialogFragmentCompat = CurrencySymbolPreferenceDialogFragmentCompat.newInstance(preference.getKey());
        showPreferenceDialogFragmentCompat(currencySymbolPreferenceDialogFragmentCompat);
    }

    // Showing custom dialog preference.
    ////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Callback when we are using custom dialog preference.
    @Override
    public Fragment getCallbackFragment() {
        return this;
    }

    @Override
    public boolean onPreferenceDisplayDialog(PreferenceFragmentCompat preferenceFragmentCompat, Preference preference) {
        final String key = preference.getKey();

        if (_CURRENCY_SYMBOL_OPTIONS.equals(key)) {
            showCurrencySymbolPreferenceDialogFragmentCompat(preference);
            return true;
        }

        return false;
    }
    // Callback when we are using custom dialog preference.
    ////////////////////////////////////////////////////////////////////////////////////////////////

CurrencySymbolPreferenceDialogFragmentCompat.java

public class CurrencySymbolPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {

    public CurrencySymbolPreferenceDialogFragmentCompat() {
    }

    public static CurrencySymbolPreferenceDialogFragmentCompat newInstance(String key) {
        CurrencySymbolPreferenceDialogFragmentCompat fragment = new CurrencySymbolPreferenceDialogFragmentCompat();
        Bundle b = new Bundle(1);
        b.putString("key", key);
        fragment.setArguments(b);
        return fragment;
    }

    @Override
    public void onDialogClosed(boolean positiveResult) {
        if (positiveResult) {
            ...
            this.getPreference().setSummary(getSummary());
            ...
        }
    } 
}

preferences.xml

<android.support.v7.preference.ListPreference
    android:title="@string/preference_currency_symbol_title"
    android:key="_CURRENCY_SYMBOL_OPTIONS" />  

Please note that, you need to add the following item in your theme.

<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>

Some bugs regarding theme

However, the theme-ing isn't perfect yet - PreferenceFragmentCompat requires preferenceTheme to be set

This is a known issues : https://code.google.com/p/android/issues/detail?id=183376

There is proposed workaround https://stackoverflow.com/a/32108439/72437 But, the workaround will only work for v14 and above, not v7 and above.

like image 70
Cheok Yan Cheng Avatar answered Oct 23 '22 09:10

Cheok Yan Cheng