Skip to content

Commit

Permalink
新增框架常见疑问文档
Browse files Browse the repository at this point in the history
补充和优化框架使用文档
补充显示长短 Toast 方法
优化框架部分字段命名及注释
优化 ToastUtils 方法实现逻辑
  • Loading branch information
getActivity committed Nov 7, 2022
1 parent 535ebed commit 5f45886
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 104 deletions.
160 changes: 160 additions & 0 deletions HelpDoc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#### 目录

* [怎么自定义 Toast 显示动画](#怎么自定义-toast-显示动画)

* [怎么自定义 Toast 显示时长](#怎么自定义-toast-显示时长)

* [怎么自定义 Toast 布局样式](#怎么自定义-toast-布局样式)

* [怎么切换成 Toast 排队显示的策略](#怎么切换成-toast-排队显示的策略)

* [框架无法满足我当前使用的场景怎么办](#框架无法满足我当前使用的场景怎么办)

* [为什么框架优先使用 WindowManager 来实现 Toast](#为什么框架优先使用-windowManager-来实现-toast)

#### 怎么自定义 Toast 显示动画

* 在 Toast 初始化的时候,修改 Toast 策略即可

```java
ToastUtils.init(this, new ToastStrategy() {

@Override
public IToast createToast(IToastStyle<?> style) {
if (toast instanceof CustomToast) {
CustomToast customToast = ((CustomToast) toast);
// 设置 Toast 动画效果
customToast.setAnimationsId(R.anim.xxx);
}
return toast;
}
});
```

* 这种方式的缺点是只有应用在前台的情况下才会生效,这是因为前台的 Toast 是用框架实现的,本质上是一个 WindowManager,优点是非常灵活,不受系统 Toast 机制限制,缺点是无法在后台的情况下显示;而后台的 Toast 是用系统来实现的,优点是能在后台的情况下显示,缺点是局限性非常大,无法做太深的定制化;而框架正是利用了两种方式的优缺点进行了互补。

#### 怎么自定义 Toast 显示时长

* 在 Toast 初始化的时候,修改 Toast 策略即可

```java
ToastUtils.init(this, new ToastStrategy() {

@Override
public IToast createToast(IToastStyle<?> style) {
IToast toast = super.createToast(style);
if (toast instanceof CustomToast) {
CustomToast customToast = ((CustomToast) toast);
// 设置短 Toast 的显示时长(默认是 2000 毫秒)
customToast.setShortDuration(1000);
// 设置长 Toast 的显示时长(默认是 3500 毫秒)
customToast.setLongDuration(5000);
}
return toast;
}
});
```

* 这种方式的缺点是只有应用在前台的情况下才会生效,这是因为前台的 Toast 是用框架实现的,本质上是一个 WindowManager,优点是非常灵活,不受系统 Toast 机制限制,缺点是无法在后台的情况下显示;而后台的 Toast 是用系统来实现的,优点是能在后台的情况下显示,缺点是局限性非常大,无法做太深的定制化;而框架正是利用了两种方式的优缺点进行了互补。

#### 怎么自定义 Toast 布局样式

* 如果你想设置全局的 Toast 样式,可以这样调用(选择任一一种即可)

```java
// 修改 Toast 布局
ToastUtils.setView(int id);
```

```java
// 修改 Toast 布局,Toast 显示重心,Toast 显示位置偏移
ToastUtils.setStyle(IToastStyle<?> style);
```

* 如果你想为某次 Toast 显示设置单独的样式,可以这样样用(选择任一一种即可)

```java
// 修改 Toast 布局
ToastParams params = new ToastParams();
params.text = "我是自定义布局的 Toast(局部生效)";
params.style = new CustomViewToastStyle(R.layout.toast_custom_view);
ToastUtils.show(params);
```

```java
// 修改 Toast 布局、Toast 显示重心、Toast 显示位置偏移
ToastParams params = new ToastParams();
params.text = "我是自定义布局的 Toast(局部生效)";
params.style = new CustomViewToastStyle(R.layout.toast_custom_view, Gravity.CENTER, 10, 20);
ToastUtils.show(params);
```

#### 怎么切换成 Toast 排队显示的策略

* 只需要修改 Toast 框架的初始化方式,手动传入 Toast 策略类,这里使用框架已经封装好的 ToastStrategy 类即可,

```java
// 初始化 Toast 框架
// ToastUtils.init(this);
ToastUtils.init(this, new ToastStrategy(ToastStrategy.SHOW_STRATEGY_TYPE_QUEUE));
```

* 注意构造函数需要传入 `ToastStrategy.SHOW_STRATEGY_TYPE_QUEUE`,关于这个字段的介绍可以看下面的代码注释

```
public class ToastStrategy
/**
* 即显即示模式(默认)
*
* 在发起多次 Toast 的显示请求情况下,显示下一个 Toast 之前
* 会先立即取消上一个 Toast,保证当前显示 Toast 消息是最新的
*/
public static final int SHOW_STRATEGY_TYPE_IMMEDIATELY = 0;
/**
* 不丢消息模式
*
* 在发起多次 Toast 的显示请求情况下,等待上一个 Toast 显示 1 秒或者 1.5 秒后
* 然后再显示下一个 Toast,不按照 Toast 的显示时长来,因为那样等待时间会很长
* 这样既能保证用户能看到每一条 Toast 消息,又能保证用户不会等得太久,速战速决
*/
public static final int SHOW_STRATEGY_TYPE_QUEUE = 1;
}
```

#### 框架无法满足我当前使用的场景怎么办

* ToastUtils 框架意在解决一些的 Toast 需求,如果 ToastUtils 无法满足你的需求,你可以考虑使用 [XToast](https://github.com/getActivity/XToast) 悬浮窗框架来实现。

#### 为什么框架优先使用 WindowManager 来实现 Toast

* 系统 Toast 的坑太多了,主要问题表现如下:

* 系统 Toast 会引发一些内存泄漏的问题

* 系统 Toast 无法实现自定义显示动画、显示时长控制

* Android 7.1 版本会主线程阻塞会出现 BadTokenException 的问题

* Android 10.0 以下关闭通知栏权限会导致系统 Toast 显示不出来的问题

* Android 11 及以上版本,无法自定义 Toast 样式(布局、位置重心、位置偏移)

* 所以框架优先使用 WindowManager 来实现 Toast 显示,具体优缺点以下:

* 优点

* 不会出现内存泄漏,也不会有那么多奇奇怪怪的问题

* 可定制程度高,支持自定义动画和自定义显示时长

* 突破 Google 在新版本 Android 对 Toast 的一些限制

* 缺点

* WindowManager 无法在没有悬浮窗权限情况下在后台弹出 <br> (框架的解决方案:如果是在后台的情况下显示,则使用系统的 Toast 来显示)

* WindowManager 会和 Activity 绑定,会随 Activity 销毁而消失 <br> (框架的解决方案:延迟 200 毫秒显示,由此等待最新的 Activity 创建出来才调用显示,这样 WindowManager 就和最新 Activity 绑定在一起,就不会出现和旧 Activity finish 时一起消失的问题)

* 当然不是说用系统 Toast 就不好,用 WindowManger 一定就好,视具体的使用场景而定,我觉得最好的方式是:应用在前台的情况下使用 WindowManager 来显示,在后台的情况下使用系统 Toast 来显示,两者相结合,优势互补才是最佳方案。
63 changes: 27 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

* 博客地址:[只需体验三分钟,你就会跟我一样,爱上这款 Toast](https://www.jianshu.com/p/9b174ee2c571)

* 可以扫码下载 Demo 进行演示或者测试,如果扫码下载不了的,[点击此处可直接下载](https://github.com/getActivity/ToastUtils/releases/download/11.0/ToastUtils.apk)
* 可以扫码下载 Demo 进行演示或者测试,如果扫码下载不了的,[点击此处可直接下载](https://github.com/getActivity/ToastUtils/releases/download/11.2/ToastUtils.apk)

![](picture/demo_code.png)

Expand Down Expand Up @@ -47,7 +47,7 @@ android {
dependencies {
// 吐司框架:https://github.com/getActivity/ToastUtils
implementation 'com.github.getActivity:ToastUtils:11.0'
implementation 'com.github.getActivity:ToastUtils:11.2'
}
```

Expand All @@ -72,31 +72,46 @@ public class XxxApplication extends Application {
// 显示 Toast
ToastUtils.show(CharSequence text);
ToastUtils.show(int id);
ToastUtils.show(ToastParams params);
ToastUtils.show(Object object);

// debug 模式下显示 Toast
ToastUtils.debugShow(int id);
ToastUtils.debugShow(CharSequence text);
ToastUtils.debugShow(int id);
ToastUtils.debugShow(Object object);

// 延迟显示 Toast
ToastUtils.delayedShow(int id, long delayMillis);
ToastUtils.delayedShow(CharSequence text, long delayMillis);
ToastUtils.delayedShow(int id, long delayMillis);
ToastUtils.delayedShow(Object object, long delayMillis);

// 显示短 Toast
ToastUtils.showShort(CharSequence text);
ToastUtils.showShort(int id);
ToastUtils.showShort(Object object);

// 显示长 Toast
ToastUtils.showLong(CharSequence text);
ToastUtils.showLong(int id);
ToastUtils.showLong(Object object);

// 自定义显示 Toast
ToastUtils.show(ToastParams params);

// 取消 Toast
ToastUtils.cancel();

// 设置 Toast 布局
// 设置 Toast 布局(全局生效)
ToastUtils.setView(int id);

// 设置 Toast 布局样式
// 设置 Toast 布局样式(全局生效)
ToastUtils.setStyle(IToastStyle<?> style);
// 获取 Toast 布局样式
ToastUtils.getStyle()

// 判断当前框架是否已经初始化
ToastUtils.isInit();

// 设置 Toast 策略
// 设置 Toast 策略(全局生效)
ToastUtils.setStrategy(IToastStrategy strategy);
// 获取 Toast 策略
ToastUtils.getStrategy();
Expand All @@ -105,43 +120,19 @@ ToastUtils.getStrategy();
ToastUtils.setGravity(int gravity);
ToastUtils.setGravity(int gravity, int xOffset, int yOffset);

// 设置 Toast 拦截器
// 设置 Toast 拦截器(全局生效)
ToastUtils.setInterceptor(IToastInterceptor interceptor);
// 获取 Toast 拦截器
ToastUtils.getInterceptor();
```

* 如果你需要对 Toast 的进行深度定制化,可以使用以下方式

```java
ToastUtils.init(this, new ToastStrategy() {

@Override
public IToast createToast(Application application) {
IToast toast = super.createToast(application);
if (toast instanceof CustomToast) {
CustomToast customToast = ((CustomToast) toast);
// 设置 Toast 动画效果
customToast.setAnimationsId(R.anim.xxx);
// 设置短 Toast 的显示时长(默认是 2000 毫秒)
customToast.setShortDuration(1000);
// 设置长 Toast 的显示时长(默认是 3500 毫秒)
customToast.setLongDuration(5000);
}
return toast;
}
});
```

* 这种方式的缺点是只有应用在前台的情况下才会生效,这是因为前台的 Toast 是用框架实现的,本质上是一个 WindowManager,优点是非常灵活,不受原生 Toast 机制限制,缺点是无法在后台的情况下显示;而后台的 Toast 是用系统来实现的,优点是能在后台的情况下显示,缺点是局限性非常大,无法做太深的定制化;而框架正是利用了两种方式的优缺点进行了互补。

### 温馨提示:框架意在解决一些常规的 Toast 需求,如果是有一些特殊的定制化需求请配搭 [XToast](https://github.com/getActivity/XToast) 悬浮窗框架使用
## [常见疑问请点击此处查看](HelpDoc.md)

#### 不同 Toast 框架之间的对比

| 功能或细节 | [ToastUtils](https://github.com/getActivity/ToastUtils) | [AndroidUtilCode](https://github.com/Blankj/AndroidUtilCode) | [Toasty](https://github.com/GrenderG/Toasty) |
| :----: | :------: | :-----: | :-----: |
| 对应版本 | 11.0 | 1.30.6 | 1.5.0 |
| 对应版本 | 11.2 | 1.30.6 | 1.5.0 |
| issues 数 | [![](https://img.shields.io/github/issues/getActivity/ToastUtils.svg)](https://github.com/getActivity/ToastUtils/issues) | [![](https://img.shields.io/github/issues/Blankj/AndroidUtilCode.svg)](https://github.com/Blankj/AndroidUtilCode/issues) | [![](https://img.shields.io/github/issues/GrenderG/Toasty.svg)](https://github.com/GrenderG/Toasty/issues) |
| **aar 包大小** | 31 KB | 500 KB | 50 KB |
| 框架维护状态 | **维护中** | 停止维护 | 停止维护 |
Expand All @@ -151,7 +142,7 @@ ToastUtils.init(this, new ToastStrategy() {
| 支持设置**全局** Toast 样式 ||||
| 支持 Toast **即显即示** ||||
| 支持 Toast **排队显示** ||||
| 支持 Toast **延迟显示** ||||
| 支持 Toast **延迟显示** ||||
| **处理 Toast 在 Android 7.1 崩溃的问题** ||||
| **兼容通知栏权限关闭后 Toast 显示不出来的问题** ||||
| **适配 Android 11 不能在后台显示 Toast 的问题** ||||
Expand Down
10 changes: 4 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android {
applicationId "com.hjq.toast.demo"
minSdkVersion 16
targetSdkVersion 31
versionCode 1100
versionName "11.0"
versionCode 1120
versionName "11.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

Expand Down Expand Up @@ -62,16 +62,14 @@ dependencies {
implementation 'com.google.android.material:material:1.4.0'

// 标题栏框架:https://github.com/getActivity/TitleBar
implementation 'com.github.getActivity:TitleBar:9.5'
implementation 'com.github.getActivity:TitleBar:9.6'

// 权限请求框架:https://github.com/getActivity/XXPermissions
implementation 'com.github.getActivity:XXPermissions:16.2'

// 悬浮窗框架:https://github.com/getActivity/XToast
implementation 'com.github.getActivity:XToast:8.5'
implementation 'com.github.getActivity:XToast:8.6'

// 内存泄漏捕捉:https://github.com/square/leakcanary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'

implementation 'com.tencent.mars:mars-xlog:1.2.6'
}
21 changes: 18 additions & 3 deletions app/src/main/java/com/hjq/toast/demo/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public void showToast(View v) {
ToastUtils.show("我是普通的 Toast");
}

public void showShortToast(View v) {
ToastUtils.showShort("我是一个短 Toast");
}

public void showLongToast(View v) {
ToastUtils.showLong("我是一个长 Toast");
}

public void showThriceToast(View v) {
for (int i = 0; i < 3; i++) {
ToastUtils.show("我是第 " + (i + 1) + " 个 Toast");
Expand Down Expand Up @@ -102,7 +110,14 @@ public void switchToastStrategy(View v) {
}

public void toBackgroundShowToast(View v) {
Snackbar.make(getWindow().getDecorView(), "温馨提示:安卓 10 在后台显示 Toast 需要有通知栏权限或者悬浮窗权限的情况下才可以显示", Snackbar.LENGTH_SHORT).show();
Snackbar.make(getWindow().getDecorView(), "系好安全带,即将跳转到手机桌面", Snackbar.LENGTH_SHORT).show();

v.postDelayed(new Runnable() {
@Override
public void run() {
Snackbar.make(getWindow().getDecorView(), "温馨提示:安卓 10 在后台显示 Toast 需要有通知栏权限或者悬浮窗权限的情况下才可以显示", Snackbar.LENGTH_SHORT).show();
}
}, 2000);

v.postDelayed(new Runnable() {
@Override
Expand All @@ -111,7 +126,7 @@ public void run() {
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
}, 2000);
}, 4000);

v.postDelayed(new Runnable() {
@Override
Expand All @@ -126,7 +141,7 @@ public void run() {
ToastUtils.show("我是在后台显示的 Toast");
}
}
}, 3000);
}, 5000);
}

public void combinationXToastShow(View v) {
Expand Down
Loading

0 comments on commit 5f45886

Please sign in to comment.