Search code examples
androidandroid-toast

How to make a custom toast layout to really fill fullscreen in Android?


I face a little problem with my custom toast design in my Android app.

I defined the toast XML like so in notifications_info.xml (simplified to the background only here):

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/Fifty_Percent_Black"
    android:gravity="center"
>
    <!-- Centered round-corner background, text and icon here -->
</RelativeLayout>

I use it like so:

// Load the XML layout using inflater
notificationLayout = inflater.inflate(R.layout.notifications_info, aParentView, false);
// Create the toast message
Toast notification = new Toast(App.context);
// Get the associated TextView
TextView notificationText = (TextView) notificationLayout.findViewById(R.id.Notification_Message);
// Set the text from the provided argument
notificationText.setText(aText);
// Finalize the message
notification.setView(notificationLayout);
notification.setGravity(Gravity.FILL, 0, 0);
notification.setDuration(Toast.LENGTH_SHORT);
notification.show();

Everything is working as expected, except one thing... As illustrated in the following screenshot, my toast background does not cover the space where the status and navigation bars are when not in full screen (despite the fact I set my application in fullscreen using immersive sticky mode).

Top and bottom parts should be covered by toast background as well!

Here we can see 2 brighter "bars" on top and bottom of my app, which should not be bright but with 50% translucent black layer in place (as in the rest of the screenshot). So have you an idea about how I can fix this problem please?

Have a nice day.


Solution

  • I was having the same issue but couldn't make it happen. I think the only way to do it is by changing the android source code for handling showing the Toast, see the following code from Toast.java.

    private static class TN extends ITransientNotification.Stub {
        final Runnable mShow = new Runnable() {
            @Override
            public void run() {
                handleShow();
            }
        };
    
        ...
        TN() {
            // XXX This should be changed to use a Dialog, with a Theme.Toast
            // defined that sets up the layout params appropriately.
    

    this seems to me they are planning to add the feature to allow user to tweak the theme of toast, but not there yet

            final WindowManager.LayoutParams params = mParams;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.format = PixelFormat.TRANSLUCENT;
            params.windowAnimations = com.android.internal.R.style.Animation_Toast;
            params.type = WindowManager.LayoutParams.TYPE_TOAST;
            params.setTitle("Toast");
            params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                           | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                           | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    

    adding the following line might be able to make toast respect the full screen mode

    | WindowManager.LayoutParams.FLAG_FULLSCREEN

        }
    
        /**
         * schedule handleShow into the right thread
         */
        @Override
        public void show() {
            if (localLOGV) Log.v(TAG, "SHOW: " + this);
            mHandler.post(mShow);
        }
    
        /**
         * schedule handleHide into the right thread
         */
        @Override
        public void hide() {
            if (localLOGV) Log.v(TAG, "HIDE: " + this);
            mHandler.post(mHide);
        }
    
        public void handleShow() {
            if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                                      + " mNextView=" + mNextView);
            if (mView != mNextView) {
                // remove the old view if necessary
                handleHide();
                mView = mNextView;
                Context context = mView.getContext().getApplicationContext();
                String packageName = mView.getContext().getOpPackageName();
                if (context == null) {
                    context = mView.getContext();
                }
                mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
                // We can resolve the Gravity here by using the Locale for getting
                // the layout direction
                final Configuration config = mView.getContext().getResources().getConfiguration();
                final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
                mParams.gravity = gravity;
                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
                    mParams.horizontalWeight = 1.0f;
                }
                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
                    mParams.verticalWeight = 1.0f;
                }
                mParams.x = mX;
                mParams.y = mY;
                mParams.verticalMargin = mVerticalMargin;
                mParams.horizontalMargin = mHorizontalMargin;
                mParams.packageName = packageName;
                if (mView.getParent() != null) {
                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                    mWM.removeView(mView);
                }
                if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
                mWM.addView(mView, mParams);
                trySendAccessibilityEvent();
            }
        }
    

    Edit

    Another option is to create you own Toast implementation using dialog or something similar, which has the following features:

    1. not correspond to user touch event
    2. not intercept user touch event from the window
    3. will dismiss itself after a period of time
    4. the showing up of multiple toasts are queued

    I gave up eventually because I think it doesn't worth the effort. From user experience perspective, the use of toast is supposed to be less interruptive, but your design is for having the toast to take up the whole screen which defeat the purpose already. You might want to revisit your design: do you have to use toast? why not just simply creating a dialog which dismiss itself from user click or after a period of time?