让DialogX的消息提示玩出花 - 自定义PopTip和 PopNotification的避让动画

让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 对话框 - 掘金

相关推荐
Mikey_n6 分钟前
Spring Boot 注解详细解析:解锁高效开发的密钥
java·spring boot·后端
_yingty_11 分钟前
Java设计模式-策略模式(行为型)
java·设计模式·策略模式
小小寂寞的城30 分钟前
Jenkins里构建一个简单流水线
java·运维·jenkins
飞猿_SIR40 分钟前
Android Exoplayer多路不同时长音视频混合播放
android·音视频
wowocpp1 小时前
idea springboot 配置文件 中文显示
java·spring boot·intellij-idea
User_芊芊君子1 小时前
【Java面试题】——this 和 super 的区别
java·开发语言
柴薪之王、睥睨众生1 小时前
(自用)Java学习-5.8(总结,springboot)
java·开发语言·spring boot·学习·mybatis
牛马baby1 小时前
Java高频面试之并发编程-17
java·开发语言·面试
前端懒猫1 小时前
android实现USB通讯
android
不辉放弃2 小时前
java连数据库
java·mysql