Android Dialog弹出及隐藏动画

1,694 阅读1分钟

Android Dialog弹出及隐藏动画

Android开发中,Dialog是必不可少的组件之一,通常一些活动、提示等内容的展示依赖于Dialog实现。最近需要实现一个需求,Dialog从某View中心位置弹出,隐藏的时候执行相反的动画。

实现也比较简单,使用属性动画可以轻易实现该效果,这里简要记录一下,便于以后回顾或复用。

device-2023-03-02-223333.gif

封装的Dialog代码如下:

public class BaseAnimDialog extends Dialog {
    private AnimatorSet showAnimSet;
    private AnimatorSet dismissAnimSet;

    private static final long DEFAULT_DURATION = 800;

    private float transX;
    private float transY;

    public BaseAnimDialog(@NonNull Context context) {
        super(context, R.style.Dialog);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void show() {
        try {
            super.show();
            View contentView = findViewById(R.id.content);
            if (contentView != null) {
                contentView.setVisibility(View.INVISIBLE);
            }
            showAnim();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    @Override
    public void dismiss() {
        try {
            super.dismiss();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private void showAnim() {
       // dialog主体布局id需要设置为content
        View contentView = findViewById(R.id.content);
        if (contentView == null) {
            return;
        }
        if (showAnimSet == null) {
            showAnimSet = new AnimatorSet();
            ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentView, "translationX", transX, 0);
            ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentView, "translationY", transY, 0);
            ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentView, "scaleX", 0, 1);
            ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentView, "scaleY", 0, 1);
            showAnimSet.playTogether(transXAnim, transYAnim, scaleXAnim, scaleYAnim);
            showAnimSet.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    contentView.setVisibility(View.VISIBLE);
                }
            });
            showAnimSet.setDuration(DEFAULT_DURATION);
        }
        if (showAnimSet.isRunning()) {
            return;
        }
        showAnimSet.start();
    }

    // 外部调用dismissAnim,替代Dialog本身的dismiss方法
    public void dismissAnim() {
        View contentView = findViewById(R.id.content);
        if (contentView == null) {
            return;
        }
        if (dismissAnimSet == null) {
            dismissAnimSet = new AnimatorSet();
            ObjectAnimator transXAnim = ObjectAnimator.ofFloat(contentView, "translationX", 0, transX);
            ObjectAnimator transYAnim = ObjectAnimator.ofFloat(contentView, "translationY", 0, transY);
            ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(contentView, "scaleX", 1, 0);
            ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(contentView, "scaleY", 1, 0);
            dismissAnimSet.playTogether(transXAnim, transYAnim, scaleXAnim, scaleYAnim);
            dismissAnimSet.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    dismiss();
                }
            });
            dismissAnimSet.setDuration(DEFAULT_DURATION);
        }
        if (dismissAnimSet.isRunning()) {
            return;
        }
        dismissAnimSet.start();
    }

    // 传入锚点view数据
    public void setAnchorInfo(float x, float y, float width, float height) {
        // dialog 宽200dp 高230dp
        transX = x - (PxUtil.screenWidth() - PxUtil.dp2xp(200)) / 2f - PxUtil.dp2xp(200) / 2f + width / 2f;
        transY = y - (PxUtil.screenHeight() - PxUtil.dp2xp(230)) / 2f - PxUtil.dp2xp(230) / 2f + height / 2f;
    }
}

Dialog使用Style如下:

<style name="Dialog" parent="@style/Theme.AppCompat.Light.NoActionBar">
    <item name="windowNoTitle">true</item><!--没有标题 -->
    <item name="windowActionBar">true</item><!--没有ActionBar -->
    <item name="android:windowFullscreen">true</item><!--全屏 -->
    <item name="android:windowIsFloating">false</item><!-- 浮动在activity之上,左右两边不会填充屏幕 -->
    <item name="android:windowIsTranslucent">true</item><!-- 半透明 -->
    <item name="android:windowFrame">@null</item><!--无边框 -->
    <item name="android:backgroundDimEnabled">true</item><!-- 设置背景模糊-->
    <item name="android:padding">0dp</item><!--内边距-->
    <item name="android:windowBackground">@android:color/transparent</item><!-- 设置背景模糊-->
</style>

另外,如果项目中本身引入的有FlycoDialog,继承该库中的BaseDialog直接设置showAnimdismissAnim方法更为简单。