让DialogX的消息提示玩出花 - 自定义PopTip和 PopNotification的避让动画
DialogX 的 PopTip 组件提供了类似于安卓原生 Toast 的非阻断式简单提示效果,更进一步提供了更多的扩展功能,通常情况下,PopTip 能够同时显示多个吐司消息提示,但默认情况下堆叠多个提示时会占用很大的屏幕空间面积,遮挡原本的 UI,造成视觉上的干扰。其次,PopTip 也可以通过 .noAutoDismiss()
方法实现持续显示而不自动关闭,同时也可以通过 .setButton(...)
方法设置一个按钮,常被用于展示待处理事务的场景,此时如果同时需要等待用户处理的事务过多则会导致界面遮挡严重无法正常使用(如下图)
那么是否有一种办法能解决这个问题呢?在最新的 DialogX 测试版本中提供了避让动画控制器
PopMoveDisplacementInterceptor
就可以轻松解决这个问题。
避让动画控制器是一个组件全局接口,提供了两个可覆写方法,其中 resetAnimY
方法会在执行动画前进行,目的是预算避让动画的目标位置,animUpdater
方法则会在动画执行过程中不断执行,目的是动态调整动画效果,请勿在此方法中执行过于耗时的操作,具体含义如下:
java
/**
* 重置提示对话框新增时,旧的对话框让位位移的动画具体参数
*
* @param index 对话框索引
* @param dialog 对话框
* @param fromY 从哪来
* @param toY 往哪去
* @param dialogHeight 对话框本身的高度
* @param allTipSize 提示框总数
* @param moveBack 是否向后位移
* @return 你要改为往哪去
*/
public float resetAnimY(int index, D dialog, float fromY, float toY, int dialogHeight, int allTipSize, boolean moveBack) {
return toY;
}
/**
* 动画更新器
*
* @param index 对话框索引
* @param dialog 对话框
* @param dialogBody 对话框内容布局
* @param fromY 从哪来
* @param toY 往哪去
* @param progress 动画进度(0f~1f)
* @param animation 动画执行器
* @param allTipSize 提示框总数
* @param moveBack 是否向后位移
* @return 返回true表示拦截处理,否则依然会执行原本的动画
*/
public boolean animUpdater(int index, D dialog, View dialogBody, float fromY, float toY, float progress, ValueAnimator animation, int allTipSize, boolean moveBack) {
return false;
}
根据这两个方法所提供的参数即可实时对 PopTip 的避让动画进行修改,例如我们可以在新的 PopTip 弹出时,让旧 PopTip 减少位移缩小一些挪至新 PopTip 的背后,以此类推即可让多个 PopTip 的显示不再占用太大的用户操作空间(如下图)

同时,在用户通过操作关闭前层的 PopTip 时,则需要将后层的 PopTip 恢复到原有的位置,而这个想法通过避让动画控制器 PopMoveDisplacementInterceptor
就可以轻松实现。
根据上边的接口,通过如下代码实现:
java
PopTip.moveDisplacementInterceptor = new PopMoveDisplacementInterceptor<PopTip>() {
//旧的对话框让位位移的动画具体参数
@Override
public float resetAnimY(int index, PopTip dialog, float fromY, float toY, int dialogHeight, int allTipSize, boolean moveBack) {
if (moveBack) { //如果是后移
return fromY - dialogHeight * 0.5f + 0.15f * (allTipSize - index - 1) * dialogHeight;
} else { //如果是前移
return fromY + dialogHeight * 0.5f - 0.15f * (allTipSize - index - 1) * dialogHeight;
}
}
float zoomRatio = 0.03f;
//动画更新器
@Override
public boolean animUpdater(int index, PopTip dialog, View dialogBody, float fromY, float toY, float progress, ValueAnimator animation, int allTipSize, boolean moveBack) {
if (moveBack) { //如果是后移
float originalScale = 1f - zoomRatio * (allTipSize - index - 1);
float targetScale = originalScale * (1f - zoomRatio * progress);
} else { //如果是前移
float originalScale = 1f - zoomRatio * (allTipSize - index - 1);
float currentScale = originalScale * (1f - zoomRatio * 1);
float targetScale = currentScale + (originalScale - currentScale) * progress;
}
if (targetScale > 1) targetScale = 1;
dialogBody.setScaleX(targetScale);
dialogBody.setScaleY(targetScale);
dialogBody.setAlpha(targetScale);
return false;
}
};
同样的,PopNotification 对话框组件可以在无需通知权限的情况下在app内实现通知提示效果,这个对话框组件也支持避让动画控制器 PopMoveDisplacementInterceptor
,可以实现相似的效果(如下图)

具体实现代码如下:
ini
PopNotification.moveDisplacementInterceptor=new PopMoveDisplacementInterceptor<PopNotification>() {
@Override
public float resetAnimY(int index, PopNotification dialog, float fromY, float toY, int dialogHeight, int allTipSize, boolean moveBack) {
if (moveBack) {
return fromY + dialogHeight * 0.25f - 0.1f * (allTipSize - index - 1) * dialogHeight;
} else {
return fromY - dialogHeight * 0.25f+ 0.1f * (allTipSize - index - 1) * dialogHeight;
}
}
float zoomRatio = 0.03f;
@Override
public boolean animUpdater(int index, PopNotification dialog, View dialogBody, float fromY, float toY, float progress, ValueAnimator animation, int allTipSize, boolean moveBack) {
if (moveBack) {
float originalScale = 1f - zoomRatio * (allTipSize - index - 1);
float targetScale = originalScale * (1f - zoomRatio * progress);
if (targetScale > 1) targetScale = 1;
dialogBody.setScaleX(targetScale);
dialogBody.setScaleY(targetScale);
dialogBody.setAlpha(targetScale);
} else {
float originalScale = 1f - zoomRatio * (allTipSize - index - 1);
float currentScale = originalScale * (1f - zoomRatio * 1);
float targetScale = currentScale + (originalScale - currentScale) * progress;
if (targetScale > 1) targetScale = 1;
dialogBody.setScaleX(targetScale);
dialogBody.setScaleY(targetScale);
dialogBody.setAlpha(targetScale);
}
return false;
}
};
如此即可轻松完成避让动画的改进,以解决占用很大的屏幕空间面积的问题。
上述代码中 PopTip 的样式为模仿 Snackbar 的样式实现,要将默认的 PopTip 改为这个样式,可以增加一个布局文件 layout_dialogx_poptip_snackbar.xml
,具体实现代码如下:
ini
<?xml version="1.0" encoding="utf-8"?>
<com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/box_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:baseFocusable="false">
<LinearLayout
android:id="@+id/box_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/rect_dialogx_material_poptip_bkg_night"
android:elevation="5dp"
android:gravity="center_vertical"
android:minHeight="50dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/img_dialogx_pop_icon"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="-5dp"
android:visibility="gone" />
<TextView
android:id="@+id/txt_dialogx_pop_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp"
android:layout_weight="1"
android:gravity="left|center_vertical"
android:text="Sure?"
android:textColor="@color/white"
android:textSize="14dp" />
<RelativeLayout
android:id="@+id/box_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<TextView
android:id="@+id/txt_dialogx_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="-15dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:background="@drawable/button_dialogx_material_night"
android:gravity="left|center_vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"
android:text="Dismiss"
android:textColor="@color/dialogxPopButtonBlueDark"
android:textSize="14dp"
android:visibility="gone" />
</LinearLayout>
</com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout>
通过以下代码修改默认主题 MaterialStyle
的设置,使用其他主题可以参考修改:
typescript
DialogX.globalStyle = new MaterialStyle() {
@Override
public PopTipSettings popTipSettings() {
return new PopTipSettings() {
@Override
public int layout(boolean light) {
return R.layout.layout_dialogx_poptip_snackbar;
}
@Override
public ALIGN align() {
return ALIGN.BOTTOM;
}
@Override
public int enterAnimResId(boolean light) {
return com.kongzue.dialogx.R.anim.anim_dialogx_default_enter;
}
@Override
public int exitAnimResId(boolean light) {
return com.kongzue.dialogx.R.anim.anim_dialogx_default_exit;
}
};
}
};
相关参考:使用 DialogX 快速构建 Android App 对话框使用 DialogX 快速构建 Android App 对话框 - 掘金