AppCompatPreferenceActivity strange padding on left and right in Android 4.4
Asked Answered
K

5

11

I have an SettingsActivity extending AppCompatPreferenceActivity.

my pref_headers.xml looks like this:

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    <header
        android:fragment="com.blabla.activities.fragments.ProfileFragment"
        android:icon="@drawable/ic_users"
        android:title="Profil">
    </header>
</preference-headers>

Where the fragment code looks like this:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class ProfileFragment extends PreferenceFragment {
    @BindView(R.id.email)
    TextView email;
    @BindView(R.id.username)
    TextView username;
    @BindView(R.id.loadingPanel)
    RelativeLayout loadingPanel;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_profile, container, false);
        ButterKnife.bind(this, rootView);

        if (setActionbarListener != null) {
            setActionbarListener.setActionbarTitle("Profil");
        }

        loadingPanel.setVisibility(View.VISIBLE);
        UsernameHandler uHandler = UsernameHandler.getInstance(new UsernameResult() {
            @Override
            public void finished(String uname) {
                username.setText(uname);
                loadingPanel.setVisibility(View.GONE);  // hide loading spinner
            }
        });
        email.setText(MainActivity.getFbUser().getEmail());

        return rootView;
    }
}

My Problem is, that there is some space on the left and the right side to the layout I am loading. This padding definitely does not come from the layout itself. When starting the app in android 8.1 there is no such padding/margin.

See the picture:

enter image description here

Finally the code of the SettingsActivity:

public class SettingsActivity extends AppCompatPreferenceActivity implements OnSetActionbarTitleListener {

    /**
     * A preference value change listener that updates the preference's summary
     * to reflect its new value.
     */
    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();

            if (preference instanceof ListPreference) {
                // For list preferences, look up the correct display value in
                // the preference's 'entries' list.
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);

                // Set the summary to reflect the new value.
                preference.setSummary(
                        index >= 0
                                ? listPreference.getEntries()[index]
                                : null);

            } else if (preference instanceof RingtonePreference) {
                // For ringtone preferences, look up the correct display value
                // using RingtoneManager.
                if (TextUtils.isEmpty(stringValue)) {
                    // Empty values correspond to 'silent' (no ringtone).
                    preference.setSummary(R.string.pref_ringtone_silent);

                } else {
                    Ringtone ringtone = RingtoneManager.getRingtone(
                            preference.getContext(), Uri.parse(stringValue));

                    if (ringtone == null) {
                        // Clear the summary if there was a lookup error.
                        preference.setSummary(null);
                    } else {
                        // Set the summary to reflect the new ringtone display
                        // name.
                        String name = ringtone.getTitle(preference.getContext());
                        preference.setSummary(name);
                    }
                }

            } else {
                // For all other preferences, set the summary to the value's
                // simple string representation.
                preference.setSummary(stringValue);
            }
            return true;
        }
    };

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    /**
     * Binds a preference's summary to its value. More specifically, when the
     * preference's value is changed, its summary (line of text below the
     * preference title) is updated to reflect the value. The summary is also
     * immediately updated upon calling this method. The exact display format is
     * dependent on the type of preference.
     *
     * @see #sBindPreferenceSummaryToValueListener
     */
    public static void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

        // Trigger the listener immediately with the preference's
        // current value.
        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();
    }


    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    private void setupActionBar() {
        getLayoutInflater().inflate(R.layout.pref_toolbar, (ViewGroup)findViewById(android.R.id.content));
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        if (toolbar != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }

        setActionBarBelowContent();
    }

    private void setActionBarBelowContent() {
        int horizontalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
        int verticalMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
        int actionBarHeight = UserInterfaceUtils.getActionBarHeight(MainActivity.context);
        getListView().setPadding(0, actionBarHeight+10, 0, verticalMargin);
    }

    @Override
    public void onHeaderClick(Header header, int position) {
        setActionBarBelowContent();
        super.onHeaderClick(header, position);
    }

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            onBackPressed();
            return true;
        }
        return super.onMenuItemSelected(featureId, item);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }

    /**
     * This method stops fragment injection in malicious applications.
     * Make sure to deny any unknown fragments here.
     */
    @Override
    protected boolean isValidFragment(String fragmentName) {
        return PreferenceFragment.class.getName().equals(fragmentName)
                || SettingsFragment.class.getName().equals(fragmentName)
                || FeedbackFragment.class.getName().equals(fragmentName)
                || ProfileFragment.class.getName().equals(fragmentName)
                || AGBFragment.class.getName().equals(fragmentName)
                || PrivacyFragment.class.getName().equals(fragmentName)
                || FAQFragment.class.getName().equals(fragmentName)
                || LicenseFragment.class.getName().equals(fragmentName);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        setActionbarTitle("Einstellungen");
    }

    @Override
    public void setActionbarTitle(String title) {
        getSupportActionBar().setTitle(title);
    }
}

Edit - added layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/item_list_item"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardUseCompatPadding="true"
        app:cardElevation="4dp"
        app:cardCornerRadius="0dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"
            android:padding="15dp"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/preUsername"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Dein Benutzername:"
                    android:textAppearance="@style/profileText"
                    android:textStyle="bold"/>

                <TextView
                    android:id="@+id/username"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAppearance="@style/profileText"
                    android:layout_marginLeft="5dp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/preEmail"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAppearance="@style/profileText"
                    android:textStyle="bold"
                    android:text="Deine Email:"/>

                <TextView
                    android:id="@+id/email"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAppearance="@style/profileText"
                    android:layout_marginLeft="5dp"/>

            </LinearLayout>

        </LinearLayout>
    </android.support.v7.widget.CardView>

    <RelativeLayout
        android:id="@+id/loadingPanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_vertical|center_horizontal"
        android:gravity="center">

        <ProgressBar
            android:id="@+id/progressBar"
            style="@style/MyProgressBarSpinner"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminate="true" />
    </RelativeLayout>

</RelativeLayout>
Kareenkarel answered 30/7, 2018 at 14:21 Comment(9)
Can you post your layout as well?Eisen
@Eisen I added it to the question, but as mentioned I don't think, that it has anything to do with the layout of the fragment itself.Kareenkarel
It is the card compat padding coming from your cardview layoutEisen
@Eisen No it is not. I even got the padding when I am using a clear relativelayout with just a textview inside of it or something similar. So I am really really sure, that this has nothing to do with my fragment layout itself.Kareenkarel
Change your image then, because it gives the wrong idea. Your image padding comes from compat padding...Eisen
@Eisen nope, it does not.Kareenkarel
It looks like from Activity layoutSheedy
These sorts of things can be fluid at times between different API levels. I think that you issue stems from a layout difference between API versions. Can you post a simple demo app that show this problem to aid in tracking down the issue? If you do, I think that you will get a quick answer.Anaxagoras
If you post compilable demo here you more likely get an answer here.Bouleversement
S
3

This is as per design i.e. expected behavior that you are getting padding on KitKat devices. From Official documentation:

On pre-Lollipop platforms, CardView does not clip the bounds of the Card for the rounded corners. Instead, it adds padding to content so that it won't overlap with the rounded corners. You can disable this behavior by setting this field to false.

Solution:

In XML Layout: app:cardPreventCornerOverlap="false"

OR

In Java: setPreventCornerOverlap(false);

So in your case:

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardUseCompatPadding="true"
    app:cardElevation="4dp"
    app:cardPreventCornerOverlap="false"
    app:cardCornerRadius="0dp">

Hope it will help you!

Slotter answered 2/8, 2018 at 14:4 Comment(1)
Sadly this does not fix my issue :( I even have this problem when not using a cardview.Kareenkarel
B
2

You're right that this padding is not because of CardView:

enter image description here

It happens on pre-lolipop because of prefs paddings:

enter image description here

enter image description here

In order to remove this border in your case you just could remove paddings from parent view after view is created

 @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        View containerParent = (View)view.getParent();
        containerParent.setPadding(0, 0, 0, 0);
    }

This will remove paddings on pre-lolipop

enter image description here

Bouleversement answered 17/8, 2018 at 8:22 Comment(0)
S
0

If you are using app:cardUseCompatPadding=true. Use negative layout_margin, to balance-out the unwanted padding from the compat library. Example below:

<android.support.v7.widget.CardView

   android:layout_width="match_parent"
   android:layout_margin="-10dp"
   android:layout_height="wrap_content"
   app:cardUseCompatPadding="true"
   app:cardElevation="4dp"
   app:cardCornerRadius="0dp">

// Your other views

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

This will remove unwanted space and look similar for all OS (Not tested in Orio)

For more detailed about cardview Android CardView document. and also check this stackoverflow answer Android layout unwanted padding

Seignior answered 8/8, 2018 at 13:27 Comment(1)
As I already stated in comments and the other answer. This Problem has nothing to do with any padding of CardView.Kareenkarel
P
0

I think I remember I had such issues with Preferences. I think I used:

if(view != null) {
    ListView lv = (ListView) view.findViewById(android.R.id.list);
    lv.setPadding(0, 0, 0, 0);
}

in onCreateView().

Putscher answered 8/8, 2018 at 13:55 Comment(1)
you mean the onCreate from the SettingsActivity? Then where ist the view coming from? I think this does not solve my Issue because you are trying to change the padding of the initial listview in the Settingsactivity. But I am one layer beneath already in my own Fragment.Kareenkarel
C
0

Did you try to use PreferenceFragmentCompat, when extending your ProfileFragment like: public class ProfileFragment extends PreferenceFragmentCompat ? Looks like PreferenceFragment is deprecated .

Carmarthenshire answered 16/8, 2018 at 11:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.