只需體驗三分鐘,你就會跟我一樣,愛上這款Toast
阿新 • • 發佈:2019-02-18
這可能是效能最優、使用最簡單,支援自定義,不需要通知欄許可權的吐司
已投入公司專案多時,沒有任何毛病,可勝任任何需求,點選此處下載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;
}
}
}