Android 9中如何显示30秒无闪烁Toast?已尝试现有方法无效
嘿,我来帮你搞定这个Android 9上的Toast问题!
首先得明确:Android系统原生的Toast确实不支持直接设置超过Toast.LENGTH_LONG(大概3.5秒)的时长,而且如果用循环调用show()的方式来延长时长,大概率会出现闪烁问题——这也是你之前试的方法失效的原因之一。
那要实现持续30秒且无闪烁的Toast,最可靠的方式是绕过系统Toast的限制,用WindowManager手动创建一个模拟Toast的悬浮View,这样你完全可以控制它的显示时长,而且不会有闪烁。
具体实现步骤:
1. 自定义Toast布局(模拟系统样式)
先创建一个和系统Toast风格一致的布局文件res/layout/custom_toast.xml,保证用户体验不突兀:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/toast_background" android:paddingHorizontal="16dp" android:paddingVertical="12dp" android:orientation="horizontal"> <TextView android:id="@+id/toast_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:textSize="14sp"/> </LinearLayout>
再创建对应的背景drawableres/drawable/toast_background.xml,实现系统Toast的半透明圆角效果:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#CC000000"/> <!-- 半透明黑色 --> <corners android:radius="8dp"/> <!-- 圆角大小 --> </shape>
2. 封装管理类控制显示和隐藏
创建工具类LongDurationToast.java,负责用WindowManager添加/移除View,以及定时销毁:
import android.content.Context; import android.graphics.PixelFormat; import android.os.Handler; import android.os.Looper; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.widget.TextView; public class LongDurationToast { private static View toastView; private static WindowManager windowManager; private static WindowManager.LayoutParams layoutParams; public static void show(Context context, String message, long durationMillis) { // 先销毁已存在的Toast,避免重复显示 dismiss(); windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); toastView = LayoutInflater.from(context).inflate(R.layout.custom_toast, null); TextView textView = toastView.findViewById(R.id.toast_text); textView.setText(message); // 设置WindowManager参数,和系统Toast保持一致 layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST; layoutParams.format = PixelFormat.TRANSLUCENT; // 确保Toast不获取焦点,不影响用户操作 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; // 设置底部偏移,和系统Toast一致(可根据需求调整) layoutParams.y = (int) context.getResources().getDimension(R.dimen.toast_bottom_offset); // 将View添加到WindowManager windowManager.addView(toastView, layoutParams); // 定时移除View,实现指定时长的显示 new Handler(Looper.getMainLooper()).postDelayed(LongDurationToast::dismiss, durationMillis); } // 手动销毁Toast的方法 public static void dismiss() { if (toastView != null && windowManager != null) { try { windowManager.removeView(toastView); } catch (IllegalArgumentException e) { // 避免View已被移除的异常 e.printStackTrace(); } toastView = null; windowManager = null; } } }
3. 调用方式
在你的Activity或Fragment里直接调用即可:
// 显示30秒的Toast LongDurationToast.show(this, "这是持续30秒无闪烁的Toast", 30000);
注意事项:
- 如果你的应用需要在后台显示这个自定义Toast,Android 9及以上版本需要申请
SYSTEM_ALERT_WINDOW权限,并且引导用户手动开启悬浮窗权限(在应用设置里)。此时需要把layoutParams.type改为WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY。 - 这个方法不会出现闪烁,因为是一次性添加View到WindowManager,到时间后才移除,没有重复调用
show()的操作。 - 系统原生的Toast因为受系统服务管理,无法突破时长限制,所以自定义View是目前最稳妥的方案。
内容的提问来源于stack exchange,提问作者Tester2389
相关产品推荐
相关产品推荐

