🔥 应用场景
????????Toast提示默认显示在界面底部,使用Toast.setGravity()将提示显示在中间,如下:
????????Toast?toast?=?Toast.makeText(this,?str,?Toast.LENGTH_SHORT);
????????toast.setGravity(Gravity.CENTER,?0,?0);
????????toast.show();
????????运行在在Android 12上无法显示,查看Logcat提示如下:
Toast:?setGravity()?shouldn't?be?called?on?text?toasts,?the?values?won't?be?used
????????意思就是:你不能使用toast调用setGravity,调用无效。哎呀,看给牛气的,咱看看源码找找原因
🔥 源码
💥 Toast.setGravity()
????/**
?????*?设置Toast出现在屏幕上的位置。
?????*
?????*?警告:从?Android?R?开始,对于面向?API?级别?R?或更高级别的应用程序,此方法在文本?toast?上调用时无效。
?????*/
????public?void?setGravity(int?gravity,?int?xOffset,?int?yOffset)?{
????????if?(isSystemRenderedTextToast())?{
????????????Log.e(TAG,?"setGravity()?shouldn't?be?called?on?text?toasts,?the?values?won't?be?used");
????????}
????????mTN.mGravity?=?gravity;
????????mTN.mX?=?xOffset;
????????mTN.mY?=?yOffset;
????}
妥了,人家就告诉你了 版本>=Android R(30),调用该方法无效。无效就无效呗,还不给显示了,过分。
Logcat的提示居然是在这里提示的,来都来了,咱们看看isSystemRenderedTextToast()方法。
💥 Toast.isSystemRenderedTextToast()
????/**
?????*Text?Toast?将由?SystemUI?呈现,而不是在应用程序内呈现,因此应用程序无法绕过后台自定义?Toast?限制。
?????*/
????@ChangeId
????@EnabledAfter(targetSdkVersion?=?Build.VERSION_CODES.Q)
????private?static?final?long?CHANGE_TEXT_TOASTS_IN_THE_SYSTEM?=?147798919L;
????
????private?boolean?isSystemRenderedTextToast()?{
????????return?Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)?&&?mNextView?==?null;
????}
????????重点了。Text Toast 将由 SystemUI 呈现,而不是在应用程序内呈现。
????????清晰明了,可以这样玩,但是你级别不够,不给你玩。
????????事情整明白了,再想想解决解决方案。他说了Text Toast 将由 SystemUI 呈现,那我不用 Text 不就行了。
🔥 Toast 提供的方法
先看看Tast提供的方法:

????????有这几个方法。咱们实践一下。保险起见看看源码
💥 Toast.setView() 源码
????/**
?????*?设置显示的View
?????*?@deprecated?自定义?Toast?视图已弃用。?应用程序可以使用?makeText?方法创建标准文本?toast,
?????*?或使用?Snackbar
?????*/
????@Deprecated
????public?void?setView(View?view)?{
????????mNextView?=?view;
????}
这个更狠,直接弃用。
-
要么老老实实的用默认的Toast。 -
要么使用 Snackbar。
🔥 Snackbar
Snackbar 就是一个类似Toast的快速弹出消息提示的控件。
与Toast相比:
-
一次只能显示一个 -
与用户交互
-
提供Snackbar显示和关闭的监听事件
💥 代码实现
????showMessage(findViewById(android.R.id.content),?str,?Snackbar.LENGTH_INDEFINITE);
??
????public?static?void?showMessage(View?view,?String?str,?int?length)?{
????????Snackbar?snackbar?=?Snackbar.make(view,?str,?length);
????????View?snackbarView?=?snackbar.getView();
????????//设置布局居中
????????FrameLayout.LayoutParams?params?=?new?FrameLayout.LayoutParams(snackbarView.getLayoutParams().width,?snackbarView.getLayoutParams().height);
????????params.gravity?=?Gravity.CENTER;
????????snackbarView.setLayoutParams(params);
????????//文字居中
????????TextView?message?=?(TextView)?snackbarView.findViewById(R.id.snackbar_text);
????????//View.setTextAlignment需要SDK>=17
????????message.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY);
????????message.setGravity(Gravity.CENTER);
????????message.setMaxLines(1);
????????snackbar.addCallback(new?BaseTransientBottomBar.BaseCallback<Snackbar>()?{
????????????@Override
????????????public?void?onDismissed(Snackbar?transientBottomBar,?int?event)?{
????????????????super.onDismissed(transientBottomBar,?event);
????????????????//Snackbar关闭
????????????}
????????????@Override
????????????public?void?onShown(Snackbar?transientBottomBar)?{
????????????????super.onShown(transientBottomBar);
????????????????//Snackbar显示
????????????}
????????});
????????snackbar.setAction("取消",?new?View.OnClickListener()?{
????????????@Override
????????????public?void?onClick(View?v)?{
????????????????//显示一个默认的Snackbar。
????????????????Snackbar.make(view,?"我先走",?BaseTransientBottomBar.LENGTH_LONG).show();
????????????????snackbar.dismiss();
????????????}
????????});
????????snackbar.show();
????}
Snackbar.make的三个参数:
💥 效果
Android 12

Android 5.1

💥 工具类
如果觉得设置麻烦可以看看下面这边文章,然后整合一套适合自己的。
https://www.jianshu.com/p/f4ba05d7bbda
|