Android 几个简单的自定义对话框介绍

Android 几个简单的自定义对话框介绍

文章目录

一、前言

Android 对话框直接使用肯定是不好看的,如果需要添加取消和确定按钮,肯定是需要进行自定义修改的。

本文简单介绍一个简单的可扩展的对话框,并且支持不同类型样式,加了点小动画。

有需要的可以看看。

二、对话框相关内容

1、效果

七个demo对话框显示,项目中可以根据实际情况进行使用。

原生对话框标题和内容是靠左的,如果显示默认的按钮是靠右下角的。

自定义的对话框则可以自己决定居中还是靠左和显示自己需要的图片。

2、对话框显示的调用代码

(1)原生对话框代码:
复制代码
Dialog alertDialog = new AlertDialog.Builder(this).
    setTitle("对话框的标题").
    setMessage("对话框的内容").
    setIcon(R.drawable.ic_launcher).
    create();
alertDialog.show();

虽然 原生的AlertDialog 调用不复杂,但是显示有点丑,并且大小在不同设备上显示大小是不一样的。

AlertDialog 也是可以行决定是否显示确定和取消按钮的,监听setPositiveButton和setNegativeButton方法即可。

(2)自定义对话框代码:
复制代码
 //(1)默认字符串显示,显示一个确认按钮,只是用来测试
 new SweetAlertDialog(this).show();
 
  //(2)修改标题和文本内容,显示一个确认按钮
 new SweetAlertDialog(this)
 .setTitleText("Title!")
 .setContentText("It's pretty, isn't it?")
 .show();
 
   //(3)修改标题和文本内容和类型图标,显示一个确认按钮
 new SweetAlertDialog(this, SweetAlertDialog.CUSTOM_IMAGE_TYPE)
 .setTitleText("Sweet!")
 .setContentText("Here's a custom image.")
 .setCustomImage(R.drawable.custom_img)
 .show();
 
 大部分场景上面三个代码比较常用。
 
 SweetAlertDialog 的类别,一种有五种,每种类别会选择不同的图标显示。
    public static final int NORMAL_TYPE = 0;
    public static final int ERROR_TYPE = 1;
    public static final int SUCCESS_TYPE = 2;
    public static final int WARNING_TYPE = 3;
    public static final int CUSTOM_IMAGE_TYPE = 4;
 
    //(4)修改标题和文本内容和类型图标,显示一个确认按钮,确定后执行相应的动作
 new SweetAlertDialog(this, SweetAlertDialog.SUCCESS_TYPE)
 .setTitleText("Good job!")
 .setContentText("You clicked the button!")
 .setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
         @Override
         public void onClick(SweetAlertDialog sDialog) {
         // reuse previous dialog instance
         Toast.makeText(SampleActivity.this, "confirm" ,Toast.LENGTH_SHORT).show();
         sDialog.dismiss();
        }
	})
.show();
 
    //(5)修改标题和文本内容和类型图标,点击第一次确定后,还要点一次确定
 new SweetAlertDialog(this, SweetAlertDialog.WARNING_TYPE)
 .setTitleText("Are you sure?")
 .setContentText("Won't be able to recover this file!")
 .setCancelText("No,cancel plx!")
 .setConfirmText("Yes,delete it!")
 .showCancelButton(true)
 .setCancelClickListener(new SweetAlertDialog.OnSweetClickListener() {
     @Override
     public void onClick(SweetAlertDialog sDialog) {
         // reuse previous dialog instance
         sDialog.setTitleText("Cancelled!")
         .setContentText("Your imaginary file is safe :)")
         .setConfirmText("OK")
         .showCancelButton(false)
         .setCancelClickListener(null)
         .setConfirmClickListener(null)
         .changeAlertType(SweetAlertDialog.ERROR_TYPE);
         
        // or you can new a SweetAlertDialog to show

    }
})
.setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
    @Override
    public void onClick(SweetAlertDialog sDialog) {
        sDialog.setTitleText("Deleted!")
        .setContentText("Your imaginary file has been deleted!")
        .setConfirmText("OK")
        .showCancelButton(false)
        .setCancelClickListener(null)
        .setConfirmClickListener(null)
        .changeAlertType(SweetAlertDialog.SUCCESS_TYPE);
    }
})
.show();

项目中可以根据实际情况进行适配修改,显示一个按钮还是两个按钮都是可以选择的。

3、对话框SweetAlertDialog 主要实现代码:

复制代码
package com.my.beautifuldialog;


import android.app.Dialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.Transformation;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class SweetAlertDialog extends Dialog implements View.OnClickListener {
    private View mDialogView;
    private AnimationSet mModalInAnim;
    private AnimationSet mModalOutAnim;
    private Animation mOverlayOutAnim;
    private Animation mErrorInAnim;
    private AnimationSet mErrorXInAnim;
    private AnimationSet mSuccessLayoutAnimSet;
    private Animation mSuccessBowAnim;
    private TextView mTitleTextView;
    private TextView mContentTextView;
    private String mTitleText;
    private String mContentText;
    private boolean mShowCancel;
    private String mCancelText;
    private String mConfirmText;
    private int mAlertType;
    private FrameLayout mErrorFrame;
    private FrameLayout mSuccessFrame;
    private SuccessTickView mSuccessTick;
    private ImageView mErrorX;
    private View mSuccessLeftMask;
    private View mSuccessRightMask;
    private Drawable mCustomImgDrawable;
    private ImageView mCustomImage;
    private Button mConfirmButton;
    private Button mCancelButton;
    private FrameLayout mWarningFrame;
    private OnSweetClickListener mCancelClickListener;
    private OnSweetClickListener mConfirmClickListener;
    private boolean mCanceledOnTouchOutside = false;

    public static final int NORMAL_TYPE = 0;
    public static final int ERROR_TYPE = 1;
    public static final int SUCCESS_TYPE = 2;
    public static final int WARNING_TYPE = 3;
    public static final int CUSTOM_IMAGE_TYPE = 4;

    public static interface OnSweetClickListener {
        public void onClick(SweetAlertDialog sweetAlertDialog);
    }

    public SweetAlertDialog(Context context) {
        this(context, NORMAL_TYPE);
    }

    public SweetAlertDialog(Context context, int alertType) {
        super(context, R.style.alert_dialog);
        setCancelable(true);
        setCanceledOnTouchOutside(false);
        mAlertType = alertType;
        mErrorInAnim = OptAnimationLoader.loadAnimation(getContext(), R.anim.error_frame_in);
        mErrorXInAnim = (AnimationSet)OptAnimationLoader.loadAnimation(getContext(), R.anim.error_x_in);
        // 2.3.x system don't support alpha-animation on layer-list drawable
        // remove it from animation set
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { //Android3 一下,其实没啥必要判断了
            List<Animation> childAnims = mErrorXInAnim.getAnimations();
            int idx = 0;
            for (;idx < childAnims.size();idx++) {
                if (childAnims.get(idx) instanceof AlphaAnimation) {
                    break;
                }
            }
            if (idx < childAnims.size()) {
                childAnims.remove(idx);
            }
        }
        mSuccessBowAnim = OptAnimationLoader.loadAnimation(getContext(), R.anim.success_bow_roate);
        mSuccessLayoutAnimSet = (AnimationSet)OptAnimationLoader.loadAnimation(getContext(), R.anim.success_mask_layout);
        mModalInAnim = (AnimationSet) OptAnimationLoader.loadAnimation(getContext(), R.anim.modal_in);
        mModalOutAnim = (AnimationSet) OptAnimationLoader.loadAnimation(getContext(), R.anim.modal_out);
        mModalOutAnim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mDialogView.setVisibility(View.GONE);
                mDialogView.post(new Runnable() {
                    @Override
                    public void run() {
                        SweetAlertDialog.super.dismiss();
                    }
                });
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        // dialog overlay fade out
        mOverlayOutAnim = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                WindowManager.LayoutParams wlp = getWindow().getAttributes();
                wlp.alpha = 1 - interpolatedTime;
                getWindow().setAttributes(wlp);
            }
        };
        mOverlayOutAnim.setDuration(120);
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.alert_dialog);
        mDialogView = getWindow().getDecorView().findViewById(android.R.id.content);
        mTitleTextView = (TextView)findViewById(R.id.title_text);
        mContentTextView = (TextView)findViewById(R.id.content_text);
        mErrorFrame = (FrameLayout)findViewById(R.id.error_frame);
        mErrorX = (ImageView)mErrorFrame.findViewById(R.id.error_x);
        mSuccessFrame = (FrameLayout)findViewById(R.id.success_frame);
        mSuccessTick = (SuccessTickView)mSuccessFrame.findViewById(R.id.success_tick);
        mSuccessLeftMask = mSuccessFrame.findViewById(R.id.mask_left);
        mSuccessRightMask = mSuccessFrame.findViewById(R.id.mask_right);
        mCustomImage = (ImageView)findViewById(R.id.custom_image);
        mWarningFrame = (FrameLayout)findViewById(R.id.warning_frame);
        mConfirmButton = (Button)findViewById(R.id.confirm_button);
        mCancelButton = (Button)findViewById(R.id.cancel_button);

        mConfirmButton.setOnClickListener(this);
        mCancelButton.setOnClickListener(this);

        setTitleText(mTitleText);
        setContentText(mContentText);
        showCancelButton(mShowCancel);
        setCancelText(mCancelText);
        setConfirmText(mConfirmText);
        changeAlertType(mAlertType, true);
//        getWindow().setBackgroundDrawableResource(android.R.color.transparent);
    }

    private void restore () {
        mCustomImage.setVisibility(View.GONE);
        mErrorFrame.setVisibility(View.GONE);
        mSuccessFrame.setVisibility(View.GONE);
        mWarningFrame.setVisibility(View.GONE);

        mConfirmButton.setBackgroundResource(R.drawable.blue_button_background);
        mErrorFrame.clearAnimation();
        mErrorX.clearAnimation();
        mSuccessTick.clearAnimation();
        mSuccessLeftMask.clearAnimation();
        mSuccessRightMask.clearAnimation();
    }

    private void playAnimation () {
        if (mAlertType == ERROR_TYPE) {
            mErrorFrame.startAnimation(mErrorInAnim);
            mErrorX.startAnimation(mErrorXInAnim);
        } else if (mAlertType == SUCCESS_TYPE) {
            mSuccessTick.startTickAnim();
            mSuccessRightMask.startAnimation(mSuccessBowAnim);
        }
    }

    private void changeAlertType(int alertType, boolean fromCreate) {
        mAlertType = alertType;
        // call after created views
        if (mDialogView != null) {
            if (!fromCreate) {
                // restore all of views state before switching alert type
                restore();
            }
            switch (mAlertType) {
                case ERROR_TYPE:
                    mErrorFrame.setVisibility(View.VISIBLE);
                    break;
                case SUCCESS_TYPE:
                    mSuccessFrame.setVisibility(View.VISIBLE);
                    // initial rotate layout of success mask
                    mSuccessLeftMask.startAnimation(mSuccessLayoutAnimSet.getAnimations().get(0));
                    mSuccessRightMask.startAnimation(mSuccessLayoutAnimSet.getAnimations().get(1));
                    break;
                case WARNING_TYPE:
                    mConfirmButton.setBackgroundResource(R.drawable.red_button_background);
                    mWarningFrame.setVisibility(View.VISIBLE);
                    break;
                case CUSTOM_IMAGE_TYPE:
                    setCustomImage(mCustomImgDrawable);
                    break;
            }
            if (!fromCreate) {
                playAnimation();
            }
        }
    }

    public int getAlerType () {
        return mAlertType;
    }

    public void changeAlertType(int alertType) {
        changeAlertType(alertType, false);
    }


    public String getTitleText () {
        return mTitleText;
    }

    //解决dialog.setCanceledOnTouchOutside(true) 不生效问题
    public void setDialogTouchOutsideCloseable(Dialog dialog, int gravity) {
        Window window = dialog.getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = ViewGroup.LayoutParams.MATCH_PARENT;
        params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        window.setAttributes(params);
        window.setGravity(gravity);

    }

    //设置点击外部消失
    public SweetAlertDialog setCanceledOutside(boolean cancel) {
        setCanceledOnTouchOutside(cancel);
        return this;
    }

    //设置标题
    public SweetAlertDialog setTitleText (String text) {
        mTitleText = text;
        if (mTitleTextView != null && mTitleText != null) {
            mTitleTextView.setText(mTitleText);
        }
        return this;
    }

    //设置标题上方图标,Drawable 对象
    public SweetAlertDialog setCustomImage (Drawable drawable) {
        mCustomImgDrawable = drawable;
        if (mCustomImage != null && mCustomImgDrawable != null) {
            mCustomImage.setVisibility(View.VISIBLE);
            mCustomImage.setImageDrawable(mCustomImgDrawable);
        }
        return this;
    }

    //设置标题上方图标,Drawable int值
    public SweetAlertDialog setCustomImage (int resourceId) {
        return setCustomImage(getContext().getResources().getDrawable(resourceId));
    }

    public String getContentText () {
        return mContentText;
    }

    //设置显示内容
    public SweetAlertDialog setContentText (String text) {
        mContentText = text;
        if (mContentTextView != null && mContentText != null) {
            mContentTextView.setVisibility(View.VISIBLE);
            mContentTextView.setText(mContentText);
        }
        return this;
    }

    public boolean isShowCancelButton () {
        return mShowCancel;
    }

    //显示取消按钮
    public SweetAlertDialog showCancelButton (boolean isShow) {
        mShowCancel = isShow;
        if (mCancelButton != null) {
            mCancelButton.setVisibility(mShowCancel ? View.VISIBLE : View.GONE);
        }
        return this;
    }

    public String getCancelText () {
        return mCancelText;
    }

    //设置取消按钮的文字
    public SweetAlertDialog setCancelText (String text) {
        mCancelText = text;
        if (mCancelButton != null && mCancelText != null) {
            mCancelButton.setText(mCancelText);
        }
        return this;
    }

    public String getConfirmText () {
        return mConfirmText;
    }

    //设置确认按钮的文字
    public SweetAlertDialog setConfirmText (String text) {
        mConfirmText = text;
        if (mConfirmButton != null && mConfirmText != null) {
            mConfirmButton.setText(mConfirmText);
        }
        return this;
    }

    public SweetAlertDialog setCancelClickListener (OnSweetClickListener listener) {
        mCancelClickListener = listener;
        return this;
    }

    public SweetAlertDialog setConfirmClickListener (OnSweetClickListener listener) {
        mConfirmClickListener = listener;
        return this;
    }

    protected void onStart() {
        mDialogView.startAnimation(mModalInAnim);
        playAnimation();
    }

    public void dismiss() {
        mConfirmButton.startAnimation(mOverlayOutAnim);
        mDialogView.startAnimation(mModalOutAnim);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.cancel_button) {
            if (mCancelClickListener != null) {
                mCancelClickListener.onClick(SweetAlertDialog.this);
            } else {
                dismiss();
            }
        } else if (v.getId() == R.id.confirm_button) {
            if (mConfirmClickListener != null) {
                mConfirmClickListener.onClick(SweetAlertDialog.this);
            } else {
                dismiss();
            }
        }
    }
}

4、优点和缺点

(1)优点
复制代码
显示方便UI好看
调用api简单方便
确定和取消按钮可以选择显示一个或者两个
添加了不同类别图标,并且图标会显示动画效果
扩展了点击一次确定后,还可以进行多次弹框的情况
(2)缺点
复制代码
对话框显示的大小基本固定,适合简单信息的显示
对话框无法设置点击周边就消失,因为已经全局显示了
(3)其他扩展

可以用来做自定义Toast。

具体实现思路是:自定义几秒后,执行dismiss关闭对话框。

三、其他

1、小结

网上有千千万万中自定义对话框,各种花里胡哨的也很多,但是简单使用的很少。

在很多实际项目中只要用到demo代码中的最普通的显示文本的情况就ok的,需要显示图片的场景并不多。

并且上面显示图片类型的代码,都是添加了不同动画类的,移植反而麻烦。

所以一般的使用只移植简单文本部分的功能使用就OK了。

其他的就当预留的吧,万一真的要呢。

如果对话框UI没啥要求,只要可以显示文本和确定、取消按钮这样的场景,使用原生的AlertDialog很好了。

2、Android对话框的使用总结

都是对原生对话框的详细介绍

https://blog.csdn.net/wenzhi20102321/article/details/52818351

3、Android加载中对话框示例

转圈圈的加载中对话框

https://blog.csdn.net/wenzhi20102321/article/details/79619719

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui