欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Android] 仿IOS实现自定义Dialog,底部弹窗和中间弹窗工具

程序员文章站 2022-07-02 19:50:35
...

用过Android的默认对话框的都懂,不管是哪个版本的对话框,都丑到爆!就算是Google推崇的Material Design风格的弹窗一样不好看,基本每款APP都不会去使用默认的对话框样式,他们都有自己的风格,怎样去改变默认的对话框样式呢?只能自定义了,将系统对话框改为自己喜欢或者是APP特有风格的样式。本文将介绍如何去实现自定义Dialog,仿IOS,并添加动画效果,并提供丰富的方法调用,让开发者可以在已有样式的基础上进行进一步的细节改变。算是一个工具类了,直接copy就可以直接用了。

原创文章,转载请注明出处:https://blog.csdn.net/Lone1yCode/article/details/79927873

一、举例

这是Android 4.2版本的弹窗:

[Android] 仿IOS实现自定义Dialog,底部弹窗和中间弹窗工具

这是Android 7.0版本的弹窗:

[Android] 仿IOS实现自定义Dialog,底部弹窗和中间弹窗工具

我是没有觉得很好看。大概这就是程序员的审美吧。

下面再看一下IOS的对话框,话说找这个对话框太难了。我找了好久好久,都找不到有什么地方能弹窗,不找的时候一直有。还好不负所望,找了俩。中间弹窗对话框:

[Android] 仿IOS实现自定义Dialog,底部弹窗和中间弹窗工具

IOS底部弹窗:

[Android] 仿IOS实现自定义Dialog,底部弹窗和中间弹窗工具

是不是感觉还不错!Android的系统对话框虽然样式很丑,但毕竟是开源系统,它可以轻松实现对话框样式的自定义,而且Android的对话框的样式基本一个APP就一个样,种类繁多,样式丰富。

二、实现效果

经过自定义后,现在的Dialog已经能实现各种丰富的样式了。

[Android] 仿IOS实现自定义Dialog,底部弹窗和中间弹窗工具

可以看到自定义的Dialog已经实现了IOS效果的弹窗。并且里面的按钮、文本、标题都可以在使用时进行各种详细的定义,如改变文字颜色、文字大小、文字粗体、背景色,还可以传入自己定义的动画效果去替换原有的动画效果,如果不觉得突兀,还可以取消动画效果

三、特点

其实特点就是仿照IOS的特点。

1、圆角。经过自定义的弹窗,其圆角效果已经和IOS的很接近了,而且圆角很大,当然如果你不喜欢,可以在XML文件中进行修改,目前的圆角是15。

2、Dialog控件之间的间隔很大。这应该也算是IOS风格的一个特色了,它的文字、留白都非常大,如果说多数Android的弹窗效果都是小巧玲珑的话,这种风格可以说是豪迈奔放了。

3、动画效果。这个动画效果是完全仿IOS的,底部弹窗效果不是很像,只是加了一个平移效果。中间弹窗的话还能算是精仿,包括缩放和透明度的变化。

四、全部代码

说实话,全部代码并不长,只是注释太多,占用了绝大部分的空间。

1、MyDialog核心类

package com.my.dialogdemo;

import android.app.Dialog;
import android.content.Context;
import android.support.v7.app.ActionBar;
import android.text.TextPaint;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static android.content.ContentValues.TAG;

public class MyDialog {

    private Context mContext;                       //上下文

    private View mDialogLayout;                     //弹窗布局

    private boolean mCancelable = true;             //返回键、窗体外区域是否可点击取消,默认可以

    private View.OnClickListener positiveButton;    //positive区域监听器
    private View.OnClickListener negativeButton;    //negative区域监听器

    private AdapterView.OnItemClickListener mItemClickListener;  //item的点击事件

    private Dialog dialog;                          //构建的弹窗

    private int mCustomAnim;                        //自定义动画

    private boolean mIsShowTitle;                   //是否显示标题,默认不显示
    private boolean mIsShowNegativeButton;          //是否显示negative区域按钮,默认不显示
    private boolean mIsShowPositiveButton;          //是否显示positive区域按钮,默认不显示
    private boolean mIsShowListView;                //是否在内容区显示ListView,默认不显示
    private boolean mIsHaveCustomAnim;              //是否含有自定义的动画效果

    private boolean mIsShowBottomTitle;             //是否显示底部弹窗标题,默认不显示
    private boolean mIsShowBottomNegativeButton;    //是否显示底部弹窗的negative区域按钮,默认不显示
    private boolean mIsBottomDialog;                //是否是底部弹窗,默认中间弹窗

    private MyAdapter mAdapter;                     //Adapter,设配自定义的数据
    private List<StringItemBean> mDataList;         //数据源,显示的文本

    public static final String BOTTOM = "BOTTOM";   //底部弹窗标志

    /**
     * 中间弹窗,构造函数
     *
     * @param context 上下文
     */
    public MyDialog(Context context) {
        this.mContext = context;
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mDialogLayout = inflater.inflate(R.layout.my_custom_dialog_layout, null);
    }

    /**
     * 中间弹窗,构造函数,需要传入自定义动画的ID,若传入0,则代表无动画
     *
     * @param context    上下文
     * @param customAnim 自定义的动画效果ID
     */
    public MyDialog(Context context, int customAnim) {
        this(context);
        mCustomAnim = customAnim;
        mIsHaveCustomAnim = true;
    }

    /**
     * 底部弹窗,构造函数,需要传入String类型参数,BOTTOM,才会显示底部Dialog
     *
     * @param context 上下文
     * @param gravity 位置,String类型,必须是"BOTTOM"才会显示底部Dialog
     */
    public MyDialog(Context context, String gravity) {
        this.mContext = context;
        if (gravity.equals(BOTTOM)) {
            mIsBottomDialog = true;
        }
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mDialogLayout = inflater.inflate(R.layout.my_custom_bottom_dialog_layout, null);
    }

    /**
     * 都不弹窗,构造函数,需要传入String类型参数,BOTTOM,才会显示底部Dialog;自定义动画效果
     *
     * @param context    上下文
     * @param customAnim 自定义的动画效果
     * @param gravity    位置,String类型,必须是"BOTTOM"才会显示底部Dialog
     */
    public MyDialog(Context context, int customAnim, String gravity) {
        this.mContext = context;
        if (gravity.equals(BOTTOM)) {
            mIsBottomDialog = true;
        }
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mDialogLayout = inflater.inflate(R.layout.my_custom_bottom_dialog_layout, null);
        mCustomAnim = customAnim;
        mIsHaveCustomAnim = true;
    }

    /**
     * 能否返回键取消和点击弹窗外部区域取消
     * 中间、底部弹窗共用
     *
     * @param boolean1 true 代表可以取消,false 不可取消
     * @return this
     */
    public MyDialog setCancelable(Boolean boolean1) {
        this.mCancelable = boolean1;
        return this;
    }

    /**
     * 中间弹窗,设置标题 int型 不常用,适配更多类型可重载多个该方法,参数类型不同即可
     *
     * @param title int型参数
     * @return this
     */
    public MyDialog setTitle(int title) {
        mIsShowTitle = true;
        ((TextView) mDialogLayout.findViewById(R.id.title)).setText(title);
        return this;
    }

    /**
     * 中间弹窗,设置标题 String型 最常用
     *
     * @param title String型参数
     * @return this
     */
    public MyDialog setTitle(String title) {
        mIsShowTitle = true;
        ((TextView) mDialogLayout.findViewById(R.id.title)).setText(title);
        return this;
    }

    /**
     * 中间弹窗,设置标题文字大小
     *
     * @param size 大小值,int型
     * @return this
     */
    public MyDialog setTitleSize(int size) {
        ((TextView) mDialogLayout.findViewById(R.id.title)).setTextSize(size);
        return this;
    }

    /**
     * 中间弹窗,设置标题文字颜色
     *
     * @param color 颜色
     * @return this
     */
    public MyDialog setTitleColor(int color) {
        ((TextView) mDialogLayout.findViewById(R.id.title)).setTextColor(mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 中间弹窗,设置标题字体为粗体
     *
     * @return this
     */
    public MyDialog setTitleStyleBold(){
        TextView tv = (TextView)mDialogLayout.findViewById(R.id.title);
        TextPaint tp = tv.getPaint();
        tp.setFakeBoldText(true);
        return this;
    }

    /**
     * 中间弹窗,设置标题区域的背景颜色 不常用
     *
     * @param color 颜色
     * @return this
     */
    public MyDialog setTitleBackgroundColor(int color) {
        mDialogLayout.findViewById(R.id.title_background).setBackgroundColor(mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 中间弹窗,设置内容,int型,不常用,适配更多类型可重载多个该方法,参数类型不同即可
     *
     * @param message int型参数
     * @return this
     */
    public MyDialog setMessage(int message) {
        ((TextView) mDialogLayout.findViewById(R.id.message)).setText(message);
        return this;
    }

    /**
     * 中间弹窗,设置内容,String型,最常用
     *
     * @param message String型信息
     * @return this
     */
    public MyDialog setMessage(String message) {
        ((TextView) mDialogLayout.findViewById(R.id.message)).setText(message);
        return this;
    }

    /**
     * 中间弹窗,设置内容的文本颜色
     *
     * @param color 文本颜色
     * @return this
     */
    public MyDialog setMessageColor(int color){
        ((TextView) mDialogLayout.findViewById(R.id.message)).setTextColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 中间弹窗,设置内容区域的背景色
     *
     * @param color 背景色
     * @return this
     */
    public MyDialog setMessageBackground(int color){
        mDialogLayout.findViewById(R.id.content).setBackgroundColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 中间弹窗,设置negative区域的文本和点击事件,一般为"取消"
     * 同AlertDialog.Builder的设置名称相同
     *
     * @param negativeText 按钮文本
     * @param listener     监听器
     * @return this
     */
    public MyDialog setNegativeButton(String negativeText, View.OnClickListener listener) {
        mIsShowNegativeButton = true;
        ((TextView) mDialogLayout.findViewById(R.id.negative)).setText(negativeText);
        this.negativeButton = listener;
        return this;
    }

    /**
     * 中间弹窗,设置negative区域显示文本的颜色,如蓝色的"取消"文字
     * 多数APP如网购APP,在某个商品浏览页面,不希望用户退出又必须要给出退出提示时,多将negative设置为显眼的颜色
     * 而positive设置为暗色。所以该方法还是使用比较常见的
     *
     * @param color 颜色
     * @return this
     */
    public MyDialog setNegativeButtonColor(int color) {
        ((TextView) mDialogLayout.findViewById(R.id.negative)).setTextColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 中间弹窗,设置negative文本的大小
     *
     * @param size 文本大小
     * @return this
     */
    public MyDialog setNegativeButtonTextSize(int size){
        ((TextView) mDialogLayout.findViewById(R.id.negative)).setTextSize(size);
        return this;
    }

    /**
     * 中间弹窗,设置negative文本字体为粗体
     *
     * @return this
     */
    public MyDialog setNegativeButtonStyleBold(){
        TextView tv = (TextView) mDialogLayout.findViewById(R.id.negative);
        TextPaint tp = tv.getPaint();
        tp.setFakeBoldText(true);
        return this;
    }

    /**
     * 中间弹窗,设置positive区域的文本和点击事件,一般为"确定"
     * 同AlertDialog.Builder的设置名称相同
     *
     * @param positiveText 按钮文本
     * @param listener     监听器
     * @return this
     */
    public MyDialog setPositiveButton(String positiveText, View.OnClickListener listener) {
        mIsShowPositiveButton = true;
        ((TextView) mDialogLayout.findViewById(R.id.positive)).setText(positiveText);
        this.positiveButton = listener;
        return this;
    }

    /**
     * 中间弹窗,设置positive区域显示文本的颜色,如蓝色的"确定"文字
     *
     * @param color 颜色
     * @return this
     */
    public MyDialog setPositiveButtonColor(int color) {
        ((TextView) mDialogLayout.findViewById(R.id.positive)).setTextColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 中间弹窗,设置positive区域显示文本的大小
     *
     * @param size 文本大小
     * @return this
     */
    public MyDialog setPositiveButtonSize(int size){
        ((TextView) mDialogLayout.findViewById(R.id.positive)).setTextSize(size);
        return this;
    }

    /**
     * 中间弹窗,设置positive文本字体为粗体
     *
     * @return this
     */
    public MyDialog setPositiveButtonStyleBold(){
        TextView tv = (TextView) mDialogLayout.findViewById(R.id.positive);
        TextPaint tp = tv.getPaint();
        tp.setFakeBoldText(true);
        return this;
    }

    /**
     * 中间弹窗,重新设置内容的显示控件
     * 默认的Dialog只有一个显示的TextView,替换显示控件可以实现显示更丰富的内容,如图片 + 文本。
     *
     * @param v 要显示的控件
     * @return this
     */
    public MyDialog setView(View v) {
        ((FrameLayout) mDialogLayout.findViewById(R.id.sv)).removeAllViews();
        //进行判断,否则第二次弹出Dialog时会报异常
        //异常:java.lang.IllegalStateException: The specified child already has a parent.
        //     You must call removeView() on the child's parent first.
        ViewGroup parent = (ViewGroup) v.getParent();
        if (parent != null) {
            parent.removeAllViews();
        }
        ((FrameLayout) mDialogLayout.findViewById(R.id.sv)).addView(v);
        return this;
    }

    /**
     * 设置显示内容为ListView,传入要显示的数组和监听事件
     * 显示默认颜色
     * 中间弹窗和底部弹窗共用
     *
     * @param data     数据源,数组,String类型
     * @param listener item的监听事件,短按类型
     * @return this
     */
    public MyDialog setListView(String[] data, AdapterView.OnItemClickListener listener) {
        setListView(Arrays.asList(data), listener);
        return this;
    }

    /**
     * 设置显示内容为ListView,传入要显示的list和监听事件
     * 显示默认颜色
     * 中间弹窗和底部弹窗共用
     *
     * @param list     数据源,list,String类型
     * @param listener item的监听事件,短按类型
     * @return this
     */
    public MyDialog setListView(List<String> list, AdapterView.OnItemClickListener listener) {
        mItemClickListener = listener;
        mIsShowListView = true;
        mDataList = new ArrayList<>();
        for (String str : list) {
            mDataList.add(new StringItemBean(str));
        }
        mAdapter = new MyAdapter(mContext, R.layout.string_item_layout, mDataList);
        return this;
    }

    /**
     * 设置显示内容为ListView,可以设置item的颜色,且可以分别设置
     * 数据源类型:数组,数组
     * 中间弹窗和底部弹窗共用
     *
     * @param data     数据源,数组,String类型
     * @param colors   颜色数据源,数组,Integer类型
     * @param listener item的监听事件,短按类型
     * @return this
     */
    public MyDialog setListView(String[] data, Integer[] colors, AdapterView.OnItemClickListener listener) {
        setListView(Arrays.asList(data), Arrays.asList(colors), listener);
        return this;
    }

    /**
     * 设置显示内容为ListView,可以设置item的颜色,且可以分别设置
     * 数据源类型:List,数组
     * 中间弹窗和底部弹窗共用
     *
     * @param list     数据源,List,String类型
     * @param colors   颜色数据源,数组,Integer类型
     * @param listener item的监听事件,短按类型
     * @return this
     */
    public MyDialog setListView(List<String> list, Integer[] colors, AdapterView.OnItemClickListener listener) {
        setListView(list, Arrays.asList(colors), listener);
        return this;
    }

    /**
     * 设置显示内容为ListView,可以设置item的颜色,且可以分别设置
     * 数据源类型:数组,List
     * 中间弹窗和底部弹窗共用
     *
     * @param data     数据源,数组,String类型
     * @param colors   颜色数据源,List,Integer类型
     * @param listener item的监听事件,短按类型
     * @return this
     */
    public MyDialog setListView(String[] data, List<Integer> colors, AdapterView.OnItemClickListener listener) {
        setListView(Arrays.asList(data), colors, listener);
        return this;
    }

    /**
     * 设置显示内容为ListView,可以设置item的颜色,且可以分别设置
     * 数据源类型:List,List,
     * 不管传入的数据源和颜色数据源的类型是数组还是List,最后都要使用这个方法进行设置
     * 中间弹窗和底部弹窗共用
     *
     * @param list     数据源,List,String类型
     * @param colors   颜色数据源,List,Integer类型
     * @param listener item的监听事件
     * @return this
     */
    public MyDialog setListView(List<String> list, List<Integer> colors, AdapterView.OnItemClickListener listener) {
        mIsShowListView = true;
        mItemClickListener = listener;
        mDataList = new ArrayList<>();
        for (String str : list) {
            mDataList.add(new StringItemBean(str));
        }
        mAdapter = new MyAdapter(mContext, R.layout.string_item_layout, mDataList, colors);
        return this;
    }

    /**
     * 底部弹窗,重新设置内容的显示控件
     *
     * @param v 要显示的控件
     * @return this
     */
    public MyDialog setBottomView(View v) {
        ((LinearLayout) mDialogLayout.findViewById(R.id.list_content)).removeAllViews();
        ViewGroup parent = (ViewGroup) v.getParent();
        if (parent != null) {
            parent.removeAllViews();
        }
        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        int height = wm.getDefaultDisplay().getHeight();
        if (getMsgListViewHeight((ListView) v) > height / 5 * 3){
            //如果List的高度大于屏幕高度的4/5
            LinearLayout.LayoutParams LayoutParams = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,height / 5 * 3);
            mDialogLayout.findViewById(R.id.list_content).setLayoutParams(LayoutParams);
        }
        ((LinearLayout) mDialogLayout.findViewById(R.id.list_content)).addView(v);
        return this;
    }

    /**
     * 底部弹窗,设置标题
     *
     * @param title 整型标题
     * @return this
     */
    public MyDialog setBottomTitle(int title) {
        mIsShowBottomTitle = true;
        ((TextView) mDialogLayout.findViewById(R.id.bottom_title)).setText(title);
        return this;
    }

    /**
     * 底部弹窗,设置标题
     *
     * @param title String型标题
     * @return this
     */
    public MyDialog setBottomTitle(String title) {
        mIsShowBottomTitle = true;
        ((TextView) mDialogLayout.findViewById(R.id.bottom_title)).setText(title);
        return this;
    }

    /**
     * 底部弹窗,设置标题文本的颜色
     *
     * @param color 文本颜色
     * @return this
     */
    public MyDialog setBottomTitleColor(int color) {
        ((TextView) mDialogLayout.findViewById(R.id.bottom_title)).setTextColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 设置底部弹窗标题文本的文字大小
     *
     * @param size 文字大小
     * @return this
     */
    public MyDialog setBottomTitleSize(int size){
        ((TextView) mDialogLayout.findViewById(R.id.bottom_title)).setTextSize(size);
        return this;
    }

    /**
     * 底部弹窗,设置标题区域的背景色
     *
     * @param color 背景色
     * @return this
     */
    public MyDialog setBottomTitleBackground(int color) {
        mIsShowBottomTitle = true;
        mDialogLayout.findViewById(R.id.bottom_title_content).setBackgroundColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 底部弹窗,设置Negative的文本和点击事件,点击事件可为null
     *
     * @param negativeText 文本,如"取消"
     * @param listener     negative区域的监听事件
     * @return this
     */
    public MyDialog setBottomNegativeButton(String negativeText, View.OnClickListener listener) {
        mIsShowBottomNegativeButton = true;
        ((TextView) mDialogLayout.findViewById(R.id.bottom_negative)).setText(negativeText);
        this.negativeButton = listener;
        return this;
    }

    /**
     * 底部弹窗,设置negative文本的颜色
     *
     * @param color 文本颜色
     * @return this
     */
    public MyDialog setBottomNegativeButtonColor(int color) {
        ((TextView) mDialogLayout.findViewById(R.id.bottom_negative)).setTextColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 底部弹窗,设置negative文本的字体大小
     *
     * @param size 文本大小
     * @return this
     */
    public MyDialog setBottomNegativeButtonSize(int size){
        ((TextView) mDialogLayout.findViewById(R.id.bottom_negative)).setTextSize(size);
        return this;
    }

    /**
     * 设置底部弹窗negative文本的字体为粗体
     *
     * @return this
     */
    public MyDialog setBottomNegativeButtomStyleBold(){
        TextView tv = (TextView) mDialogLayout.findViewById(R.id.bottom_negative);
        TextPaint tp = tv.getPaint();
        tp.setFakeBoldText(true);
        return this;
    }

    /**
     * 设置底部弹窗negative区域的背景色
     *
     * @param color 背景色
     * @return this
     */
    public MyDialog setBottomNegativeButtonBackground(int color) {
        mDialogLayout.findViewById(R.id.bottom_negative_content).setBackgroundColor(
                mContext.getResources().getColor(color));
        return this;
    }

    /**
     * 获取List的总高度
     * @param mMessageCenterLv ListView
     * @return this
     */
    private int getMsgListViewHeight(ListView mMessageCenterLv) {
        //ListView总高度
        int totalHeight = 0;
        ListAdapter listAdapter = mMessageCenterLv.getAdapter();
        if (listAdapter == null) {
            return totalHeight;
        }
        int height = 0;
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, mMessageCenterLv);
            int desiredWidth = View.MeasureSpec.makeMeasureSpec(mMessageCenterLv.getWidth(), View.MeasureSpec.AT_MOST);
            listItem.measure(desiredWidth, 0);
            height += (listItem.getMeasuredHeight());
            Log.d(TAG, "每项item的高度:"+listItem.getMeasuredHeight());
        }
        totalHeight = height + (mMessageCenterLv.getDividerHeight() * (listAdapter.getCount() - 1));
        return totalHeight;
    }

    /**
     * 构建窗体,所有链式调用都在这里进行集中整理
     *
     * @return 构建完毕的窗体
     */
    public Dialog builder() {
        dialog = new Dialog(mContext, R.style.MyDialogTheme);
        dialog.setCancelable(mCancelable);
        dialog.addContentView(mDialogLayout, new ActionBar.LayoutParams(
                ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT));
        //如果是中间弹窗
        if (!mIsBottomDialog) {
            //如果没有设置Title
            if (!mIsShowTitle) {
                mDialogLayout.findViewById(R.id.title_background).setVisibility(View.GONE);
            }
            //如果设置显示了ListView
            if (mIsShowListView) {
                ListView listView = new ListView(mContext);
                LinearLayout.LayoutParams listLayoutParams = new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
                listView.setLayoutParams(listLayoutParams);
                listView.setAdapter(mAdapter);
                int list_height = getMsgListViewHeight(listView);   //获取ListView的高度

                Log.v(TAG, "List的总高度为:"+list_height);
                WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
                int height = wm.getDefaultDisplay().getHeight();
                Log.d(TAG, "屏幕高度:" + height);
                if (list_height > height*3/5) {
                    list_height = height*3/5;
                }
                LinearLayout.LayoutParams LayoutParams = new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.MATCH_PARENT, list_height);
                ((ScrollView) mDialogLayout.findViewById(R.id.sv)).setLayoutParams(LayoutParams);

                setView(listView);
                if (mItemClickListener != null) {
                    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                            mItemClickListener.onItemClick(parent, view, position, id);
                            dialog.dismiss();
                        }
                    });
                } else {
                    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                            dialog.dismiss();
                        }
                    });
                }
            }
            //如果设置了negative区域的按钮
            if (mIsShowNegativeButton) {
                if (negativeButton != null) {
                    mDialogLayout.findViewById(R.id.negative).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            negativeButton.onClick(v);
                            dialog.dismiss();
                        }
                    });
                } else {
                    mDialogLayout.findViewById(R.id.negative).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            dialog.dismiss();
                        }
                    });
                }
            } else {
                mDialogLayout.findViewById(R.id.negative).setVisibility(View.GONE);
                mDialogLayout.findViewById(R.id.line3).setVisibility(View.GONE);
            }
            //如果设置了positive区域的按钮
            if (mIsShowPositiveButton) {
                if (positiveButton != null) {
                    mDialogLayout.findViewById(R.id.positive).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            positiveButton.onClick(v);
                            dialog.dismiss();
                        }
                    });
                } else {
                    mDialogLayout.findViewById(R.id.positive).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            dialog.dismiss();
                        }
                    });
                }
            } else {
                mDialogLayout.findViewById(R.id.positive).setVisibility(View.GONE);
                mDialogLayout.findViewById(R.id.line3).setVisibility(View.GONE);
            }
            mDialogLayout.findViewById(R.id.negative).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (negativeButton != null) {
                        negativeButton.onClick(v);
                    }
                    dialog.dismiss();
                }
            });
            //如果有自定义的动画效果传入,就显示传入的动画效果,否则显示默认效果,另外:传入0,无动画
            if (mIsHaveCustomAnim) {
                if (mCustomAnim != 0) { //设置显示dialog的显示动画
                    dialog.getWindow().setWindowAnimations(mCustomAnim);
                }
            } else {                    //设置默认dialog的显示动画
                dialog.getWindow().setWindowAnimations(R.style.DialogInAndOutAnim);
            }
        } else { //是底部弹窗
            //如果没有设置底部弹窗标题
            if (!mIsShowBottomTitle) {
                mDialogLayout.findViewById(R.id.bottom_title_content).setVisibility(View.GONE);
            }
            //如果设置了显示ListView
            if (mIsShowListView) {
                ListView listView = new ListView(mContext);
                LinearLayout.LayoutParams listLayoutParams = new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
                listView.setLayoutParams(listLayoutParams);
                listView.setAdapter(mAdapter);
                setBottomView(listView);
                if (mItemClickListener != null) {
                    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                            mItemClickListener.onItemClick(parent, view, position, id);
                            dialog.dismiss();
                        }
                    });
                } else {
                    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                            dialog.dismiss();
                        }
                    });
                }
            }
            //如果设置了显示底部Negative按钮
            if (mIsShowBottomNegativeButton) {
                if (negativeButton != null) {
                    mDialogLayout.findViewById(R.id.bottom_negative_content).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            negativeButton.onClick(v);
                            dialog.dismiss();
                        }
                    });
                } else {
                    mDialogLayout.findViewById(R.id.bottom_negative_content).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            dialog.dismiss();
                        }
                    });
                }
            } else {
                mDialogLayout.findViewById(R.id.bottom_negative_content).setVisibility(View.GONE);
            }
            //如果有自定义的动画效果传入,就显示传入的动画效果,否则显示默认效果,另外:传入0,无动画
            if (mIsHaveCustomAnim) {
                if (mCustomAnim != 0) { //设置显示底部dialog的显示动画
                    dialog.getWindow().setWindowAnimations(mCustomAnim);
                }
            } else {                    //设置默认底部dialog的显示动画
                dialog.getWindow().setWindowAnimations(R.style.BottomDialogInAndOutAnim);
            }
            Window dialogWindow = dialog.getWindow();
            dialogWindow.setGravity(Gravity.BOTTOM);
        }

        return dialog;
    }
}

2、所有Layout文件代码

(1)、中间弹窗设计:my_custom_dialog_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/my_dialog_bg"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/title_background"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:minHeight="50dp"
        android:paddingEnd="15dp"
        android:paddingStart="15dp"
        android:paddingTop="10dp">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:gravity="center"
            android:maxLines="1"
            android:text="标题"
            android:textColor="@color/black"
            android:textSize="20sp" />

    </LinearLayout>

    <ScrollView
        android:id="@+id/sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        android:fadingEdge="none"
        android:overScrollMode="never">

        <LinearLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:minHeight="80dp"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="15dp"
                android:text="内容"
                android:textColor="@color/black"
                android:textSize="16sp" />

        </LinearLayout>

    </ScrollView>

    <View
        android:id="@+id/line2"
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="@color/line" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/negative"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingBottom="15dp"
            android:paddingTop="15dp"
            android:text="取消"
            android:textColor="@color/gray"
            android:textSize="18sp"
            android:textStyle="normal" />

        <View
            android:id="@+id/line3"
            android:layout_width="0.5dp"
            android:layout_height="match_parent"
            android:background="@color/line" />

        <TextView
            android:id="@+id/positive"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingBottom="15dp"
            android:paddingTop="15dp"
            android:text="确认"
            android:textColor="@color/blue"
            android:textSize="18sp"
            android:textStyle="normal" />

    </LinearLayout>

</LinearLayout>

(2)、底部弹窗设计:my_custom_bottom_dialog_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="@android:color/transparent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/my_dialog_bg"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/bottom_title_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:id="@+id/bottom_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="15dp"
                android:layout_gravity="center"
                android:text="标题" />

            <View
                android:id="@+id/line"
                android:layout_width="match_parent"
                android:layout_height="0.5dp"
                android:background="@color/line"/>

        </LinearLayout>

        <LinearLayout
            android:id="@+id/list_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

        </LinearLayout>

    </LinearLayout>

    <LinearLayout
        android:id="@+id/bottom_negative_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/my_dialog_bg"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:padding="15dp"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:id="@+id/bottom_negative"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="取消"
            android:textSize="18sp"
            android:textColor="@color/blue" />

    </LinearLayout>

</LinearLayout>

(3)、弹窗List的item设计:string_item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="15dp"
    android:gravity="center">

    <!-- item显示文本,默认大小18,字体颜色蓝色 -->
    <TextView
        android:id="@+id/item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textColor="@color/blue" />

</RelativeLayout>

(4)、测试使用的替换布局:edit_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/edittext_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="15dp"
    android:orientation="horizontal">

    <EditText
        android:id="@+id/editText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:layout_marginStart="30dp"
        android:layout_marginEnd="30dp"
        android:background="@drawable/my_edit_bg"
        android:hint="请输入信息"/>

</LinearLayout>

3、所有drawable文件代码

(1)、弹窗形状设计:my_dialog_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="#FFFFFF" />

    <!-- 圆角 -->
    <corners
        android:radius="12dp"/>

</shape>

(2)、编辑框形状设计:my_edit_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="#FFFFFF" />

    <padding
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp" />

    <corners android:radius="2dp" />

    <stroke
        android:width="0.5dp"
        android:color="#888888"
        />

</shape>

4、所有动画效果文件代码

(1)、中间弹窗进入动画:dialog_in_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <scale
        android:duration = "300"
        android:fromXScale="1.2"
        android:toXScale="1.0"
        android:fromYScale="1.2"
        android:toYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"/>

    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

</set>

(2)、中间弹窗消失动画:dialog_out_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <scale
        android:duration="300"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.2"
        android:toYScale="1.2" />

    <alpha
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />

</set>

(3)、底部弹窗进入动画:bottom_dialog_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:fromYDelta="100%"
    android:toYDelta="0" />

(4)、底部弹窗消失动画:bottom_dialog_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:fromYDelta="0"
    android:toYDelta="100%" />

5、使用到的color代码

res/values/colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <!-- 灰色 -->
    <color name="gray">#333333</color>
    <!-- 分割线颜色 -->
    <color name="line">#20888888</color>
    <!-- 蓝色 0099ff-->
    <color name="blue">#1e90ff</color>
    <!-- 黑色 -->
    <color name="black">#000000</color>
    <!-- 红色 -->
    <color name="red">#EE0000</color>
    <!-- 橘黄 -->
    <color name="yellow">#EE7600</color>
    <!-- 绿色 -->
    <color name="green">#458B00</color>

</resources>

6、弹窗样式style代码

res/values/styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <!-- 自定义对话框样式,底部弹窗和中间弹窗共用 -->
    <style name="MyDialogTheme" parent="@android:style/Theme.Dialog">
        <!-- 边框 -->
        <item name="android:windowFrame">@null</item>
        <!-- 是否浮现在activity之上 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 半透明 -->
        <item name="android:windowIsTranslucent">true</item>
        <!-- 无标题 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 背景透明 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 模糊 -->
        <item name="android:backgroundDimEnabled">true</item>
    </style>

    <!-- 自定义的Dialog进出动画 中间弹窗 -->
    <style name="DialogInAndOutAnim">
        <item name="android:windowEnterAnimation">@anim/dialog_in_anim</item>
        <item name="android:windowExitAnimation">@anim/dialog_out_anim</item>
    </style>

    <!-- 自定义Dialog进出动画 底部弹窗 -->
    <style name="BottomDialogInAndOutAnim">
        <item name="android:windowEnterAnimation">@anim/bottom_dialog_in</item>
        <item name="android:windowExitAnimation">@anim/bottom_dialog_out</item>
    </style>

</resources>

7、其他代码

(1)、弹窗中List使用的Adapter:MyAdapter.java

package com.my.dialogdemo;

import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import java.util.List;

public class MyAdapter extends ArrayAdapter<StringItemBean> {

    private int mResourceId;            //资源ID,布局文件
    private List<Integer> mColorsList;  //颜色list
    private boolean mIsHaveColor;       //是否传入了颜色

    private Context mContext;           //上下文

    public MyAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<StringItemBean> objects) {
        super(context, resource, objects);
        mResourceId = resource;
        mContext = context;
    }

    public MyAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<StringItemBean> objects,List<Integer> colors) {
        super(context, resource, objects);
        mResourceId = resource;
        mColorsList = colors;
        mContext = context;
        mIsHaveColor = true;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        //获取当前item的实例
        StringItemBean stringItemBean = getItem(position);

        View view;
        ViewHolder viewHolder;

        if (convertView == null) {    //缓存为空
            //加载布局
            view = LayoutInflater.from(getContext()).inflate(mResourceId, parent, false);
            //只有在缓存为空的情况下,才会创建ViewHolder实例
            viewHolder = new ViewHolder();
            //关联控件
            viewHolder.item = (TextView) view.findViewById(R.id.item);
            //将ViewHolder存储到view中
            view.setTag(viewHolder);
        } else {                    //缓存不为空
            view = convertView;
            //重新获取ViewHolder
            viewHolder = (ViewHolder) view.getTag();
        }

        //设置显示内容
        if (mIsHaveColor){
            viewHolder.item.setText(stringItemBean.getItemStr());
            viewHolder.item.setTextColor(mContext.getResources().getColor(mColorsList.get(position)));
        }else{
            viewHolder.item.setText(stringItemBean.getItemStr());
        }

        return view;
    }

    //内部类ViewHolder
    private class ViewHolder {
        TextView item;
    }

}

(2)、弹窗中List的item的实体类:StringItemBean.java

package com.my.dialogdemo;

public class StringItemBean {

    /**
     * ListView的Item内容
     */
    private String itemStr;

    public StringItemBean(String str){
        this.itemStr = str;
    }

    public String getItemStr() {
        return itemStr;
    }

    public void setItemStr(String itemStr) {
        this.itemStr = itemStr;
    }
}

8、项目结构图

[Android] 仿IOS实现自定义Dialog,底部弹窗和中间弹窗工具

五、具体使用

(1)、主界面布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="中间弹出,有标题,双按钮"/>

    <Button
        android:id="@+id/button_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="中间弹出,无标题,单按钮"/>

    <Button
        android:id="@+id/button_3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="中间弹出,有标题,蓝色List"/>

    <Button
        android:id="@+id/button_4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="中间弹出,无标题,彩色List"/>

    <Button
        android:id="@+id/button_5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="中间弹出,有标题,内容替换为EditText"/>

    <Button
        android:id="@+id/button_6"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="底部弹出,有标题,蓝色List"/>

    <Button
        android:id="@+id/button_7"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="底部弹出,无标题,彩色List"/>

</LinearLayout>

(2)、主界面调用Dialog代码:

package com.my.dialogdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;

import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText mEditText;     //编辑框

    //数据源,数组和List
    private String[] mDataArray = {"我是 item 1", "我是 item 2", "我是 item 3", "我是 item 4"};
    private List<String> mDataList = Arrays.asList(mDataArray);

    //颜色值数组和List
    private Integer[] mColorArray = {R.color.blue,R.color.red,R.color.yellow,R.color.green};
    private List<Integer> mColorsList = Arrays.asList(mColorArray);

    LinearLayout mEditLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //第 1 个按钮
        Button button1 = (Button) findViewById(R.id.button_1);
        button1.setOnClickListener(this);

        //第 2 个按钮
        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(this);

        //第 3 个按钮
        Button button3 = (Button) findViewById(R.id.button_3);
        button3.setOnClickListener(this);

        //第 4 个按钮
        Button button4 = (Button) findViewById(R.id.button_4);
        button4.setOnClickListener(this);

        //第 5 个按钮
        Button button5 = (Button) findViewById(R.id.button_5);
        button5.setOnClickListener(this);

        //第 6 个按钮
        Button button6 = (Button) findViewById(R.id.button_6);
        button6.setOnClickListener(this);

        //第 7 个按钮
        Button button7 = (Button) findViewById(R.id.button_7);
        button7.setOnClickListener(this);

        //引入EditText的布局文件,找到EditText控件
        LayoutInflater editInflater = LayoutInflater.from(this);
        mEditLayout = (LinearLayout) editInflater.inflate(R.layout.edit_layout, null);
        mEditText = (EditText) mEditLayout.findViewById(R.id.editText);
    }

    /**
     * 点击事件
     *
     * @param v 按钮
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            //中间弹出,有标题,双按钮
            case R.id.button_1: {
                new MyDialog(MainActivity.this)
                        .setTitle("标题")
                        .setMessage("中间弹出,有标题,双按钮")
                        .setNegativeButton("取消", new View.OnClickListener() {
                            //点击事件可以设置为null
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "点击了取消",
                                        Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setPositiveButton("确定", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "点击了确定",
                                        Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setCancelable(false)
                        .builder()
                        .show();
                break;
            }
            //中间弹出,无标题,单按钮
            case R.id.button_2: {
                new MyDialog(MainActivity.this)
                        .setCancelable(false)
                        .setMessage("中间弹出,无标题,单按钮")
                        .setPositiveButton("确 定", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "点击了确定",
                                        Toast.LENGTH_SHORT).show();
                            }
                        })
                        .builder()
                        .show();
                break;
            }
            //中间弹出,有标题,蓝色List
            case R.id.button_3: {
                new MyDialog(MainActivity.this)
                        .setTitle("标题,蓝色ListView")
                        .setCancelable(false)
                        .setListView(mDataList, new AdapterView.OnItemClickListener() {
                            @Override
                            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                                Toast.makeText(MainActivity.this, "点击了 " + position, Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setNegativeButton("取 消", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "点击了取消",
                                        Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setNegativeButtonColor(R.color.blue)
                        .builder()
                        .show();
                break;
            }
            //中间弹出,无标题,彩色List
            case R.id.button_4: {
                new MyDialog(MainActivity.this)
                        .setCancelable(false)
                        .setListView(mDataList, mColorArray, new AdapterView.OnItemClickListener() {
                            @Override
                            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                                Toast.makeText(MainActivity.this, "点击了 " + position, Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setNegativeButton("取 消", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "点击了取消",
                                        Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setNegativeButtonColor(R.color.blue)
                        .builder()
                        .show();
                break;
            }
            //中间弹出,有标题,内容替换为EditText
            case R.id.button_5: {
                new MyDialog(MainActivity.this)
                        .setTitle("标题,内容替换为EditText")
                        .setCancelable(false)
                        .setView(mEditLayout)
                        .setNegativeButton("取消", null)
                        .setPositiveButton("确定", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, mEditText.getText().toString(),
                                        Toast.LENGTH_SHORT).show();
                            }
                        })
                        .builder()
                        .show();
                break;
            }
            //底部弹出,有标题,蓝色List
            case R.id.button_6: {
                new MyDialog(MainActivity.this,"BOTTOM")
                        .setBottomTitle("有标题,底部弹窗,蓝色List")
                        .setCancelable(false)
                        .setListView(mDataList, new AdapterView.OnItemClickListener() {
                            @Override
                            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                                Toast.makeText(MainActivity.this, "点击了 " + position, Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setBottomNegativeButton("取 消", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "点击了取消", Toast.LENGTH_SHORT).show();
                            }
                        })
                        .builder()
                        .show();
                break;
            }
            //底部弹出,无标题,彩色List
            case R.id.button_7: {
                new MyDialog(MainActivity.this,"BOTTOM")
                        .setCancelable(false)
                        .setListView(mDataArray, mColorsList, new AdapterView.OnItemClickListener() {
                            @Override
                            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                                Toast.makeText(MainActivity.this, "点击了 "+ position, Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setBottomNegativeButton("取 消", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Toast.makeText(MainActivity.this, "点击了取消", Toast.LENGTH_SHORT).show();
                            }
                        })
                        .builder()
                        .show();
                break;
            }
        }
    }
}

贴出了全部代码,看着确实是有点多。。实际使用真的不多,按照自定义Dialog的步骤,这些代码都是必要的。

1、定义弹窗样式style

2、定义弹窗布局layout

3、设置动画效果anim

4、具体实现核心类

使用是非常简单的,按照anroid中AlertDialog的方式进行链式调用。使用时上去就new就对了。想使用什么就设置什么,如果你不需要标题Title,关于它的调用只字不提即可。如果你不想使用按钮,不写按钮的逻辑就完事了。各种方法的使用在注释中说明的非常清楚,set就完了。如果你还有其他的需求,在Dialog核心类中进行添加就OK了。

六、注意事项

(1)、注意使用中间弹窗和底部弹窗的构造方法

使用弹窗时,若不传入参数"BOTTOM",则是中间弹窗,若传入,就是底部弹窗。

(2)、Cancelable默认为true,也就是说,你不进行设置,点击窗体以外的区域,就会让弹窗消失。只有传入false,他才会起作用。和AlertDialog的使用相同

七、总结

如果你嫌上面的代码太多,太啰嗦,直接copy去用。如果看懂了上面的代码(其实很简单),在进行适当的优化,他就是你自己的了。其实,这也是我第一次使用自定义的Dialog,开始想自定义的时候翻网上的一些文章,看别人是怎么实现的,看了好久都没啥思路,感觉好麻烦啊。不过真正动手写就没有问题了。遇到什么问题,慢慢也就解决了。实践比空想要实际的多。

八、项目源码下载

源码下载地址,不需要积分: 点击下载源码

九、BUG修复

出现了一个BUG,该bug导致:

1、中间弹窗,当内容为文本时,内容长度过长,则内容无法滑动,并且不会显示底部按钮;当内容为List时,List长度过长时,则不会显示底部按钮。

2、底部弹窗,当List过长时,则无法显示底部按钮。

所述BUG已经修复,加入了对List的判断,上面的代码已经同步全部更新。

剩余一个bug,中间弹窗,内容过长时,无法显示底部按钮。只有内容填充弹窗后高度大于屏幕的高度时,才会出现,一般不是特别长的内容,都不会出现该问题。


原创文章,转载请注明出处:https://blog.csdn.net/Lone1yCode/article/details/79927873