只需体验三分钟,你就会跟我一样,爱上这款Toast

这可能是性能最优、使用最简单,支持自定义,不需要通知栏权限的吐司

Github传送地址,欢迎Star

已投入公司项目多时,没有任何毛病,可胜任任何需求,点击此处下载Demo

想了解实现原理的可以点击此链接查看:ToastUtils 源码


集成步骤

dependencies {
    implementation 'com.hjq:toast:3.0'
}

初始化Toast

// 在Application中初始化
ToastUtils.init(this);

显示Toast

ToastUtils.show("我是吐司");

获取Toast对象

ToastUtils.getToast();

设置Toast布局

ToastUtils.setView();

自定义Toast样式

如果对Toast的默认样式不满意,可以在Application初始化样式,具体可参考ToastBlackStyle类的实现

ToastUtils.initStyle(new IToastStyle());

框架亮点

  • 无需权限:不管有没有授予通知栏权限都不影响吐司的弹出

  • 功能强大:不分主次线程都可以弹出Toast,自动区分资源id和int类型

  • 使用简单:只需传入文本,会自动根据文本长度决定吐司显示的时长

  • 性能最佳:单例吐司,整个Toast只有一个TextView,并且通过代码创建

  • 体验最优:限制Toast短时间内弹出的次数,避免频繁弹出造成不良的用户体验

  • 支持多种样式:默认为黑色样式,夜间模式可使用白色样式,还有仿QQ吐司样式

  • 支持自定义样式:吐司(背景、圆角、重心、偏移),文字(大小、颜色、边距)

  • 支持自定义扩展:支持获取ToastUtils中的Toast对象,支持重新自定义Toast布局

  • 支持全局配置样式:可以在Application中初始化Toast样式,达到一劳永逸的效果

  • 框架兼容性良好:本框架不依赖任何第三方库,支持Eclipse和Studio的集成使用

关于通知栏权限

本框架已经完美解决这个问题


原博主


这就是原博主的那个工具类,写的还是很不错的,可以直接使用 

package com.hjq.toast;

import android.app.AppOpsManager;
import android.app.Application;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.hjq.toast.style.ToastBlackStyle;
import com.hjq.toast.style.ToastQQStyle;
import com.hjq.toast.style.ToastWhiteStyle;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 *    author : HJQ
 *    github : https://github.com/getActivity/ToastUtils
 *    time   : 2018/09/01
 *    desc   : Toast工具类
 */
public final class ToastUtils {

    private static IToastStyle sDefaultStyle;

    private static Toast sToast;

    /**
     * 初始化ToastUtils,建议在Application中初始化
     *
     * @param application       应用的上下文
     */
    public static void init(Application application) {
        // 检查默认样式是否为空,如果是就创建一个默认样式
        if (sDefaultStyle == null) {
            sDefaultStyle = new ToastBlackStyle();
        }

        // 判断有没有通知栏权限
        if (isNotificationEnabled(application)) {
            sToast = new XToast(application);
        }else {
            sToast = new SupportToast(application);
        }

        sToast.setGravity(sDefaultStyle.getGravity(), sDefaultStyle.getXOffset(), sDefaultStyle.getYOffset());
        sToast.setView(createTextView(application));
    }

    /**
     * 显示一个对象的吐司
     *
     * @param object      对象
     */
    public static void show(Object object) {
        show(object != null ? object.toString() : "null");
    }

    /**
     * 显示一个吐司
     *
     * @param id      如果传入的是正确的string id就显示对应字符串
     *                如果不是则显示一个整数的string
     */
    public static void show(int id) {

        checkToastState();

        try {
            // 如果这是一个资源id
            show(sToast.getView().getContext().getResources().getText(id));
        } catch (Resources.NotFoundException ignored) {
            // 如果这是一个int类型
            show(String.valueOf(id));
        }
    }

    /**
     * 显示一个吐司
     *
     * @param text      需要显示的文本
     */
    public static void show(CharSequence text) {

        checkToastState();

        if (text == null || text.equals("")) return;

       // 如果显示的文字超过了10个就显示长吐司,否则显示短吐司
        if (text.length() > 20) {
            sToast.setDuration(Toast.LENGTH_LONG);
        } else {
            sToast.setDuration(Toast.LENGTH_SHORT);
        }

        sToast.setText(text);
        sToast.show();
    }

    /**
     * 取消吐司的显示
     */
    public void cancel() {
        checkToastState();
        sToast.cancel();
    }

    /**
     * 获取当前Toast对象
     */
    public static Toast getToast() {
        return sToast;
    }

    /**
     * 给当前Toast设置新的布局,具体实现可看{@link XToast#setView(View)}
     */
    public static void setView(Context context, int layoutId) {
        if (context != context.getApplicationContext()) {
            context = context.getApplicationContext();
        }
        setView(View.inflate(context, layoutId, null));
    }

    public static void setView(View view) {

        checkToastState();

        if (view == null) {
            throw new IllegalArgumentException("Views cannot be empty");
        }

        // 如果吐司已经创建,就重新初始化吐司
        if (sToast != null) {
            //取消原有吐司的显示
            sToast.cancel();
            sToast.setView(view);
        }
    }

    /**
     * 统一全局的Toast样式,建议在{@link android.app.Application#onCreate()}中初始化
     *
     * @param style         样式实现类,框架已经实现三种不同的样式
     *                      黑色样式:{@link ToastBlackStyle}
     *                      白色样式:{@link ToastWhiteStyle}
     *                      仿QQ样式:{@link ToastQQStyle}
     */
    public static void initStyle(IToastStyle style) {
        ToastUtils.sDefaultStyle = style;
        // 如果吐司已经创建,就重新初始化吐司
        if (sToast != null) {
            //取消原有吐司的显示
            sToast.cancel();
            sToast.setView(createTextView(sToast.getView().getContext().getApplicationContext()));
        }
    }

    /**
     * 检查吐司状态,如果未初始化请先调用{@link ToastUtils#init(Application)}
     */
    private static void checkToastState() {
        //吐司工具类还没有被初始化,必须要先调用init方法进行初始化
        if (sToast == null) {
            throw new IllegalStateException("ToastUtils has not been initialized");
        }
    }

    /**
     * 生成默认的 TextView 对象
     */
    private static TextView createTextView(Context context) {

        GradientDrawable drawable = new GradientDrawable();
        drawable.setColor(sDefaultStyle.getBackgroundColor()); // 设置背景色
        drawable.setCornerRadius(dp2px(context, sDefaultStyle.getCornerRadius())); // 设置圆角

        TextView textView = new TextView(context);
        textView.setId(R.id.toast_main_text_view_id);
        textView.setTextColor(sDefaultStyle.getTextColor());
        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, sp2px(context, sDefaultStyle.getTextSize()));
        textView.setPadding(dp2px(context, sDefaultStyle.getPaddingLeft()), dp2px(context, sDefaultStyle.getPaddingTop()),
                dp2px(context, sDefaultStyle.getPaddingRight()), dp2px(context, sDefaultStyle.getPaddingBottom()));
        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        // setBackground API版本兼容
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            textView.setBackground(drawable);
        }else {
            textView.setBackgroundDrawable(drawable);
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            textView.setZ(sDefaultStyle.getZ()); // 设置 Z 轴阴影
        }

        if (sDefaultStyle.getMaxLines() > 0) {
            textView.setMaxLines(sDefaultStyle.getMaxLines()); // 设置最大显示行数
        }

        return textView;
    }

    /**
     * dp转px
     *
     * @param context       上下文
     * @param dpValue       dp值
     * @return              px值
     */
    private static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * sp转px
     *
     * @param context       上下文
     * @param spValue       sp值
     * @return              px值
     */
    private static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

    /**
     * 检查通知栏权限有没有开启
     * 参考SupportCompat包中的: NotificationManagerCompat.from(context).areNotificationsEnabled();
     */
    public static boolean isNotificationEnabled(Context context){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).areNotificationsEnabled();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            ApplicationInfo appInfo = context.getApplicationInfo();
            String pkg = context.getApplicationContext().getPackageName();
            int uid = appInfo.uid;

            try {
                Class<?> appOpsClass = Class.forName(AppOpsManager.class.getName());
                Method checkOpNoThrowMethod = appOpsClass.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class);
                Field opPostNotificationValue = appOpsClass.getDeclaredField("OP_POST_NOTIFICATION");
                int value = (Integer) opPostNotificationValue.get(Integer.class);
                return (Integer) checkOpNoThrowMethod.invoke(appOps, value, uid, pkg) == 0;
            } catch (NoSuchMethodException | NoSuchFieldException | InvocationTargetException | IllegalAccessException | RuntimeException | ClassNotFoundException ignored) {
                return true;
            }
        } else {
            return true;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/fengyeNom1/article/details/83987368