如何制作自定义 toast 布局以在 Android 中真正填满全屏?

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

我的 Android 应用程序中的自定义 Toast 设计遇到了一点问题。

我在notifications_info.xml中这样定义了吐司XML(这里只简化为背景):

<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>

我是这样用的:

// 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();

一切都按预期工作,除了一件事......如下面的屏幕截图所示,我的 toast 背景没有覆盖 space 状态栏和导航栏在非全屏时所在的位置(尽管事实上,我使用沉浸式粘滞模式将我的应用程序设置为全屏。

在这里,我们可以在我的应用程序的顶部和底部看到 2 个更亮的 "bars",它们应该不亮,但有 50% 的半透明黑色层(如屏幕截图的其余部分)。那么您知道我该如何解决这个问题吗?

祝你有愉快的一天。

也许您需要让您的应用程序全屏显示。我认为这两个亮区是导航栏和状态栏。

在您的 UI 主题中试试这个方法。

protected void hideSystemUI() {
    // Set the IMMERSIVE flag.
    // Set the content to appear under the system bars so that the content
    // doesn't resize when the system bars hide and show.
    getWindow().getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_IMMERSIVE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
                    |  View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}

希望对您有所帮助。

我遇到了同样的问题,但无法解决。我认为唯一的方法是更改​​ android 源代码来处理显示 Toast,请参阅 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();
        }
    }

编辑

另一种选择是使用对话框或类似的东西创建您自己的 Toast 实现,它具有以下特点:

  1. 不对应用户触摸事件
  2. 不拦截来自 window
  3. 的用户触摸事件
  4. 一段时间后会自行解散
  5. 出现多个吐司排队

我最终放弃了,因为我认为不值得付出努力。从用户体验的角度来看,使用 toast 应该不会造成干扰,但您的设计是让 toast 占据整个屏幕,这已经违背了目的。您可能想重新审视您的设计:是否必须使用 toast?为什么不只是简单地创建一个对话框,让用户点击或在一段时间后自动关闭?