Vitalii
Vitalii

Reputation: 11091

Android KitKat: Snackbar is not in the bottom of the screen

I add a Snackbar to my app. The problem is that in API 19 it's not at the bottom of the screen.

enter image description here

In API 21 it's ok. Here is my layout

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

<data />
 <android.support.design.widget.CoordinatorLayout
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="true"
        android:focusableInTouchMode="true">

        <EditText

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@string/home_search_input_hint"
            android:inputType="text"
            android:maxLength="30"
            android:maxLines="1"/>

    </android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
</layout>

And my OnCreate

 @Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_home);
    super.onCreate(savedInstanceState);
    // binding
    binding = DataBindingUtil.setContentView(this, R.layout.activity_home);


    // snackbar test
    Snackbar snackbar = Snackbar.make(binding.root, "Snackbar", Snackbar.LENGTH_INDEFINITE);

    snackbar.show();
}

Do you have any ideas how to fix it?

UPDATE: It seems that margin from the bottom is really random, I rerun emulator and see this.

enter image description here

and this

enter image description here

Upvotes: 13

Views: 2560

Answers (4)

Johnny Five
Johnny Five

Reputation: 1015

This is a bug which is still not fixed.

Workaround - small delay on pre-lollipop devices. Delay not noticeable on UI.

Put these methods in your base fragment and base activity and use everywhere:

protected ViewGroup getRootView() {
    return (ViewGroup) getView().getParent();
}

protected void showSnackbar(@StringRes int resId) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        new Handler().postDelayed(() -> Snackbar.make(getRootView(), resId, Snackbar.LENGTH_SHORT).show(), 200);
    } else {
        Snackbar.make(getRootView(), resId, Snackbar.LENGTH_SHORT).show();
    }
}

protected void showSnackbar(String message) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        new Handler().postDelayed(() -> Snackbar.make(getRootView(), message, Snackbar.LENGTH_SHORT).show(), 200);
    } else {
        Snackbar.make(getRootView(), message, Snackbar.LENGTH_SHORT).show();
    }
}

Upvotes: 1

Mr-IDE
Mr-IDE

Reputation: 7661

To workaround it, use a small time delay before showing the Snackbar. This is needed if you want to show the Snackbar immediately when the screen displays, in onCreateView() or onCreate().

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        // For com.android.support:design:v26 or v27, use a small
        // time delay, to prevent bottom gap bug on Android 4.4
        if (isAdded()) { snackbar.show(); }
    }
}, 500);

Because you have a time delay, remember to protect against null Activity by checking for isAdded() or check getActivity() != null.

Upvotes: 4

Dmitrii Nikitin
Dmitrii Nikitin

Reputation: 41

If you use 26 or 27 support, it is probably this known bug: Google Issue Tracker: Snackbar wrong placement on the Android 4x versions

Upvotes: 4

Shyam Sunder
Shyam Sunder

Reputation: 703

This issue can be avoided by moving the code which shows snackbar to onGlobalLayout() like following.

binding.root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
        {
            @Override
            public void onGlobalLayout()
            {
                // snackbar test
                Snackbar snackbar = Snackbar.make(binding.root, "Snackbar", Snackbar.LENGTH_INDEFINITE);
                snackbar.show();

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    binding.root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                } else {
                    binding.root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
            }
        });

Upvotes: 2

Related Questions