Android API 30中Toast.setView()的等效替代方案咨询
寻找
Toast.setView()的完全替代方案 Toast.setView(view)在Android API 30中已被标记为弃用,官方推荐使用Material库中的Snackbar作为替代,但Snackbar无法满足自定义View、调整显示位置的需求;而Dialog会拦截用户输入,体验极差。截至Android API 34,Toast.setView()仍可使用,但未来版本会被移除,因此需要找到能完全替代它的方案。
Toast核心特性
- 支持自定义View
- 可设置屏幕显示位置
- 无需用户交互
- 自动消失
现有替代方案的不足
Snackbar
- 不支持自定义View
- 无法设置屏幕显示位置
- 无需用户交互
- 自动消失
Dialog
- 支持自定义View
- 可设置屏幕显示位置
- 会拦截用户输入,遮挡下方Activity
- 需要手动实现自动消失
可行替代方案:基于WindowManager实现自定义提示组件
Toast的本质是通过WindowManager将View添加到系统窗口,因此可以直接借助WindowManager来实现一个具备Toast全部特性的自定义组件,步骤如下:
创建自定义布局:根据需求编写包含图片、文字等元素的布局文件。
通过WindowManager添加View:
class CustomToast(private val context: Context) { private var windowManager: WindowManager? = null private var toastView: View? = null private var handler = Handler(Looper.getMainLooper()) private var dismissRunnable: Runnable? = null fun show(layoutResId: Int, gravity: Int, xOffset: Int, yOffset: Int, duration: Long) { dismiss() windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager toastView = LayoutInflater.from(context).inflate(layoutResId, null) val params = WindowManager.LayoutParams().apply { // 设置窗口类型,适配不同Android版本 type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_TOAST } // 设置显示位置 this.gravity = gravity this.x = xOffset this.y = yOffset // 设置窗口属性,不拦截触摸事件 flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL width = WindowManager.LayoutParams.WRAP_CONTENT height = WindowManager.LayoutParams.WRAP_CONTENT format = PixelFormat.TRANSLUCENT } windowManager?.addView(toastView, params) // 自动消失 dismissRunnable = Runnable { dismiss() } handler.postDelayed(dismissRunnable!!, duration) } fun dismiss() { dismissRunnable?.let { handler.removeCallbacks(it) } toastView?.let { try { windowManager?.removeView(it) } catch (e: IllegalArgumentException) { // 处理View已被移除的异常 } } toastView = null windowManager = null } }
- 使用方式:
// 显示自定义提示 CustomToast(context).show( R.layout.custom_toast_layout, Gravity.CENTER, 0, 0, Toast.LENGTH_LONG.toLong() )
注意事项
- Android 6.0及以上需要申请
SYSTEM_ALERT_WINDOW权限,可通过Settings.canDrawOverlays(context)检查权限,若未授权则引导用户前往设置页面开启。 - 确保在组件销毁时调用
dismiss()方法,避免内存泄漏。
内容的提问来源于stack exchange,提问作者William
相关产品推荐
相关产品推荐

