只需体验三分钟,你就会跟我一样,爱上这款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;
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
超级 Toast博客地址:悬浮窗求终结者已投入公司项目多时,没有任何毛病,可胜任任何求,点击此处下载Demo想了解实现原理的可以点击此链接查看:XToast 源码本框架意在解决一些极端求,如果是普通的 Toast 封装推荐使用 ToastUtils集成步骤dependencies {     implementation 'com.hjq:xtoast:2.0' }使用案例new XToast(XToastActivity.this) // 传入 Application 表示设置成全局的         .setView(R.layout.toast_hint)         .setDraggable() // 设置成可拖拽的 .setDuration(1000) // 设置显示时长 .setAnimStyle(android.R.style.Animation_Translucent) // 设置动画样式         .setImageDrawable(android.R.id.icon, R.mipmap.ic_dialog_tip_finish)         .setText(android.R.id.message, "点我消失")         .setOnClickListener(android.R.id.message, new OnClickListener<TextView>() {             @Override             public void onClick(XToast toast, TextView view) { // 点击这个 View 后消失                 toast.cancel();             }         })         .show();混淆规则-keep class com.hjq.xtoast.** {*;}框架亮点(原生 Toast 无法实现的功能)支持自定义 Toast 动画样式支持自定义 Toast 显示时长支持监听 Toast 的显示和销毁支持监听 Toast 中点击事件支持一键开启 Toast 拖拽功能支持 Toast 全局显示(要权限)作者的其他开源项目架构工程:AndroidProject权限封装:XXPermissions吐司封装:ToastUtils标题栏封装:TitleBarAndroid技术讨论Q群:78797078
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我定期更新这些源码资源,以适应各平台技术的最新发展和市场求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值