1. 程式人生 > >[Android] 仿IOS實現自定義Dialog,底部彈窗和中間彈窗工具

[Android] 仿IOS實現自定義Dialog,底部彈窗和中間彈窗工具

用過Android的預設對話方塊的都懂,不管是哪個版本的對話方塊,都醜到爆!就算是Google推崇的Material Design風格的彈窗一樣不好看,基本每款APP都不會去使用預設的對話方塊樣式,他們都有自己的風格,怎樣去改變預設的對話方塊樣式呢?只能自定義了,將系統對話方塊改為自己喜歡或者是APP特有風格的樣式。本文將介紹如何去實現自定義Dialog,仿IOS,並新增動畫效果,並提供豐富的方法呼叫,讓開發者可以在已有樣式的基礎上進行進一步的細節改變。算是一個工具類了,直接copy就可以直接用了。

一、舉例

這是Android 4.2版本的彈窗:


這是Android 7.0版本的彈窗:


我是沒有覺得很好看。大概這就是程式設計師的審美吧。

下面再看一下IOS的對話方塊,話說找這個對話方塊太難了。我找了好久好久,都找不到有什麼地方能彈窗,不找的時候一直有。還好不負所望,找了倆。中間彈窗對話方塊:


IOS底部彈窗:


是不是感覺還不錯!Android的系統對話方塊雖然樣式很醜,但畢竟是開源系統,它可以輕鬆實現對話方塊樣式的自定義,而且Android的對話方塊的樣式基本一個APP就一個樣,種類繁多,樣式豐富。

二、實現效果

經過自定義後,現在的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、專案結構圖

五、具體使用

(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過長時,則無法顯示底部按鈕。