Android 11及以上替代Toast.setGravity()实现居中类Toast提示的方案?
Android 11+ 实现屏幕居中类Toast消息的解决方案
从Android 11(API 30)开始,系统原生Toast的setGravity()方法已被废弃,自定义位置的逻辑不会生效,因此要实现居中显示的类Toast消息,需要放弃原生Toast,使用自定义实现即可,以下两种方案均可以实现和原生Toast一致的轻量反馈效果:
方案1:轻量自定义类Toast实现(推荐,最接近原生体验)
该方案无额外依赖,不抢占界面焦点,和原生Toast行为完全一致,支持自定义显示位置、样式、时长:
- 核心逻辑通过应用内
WindowManager添加悬浮提示View实现,不需要申请悬浮窗权限,通过Handler实现到时间自动隐藏
示例Kotlin代码如下:
class CustomToast private constructor(private val context: Context) { private var windowManager: WindowManager? = null private var toastView: View? = null private val handler = Handler(Looper.getMainLooper()) companion object { const val LENGTH_SHORT = 2000L const val LENGTH_LONG = 3500L fun makeText(context: Context, message: String, duration: Long = LENGTH_SHORT): CustomToast { val toast = CustomToast(context) // 加载自定义布局,可根据需求修改样式 toast.toastView = LayoutInflater.from(context).inflate(R.layout.layout_custom_toast, null).apply { findViewById<TextView>(R.id.tv_toast_msg).text = message } toast.windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager return toast } } fun show() { toastView ?: return windowManager ?: return val params = WindowManager.LayoutParams().apply { height = WindowManager.LayoutParams.WRAP_CONTENT width = WindowManager.LayoutParams.WRAP_CONTENT format = PixelFormat.TRANSLUCENT // 设置不抢占焦点、不接收触摸事件,和原生Toast行为一致 flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON gravity = Gravity.CENTER // 这里直接设置居中,可修改为任意位置 type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_TOAST } } windowManager?.addView(toastView, params) // 到时间自动移除 handler.postDelayed({ cancel() }, duration) } fun cancel() { try { if (toastView?.isAttachedToWindow == true) { windowManager?.removeView(toastView) } } catch (e: Exception) { e.printStackTrace() } toastView = null windowManager = null } }
- 配套布局文件
layout_custom_toast.xml可根据需求自定义,示例如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/bg_toast" android:paddingHorizontal="16dp" android:paddingVertical="12dp" android:orientation="horizontal"> <TextView android:id="@+id/tv_toast_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize="14sp"/> </LinearLayout>
- 调用方式和原生Toast完全一致:
CustomToast.makeText(this, "居中显示的提示消息", CustomToast.LENGTH_SHORT).show()
方案2:透明Dialog模拟(实现更简单)
如果不需要复杂的全局显示逻辑,仅在单个页面内使用,用透明Dialog实现更快捷:
- 自定义Dialog样式,设置背景透明、无标题、不可点击取消,布局和上述自定义Toast布局一致即可
- 通过
Handler.postDelayed()实现到时间自动关闭,示例代码:
fun showCenterToast(context: Context, msg: String, duration: Long = 2000L) { val dialog = Dialog(context) dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) dialog.setContentView(R.layout.layout_custom_toast) dialog.findViewById<TextView>(R.id.tv_toast_msg).text = msg dialog.window?.apply { setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) val params = attributes params.gravity = Gravity.CENTER attributes = params } dialog.setCancelable(false) dialog.show() Handler(Looper.getMainLooper()).postDelayed({ if (dialog.isShowing) dialog.dismiss() }, duration) }
两种方案均支持完全自定义样式,灵活度远高于原生Toast,且不会受系统版本限制,在所有Android版本上均可实现居中显示效果。
内容的提问来源于stack exchange,提问作者Allan Antony
相关产品推荐
相关产品推荐

