android 自定义样式 Toast 实现(兼容 Android 4.1+~Android 16(API 16))
完整代码 ,下面是添加了自定义样式 Toast 的完整实现,兼容到 Android 16(API 16)
package com.nyw.mvvmmode.utils;import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;public final class ToastManager {public static final String MSG_ERROR = "系统错误,请稍候重试";// 默认样式常量public static final int STYLE_DEFAULT = 0;public static final int STYLE_CUSTOM = 1;private static volatile Toast sToast;private static final Handler sHandler = new Handler(Looper.getMainLooper());private static final Runnable sCancelRunnable = () -> {if (sToast != null) {sToast.cancel();sToast = null;}};private static boolean sCanShowMsg = true;private static int sDefaultStyle = STYLE_DEFAULT; // 默认使用系统样式private ToastManager() {throw new UnsupportedOperationException("u can't instantiate me...");}public static void setCanShowMsg(boolean canShowMsg) {sCanShowMsg = canShowMsg;}/*** 设置全局默认 Toast 样式* @param style STYLE_DEFAULT 或 STYLE_CUSTOM*/public static void setDefaultStyle(int style) {sDefaultStyle = style;}/*** 显示 Toast(使用默认样式)*/public static void showToast(Context context, String text, int duration) {showToast(context, text, duration, sDefaultStyle);}/*** 显示 Toast(可指定样式)* @param style 样式:STYLE_DEFAULT 或 STYLE_CUSTOM*/public static void showToast(Context context, String text, int duration, int style) {if (!sCanShowMsg || text == null || text.isEmpty()) {return;}// 防止内存泄漏,使用 Application ContextContext appContext = context.getApplicationContext();sHandler.removeCallbacks(sCancelRunnable);if (style == STYLE_CUSTOM) {// 使用自定义样式if (sToast == null) {sToast = new Toast(appContext);// 获取自定义布局View view = LayoutInflater.from(appContext).inflate(R.layout.toast_custom, null);TextView tvMessage = view.findViewById(R.id.toast_message);tvMessage.setText(text);sToast.setView(view);sToast.setGravity(Gravity.CENTER, 0, 0);sToast.setDuration(duration);} else {// 复用已有 Toast,更新文本View view = sToast.getView();if (view != null) {TextView tvMessage = view.findViewById(R.id.toast_message);if (tvMessage != null) {tvMessage.setText(text);}}}} else {// 使用系统样式if (sToast != null) {sToast.setText(text);} else {sToast = Toast.makeText(appContext, text, duration);sToast.setGravity(Gravity.CENTER, 0, 0);}}// 确保在主线程显示sHandler.post(() -> sToast.show());// 设置自动取消时间long cancelDelay = (duration == Toast.LENGTH_LONG) ? 3500 : 2000;sHandler.postDelayed(sCancelRunnable, cancelDelay);}/*** 显示短时间 Toast(默认样式)*/public static void showShortToast(Context context, String text) {showToast(context, text, Toast.LENGTH_SHORT);}/*** 显示短时间 Toast(可指定样式)*/public static void showShortToast(Context context, String text, int style) {showToast(context, text, Toast.LENGTH_SHORT, style);}/*** 显示长时间 Toast(默认样式)*/public static void showLongToast(Context context, String text) {showToast(context, text, Toast.LENGTH_LONG);}/*** 显示长时间 Toast(可指定样式)*/public static void showLongToast(Context context, String text, int style) {showToast(context, text, Toast.LENGTH_LONG, style);}/*** 通过资源ID显示 Toast(默认样式)*/public static void showToast(Context context, int strId, int duration) {try {showToast(context, context.getString(strId), duration);} catch (Exception e) {// 资源不存在时的容错处理showToast(context, String.valueOf(strId), duration);}}/*** 通过资源ID显示 Toast(可指定样式)*/public static void showToast(Context context, int strId, int duration, int style) {try {showToast(context, context.getString(strId), duration, style);} catch (Exception e) {// 资源不存在时的容错处理showToast(context, String.valueOf(strId), duration, style);}}/*** 隐藏当前 Toast 并禁用显示*/public static void hideMsg() {sHandler.removeCallbacks(sCancelRunnable);if (sToast != null) {sToast.cancel();sToast = null;}sCanShowMsg = false;}
}
自定义 Toast 布局
在 res/layout
目录下创建 toast_custom.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:layout_margin="16dp"android:background="@drawable/toast_bg"android:orientation="vertical"android:padding="12dp"><TextViewandroid:id="@+id/toast_message"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ellipsize="end"android:maxLines="2"android:textColor="#FFFFFF"android:textSize="16sp" /></LinearLayout>
自定义 Toast 背景
在 res/drawable
目录下创建 toast_bg.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#CC000000" /> <!-- 半透明黑色 --><corners android:radius="8dp" /><paddingandroid:bottom="8dp"android:left="12dp"android:right="12dp"android:top="8dp" />
</shape>
使用方法
显示系统样式 Toast
java
运行
ToastManager.showShortToast(context, "这是系统样式Toast");
显示自定义样式 Toast
java
运行
ToastManager.showShortToast(context, "这是自定义样式Toast", ToastManager.STYLE_CUSTOM);
设置全局默认使用自定义样式
java
运行
ToastManager.setDefaultStyle(ToastManager.STYLE_CUSTOM);
// 之后调用不带样式参数的方法都会使用自定义样式
ToastManager.showShortToast(context, "全局默认自定义样式");
兼容性说明
- Android 16+ 完全兼容:通过标准 Toast API 实现,不使用任何已弃用或高版本特性
- 自定义样式稳定性:使用
setView()
方法设置自定义布局,这是官方推荐的自定义 Toast 方式 - 内存安全:所有方法都使用
Application Context
避免内存泄漏 - 线程安全:使用
volatile
关键字和Handler(Looper.getMainLooper())
确保多线程安全