天天看點

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

  • Dialog :Builder模式建立
    • Dialog常用的方法
    • setButton(…)
    • dialog消失的2種方法的差別!
    • Dialog效果圖
    • AlertDialog:基本對話框
      • 效果圖:
      • 相關的類
      • Builder的相關的方法
      • 代碼:
      • 注意:
    • Dialog添加清單
    • AlertDialog:單選對話框
      • 效果圖:
      • 相關的方法
      • 代碼:
    • AlertDialog多選對話框
      • 效果圖:
      • Builder的相關的方法
      • 點開dialog顯示上一次退出時選中的按鈕
      • 代碼:
    • ProgressDialog:進度條對話框
      • 效果圖:
      • 相關的方法
      • 設定進度條:
      • 代碼:
    • 自定義Dialog
      • 效果圖:
      • 相關
      • 代碼:
    • 自定義Dialog:加 動畫 + 設定寬高 + style
      • 效果圖:
      • 相關
      • 設定寬 + 高
      • 添加動畫
      • 代碼:
  • Dialog:構造方法建立
    • ProgressDialog
    • DatePickerDialog
      • DatePickerDialog 不重寫setButton()
        • 效果圖
        • 代碼
      • DatePickerDialog 重寫setButton()
        • 效果圖
        • 代碼
    • TimePickerDialog
      • TimePickDialog:不重寫setButton()
        • 效果圖
        • 代碼
      • TimePickDialog:重寫setButton()
        • 效果圖
        • 代碼
    • 其它
  • DialogFragment
    • 建立dialog
    • 顯示dialog
    • Demo
      • DialogFragment01
      • DialogFragment02
      • DialogFragment03
    • 使用DialogFragment怎麼把value傳給Activity?
  • 仿ios透明加載框
      • 效果圖
      • 工具類
      • WindowManager.LayoutParams.FLAG_DIM_BEHIND
    • 二:采用了幀動畫
      • 需要複制的内容
      • progress_drawable_list.xml 幀動畫
      • ProgressDialogUtil2
  • 系統級的Dialog
    • 效果圖
    • 權限+Type
    • 其它
  • 注意
    • dialog的Context不能使用getApplicationContext()
    • dialog.setCanceledOnTouchOutside(false)無效

參考:

Android API 指南:Dialog: https://developer.android.google.cn/guide/topics/ui/dialogs.html#ShowingADialog

Dialog :Builder模式建立

dialog的監聽可以為null,按“确定”、“取消”仍然有效。

對話框分類 含義
Dialog 基類:非抽象
AlertDialog 提醒對話框
ProgressDialog 進度條對話框

Dialog背景色是黑色,這是因為style的原因:

這些對話框都繼承自Dialog,API18:

見圖:

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

Dialog常用的方法

方法 含義
setContentView(View or resId) 填充布局
findViewById(resId) 找到布局中的控件,可以用dialog調用
setTitle(character char) 設定比提提
setIcon(resId) 設定圖示
show() 顯示
dismiss() 消失:從螢幕中移除
hide() 隐藏
isShow() dialog是否正在顯示
getWindow() 得到目前dialog所在的activity的窗體
類Dialog是沒有方法:setMessage(charseQuence char),但是子類AlertDialog + ProgressDialog有此方法。

setButton(…)

dialog.setButton(…)

dialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", dialog);
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, "中立", dialog);
           
dialog.setButton("自定義Button:确定", dialog);
dialog.setButton2("自定義Button:取消", dialog);
           

builder.setPositiveButton(…)

builder.setTitle("選擇時間")
 .setCancelable(false)
 .setIcon(android.R.drawable.ic_dialog_info)
 .setSingleChoiceItems(times, , new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
         //
     }
 })
 .setPositiveButton("确定", new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
         //
     }
 })

 .setNegativeButton("選擇日期", new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
         //
     }
 });
           

dialog消失的2種方法的差別!

setCancelable(boolean flag) :點選back鍵dialog是否消失
setCanceledOnTouchOutside(boolean cancel) : 點選dialog意外的區域dialog是否消失
           

見developer

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

Dialog效果圖

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

AlertDialog:基本對話框

繼承自Dialog,預設顯示在螢幕中間,左右兩邊距離螢幕有間隔。

效果圖:

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

相關的類

含義
AlertDialog 提醒對話框
AlertDialog.Builder 對話框構造器

Builder的相關的方法

方法 含義
setPositiviButton(String ,DialogInterface.onClickListener(..)) 設定确定按鈕
setNogetiveButton(String ,DialogInterface.onClickListener(..)) 設定取消按鈕
setMessage(charseQuence char) 設定dialog内容
crete() 建立dialog對象

代碼:

// 普通對話框
private void initAlertDialog() {
    Builder builder = new AlertDialog.Builder(context);
    builder.setTitle("更新提示");
    builder.setMessage("這是知乎最新版本,請更新!");
    builder.setIcon(R.drawable.ic_launcher);
    builder.setPositiveButton("取消", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            ToastUtil.showShortToast(context, "确定" + which);
            // dialog.dismiss();//可以不調用dismiss(),dialog會自動消失
        }
    });
    builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            ToastUtil.showShortToast(context, "取消" + which);
            // dialog.dismiss();可以不調用dismiss(),dialog會自動消失
        }
    });
    AlertDialog dialog = builder.create();
    dialog.show();
}
           

注意:

AlertDialog的方法setNegativeButton(CharSequence text, OnClickListener listener) + setPositiveButton(CharSequence text, OnClickListener listener) + setPositiveButton(CharSequence text, OnClickListener listener) 會自動調用dialog的dismiss(),除此之外均如果需要讓dialog消失,都必須調用dismiss().

設定單選對話框和多選對話框時,不能調用方法setMessage(charseQuence char),否則選擇清單不會顯示。

Dialog添加清單

可通過 AlertDialog API 提供三種清單:

  • 傳統單選清單
  • 永久性單選清單(單選按鈕)
  • 永久性多選清單(複選框)

checkedItem:預設選中的position。-1表示預設不選中任何一個。

.setSingleChoiceItems(provinces, -, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
       //which表示選中的item在items中的角标
    }
})
           
AlertDialog dialog = new AlertDialog.Builder(this)
    .setTitle("Title")
    .setIcon(R.mipmap.ic_launcher_round)
    .setSingleChoiceItems(provinces, -, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.d(TAG, "singleChoice,which=" + which);
        }
    })
    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.d(TAG, "Positive,which=" + which);
        }
    })
    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.d(TAG, "Negative,which=" + which);
        }
    })
    .create();
dialog.show();
           

AlertDialog:單選對話框

效果圖:

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

相關的方法

含義
setSingleChoiceItems(CharSequence[] items, int checkedItem, OnClickListener listener) 設定單選對話框
items 所有選項
checkedItem 預設選中哪一個,-1:預設都沒選

代碼:

private void initSingleChoiceDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setTitle("标題");
    // builder.setMessage("message--message");//設定message就沒有了單選清單
    builder.setIcon(R.drawable.ic_launcher);
    final String[] items = new String[] { "item1", "item2", "item3", "item4", "item5" };
    final boolean[] checkedItem = new boolean[]{false,false,false,false,false};
    builder.setSingleChoiceItems(items, -,
            new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    checkedItem[which] = true;
                    ToastUtil.showShortToast(context, items[which]);
                    dialog.dismiss();// 點選單選按鈕,dialog不會自動消失
                }
            });
    AlertDialog dialog = builder.create();
    dialog.show();
}
           

AlertDialog多選對話框

效果圖:

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

Builder的相關的方法

方法 含義
setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, OnMultiChoiceClickListener listener) 多選方法
參數 含義
items 多選清單的内容
checkedItems ,預設選中的内容

點開dialog顯示上一次退出時選中的按鈕

把checkedItems 的建立放在類中,作為類變量。

代碼:

private void initMultiChoiceDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setTitle("Title");
    // builder.setMessage("message--message");//設定message就沒有了單選清單
    builder.setIcon(R.drawable.ic_launcher);
    items = new String[] { "item1", "item2", "item3", "item4", "item5" };
    final boolean[] checkedItems = new boolean[] { false, false, false,
            false, false };
    builder.setMultiChoiceItems(items, checkedItems,
            new DialogInterface.OnMultiChoiceClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which,
                        boolean isChecked) {
                    ToastUtil.showShortToast(context, items[which]);
                }
            });
    builder.setPositiveButton("取消", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            ToastUtil.showShortToast(context, "取消");
            // dialog.dismiss();//可以不調用dismiss(),dialog會自動消失
        }
    });
    builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            StringBuffer sb = new StringBuffer();
            for (int i = ; i < checkedItems.length; i++) {
                if (checkedItems[i]) {
                    sb.append(items[i]);
                }
            }
            ToastUtil.showShortToast(context, "确定" + sb.toString());
            // dialog.dismiss();可以不調用dismiss(),dialog會自動消失
        }
    });
    AlertDialog dialog = builder.create();
    dialog.show();
}
           

如何獲選中的資料?

除了周遊

boolean[] checkedItems

外,還可以建立一個List,選中時添加到List,取消後從List中清除

ArrayList<String> selectedList = new ArrayList<>();
           
selectedList.clear();

builder.setMultiChoiceItems(provinces, null, new DialogInterface.OnMultiChoiceClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
        Log.d(TAG, "MultiChoice,which=" + which + ",isChecked=" + isChecked);
        if (isChecked) {
            selectedList.add(provinces[which]);
        } else if (selectedList.contains(provinces[which])) {
            selectedList.remove(provinces[which]);
        }
    }
})
           

ProgressDialog:進度條對話框

分為線性和圓形,沒有Builder.

效果圖:

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意
Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

相關的方法

含義
setProgressStyle(int style) 設定進度條樣式
setMax(int max) 進度最大值
setProgress(int value) 設定目前進度

設定進度條:

dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 水準線進度條
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 圓形進度條
           

代碼:

private void initProgressDialog() {
    final ProgressDialog dialog = new ProgressDialog(context);
    dialog.setTitle("Title");//設定标題
    dialog.setMessage("message----message");//設定dialog内容
    dialog.setIcon(R.drawable.ic_launcher);//設定圖示,與為Title左側
    dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 水準線進度條
    // dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//圓形進度條
    dialog.setMax();//最大值
    new Thread() {
        public void run() {
            for (int i = ; i <= ; i++) {
                SystemClock.sleep();
                dialog.setProgress(i);//每隔50毫秒設定目前進度
            }
            dialog.dismiss();// for執行完成後dialog預設不消失
        };
    }.start();
    dialog.show();
}
           

自定義Dialog

需要自己設定布局

效果圖:

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

相關

含義
window 窗體
方法 含義
setGravity(int gravity) 設定窗體位置
含義
Dialog
方法 含義
requestWindowFeature(int featureId) 窗體的title是否顯示

代碼:

private void initCustomDialog() {
    final Dialog dialog = new Dialog(context);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉dialog的title,放在設定布局前
    dialog.setContentView(R.layout.custom_dialog);

    dialog.getWindow().setGravity(Gravity.BOTTOM);

    Button btn_ok = (Button) dialog.findViewById(R.id.btn_ok);
    Button btn_cancle = (Button) dialog.findViewById(R.id.btn_cancle);

    btn_ok.setOnClickListener(new Button.OnClickListener() {

        @Override
        public void onClick(View v) {
            dialog.dismiss();
        }
    });
    btn_cancle.setOnClickListener(new Button.OnClickListener() {

        @Override
        public void onClick(View v) {
            dialog.dismiss();
        }
    });
    dialog.show();
}
           

自定義Dialog:加 動畫 + 設定寬高 + style

效果圖:

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

相關

類:Window

方法 含義
方法 含義
setGravity(int gravity) 設定窗體位置
getAttributes() 擷取目前窗體的參數
setAttributes(LayoutParams a) 設定窗體寬高
setWindowAnimations(int resId) 給窗體添加動畫

類:Dialog

方法 含義
requestWindowFeature(int featureId) 窗體的title是否顯示
setCanceledOnTouchOutside(boolean cancel) 點選dialog意外的區域,dialog是否消失

設定寬 + 高

//設定 寬 + 高
LayoutParams params = window.getAttributes();//擷取目前窗體的參數
view.measure(, );
params.width = getResources().getDisplayMetrics().widthPixels;
params.height = view.getMeasuredHeight();//不設定高的話,dialog會充滿螢幕,下方是白色,即使在布局中設定了高的具體值

window.setAttributes(params);
           

添加動畫

DialogAnimationStyle:

<style name="DialogAnimationStyle" parent="android:Animation">
    <item name="android:windowEnterAnimation">@anim/dialog_enter</item>
    <item name="android:windowExitAnimation">@anim/dialog_exit</item>
</style>
           

dialog_enter.xml:

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

dialog_exit.xml

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

MyStyle.xml

<style name="MyStyle">
    <item name="android:windowNoTitle">true</item>
    <item name="android:backgroundDimEnabled">true</item>
</style>
           

代碼:

private void initCustomDialog2() {
    final Dialog dialog = new Dialog(context , R.style.MyStyle);//去掉dialog的title,dialog區域外是灰色
//      dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉dialog的title,放在設定布局前
    View view = View.inflate(context, R.layout.custom_dialog2, null);
    dialog.setContentView(view);
    dialog.setCanceledOnTouchOutside(true);//點選dialog意外的區域,dialog是否消失

    Window window = dialog.getWindow();//建立目前窗體
    window.setGravity(Gravity.BOTTOM);//目前床底位于底部

    //添加動畫
    window.setWindowAnimations(R.style.DialogAnimationStyle);

    //設定 寬 + 高
    LayoutParams params = window.getAttributes();//擷取目前窗體的參數
    view.measure(, );
    params.width = getResources().getDisplayMetrics().widthPixels;
    params.height = view.getMeasuredHeight();//不設定高的話,dialog會充滿螢幕,下方是白色,即使在布局中設定了高的具體值

    window.setAttributes(params);

    Button btn_camera  = (Button) dialog.findViewById(R.id.btn_camera);
    Button btn_gallery  = (Button) dialog.findViewById(R.id.btn_gallery);
    Button btn6_cancle  = (Button) dialog.findViewById(R.id.btn6_cancle);

    btn_camera.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            ToastUtil.showShortToast(context, "btn_camera");
            dialog.dismiss();
        }
    });

    btn_gallery.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            ToastUtil.showShortToast(context, "btn_gallery");
            dialog.dismiss();
        }
    });

    btn6_cancle.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            ToastUtil.showShortToast(context, "btn6_cancle");
            dialog.dismiss();
        }
    });

    dialog.show();//顯示dialog
}
           
源碼:https://github.com/s1168805219/DialogDemo

再魅族手機中,虛拟按鍵會遮擋bottomDialog的下方,解決的方法是在設定window的高度是加上虛拟鍵的高度

public class VirtualHeightUtil {


    public static int getDpi(Activity activity) {
        Display display = activity.getWindowManager().getDefaultDisplay();
        DisplayMetrics dm = new DisplayMetrics();
        int height = ;
        @SuppressWarnings("rawtypes")
        Class c;
        try {
            c = Class.forName("android.view.Display");
            @SuppressWarnings("unchecked")
            Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
            method.invoke(display, dm);
            height = dm.heightPixels;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return height;
    }

    public static int[] getScreenWH(Context poCotext) {
        WindowManager wm = (WindowManager) poCotext.getSystemService(Context.WINDOW_SERVICE);
        if (wm == null) {
            return new int[]{, };
        } else {
            int width = wm.getDefaultDisplay().getWidth();
            int height = wm.getDefaultDisplay().getHeight();
            return new int[]{width, height};
        }
    }

    /**
     * 擷取魅族手機的虛拟鍵高度
     * @param poCotext
     * @return
     */
    public static int getVirtualBtnHeight(Context poCotext) {
        int location[] = getScreenWH(poCotext);
        int realHeiht = getDpi((Activity) poCotext);
        int virtualHeight = realHeiht - location[];
        return virtualHeight;
    }

}
           

Dialog:構造方法建立

我們知道設定模式有建構者模式,也就是Builder模式,上面我們建立Dialog就是這麼做的。其實采用構造方法也可以建立Dialog。

比如:

Dialog

ProgressDialog

DatePickerDialog

TimePickerDialog

都可以采用構造方法建立dialog,但是

AlertDialog

不可以。

其中:

DatePickerDialog

TimePickerDialog

也可以使用fragment來顯示,見:Android_UI:Date & Time元件(下)

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意
Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意
Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意
Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意
Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意
Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

ProgressDialog

見上面

DatePickerDialog

**注意:**DatePickerDialog和TimePickerDialog 都有方法

setButton(...)

,當我們重寫該方法後,那麼監聽

OnDateSetListener

OnTimeSetListener

就無效了,不會走這2個監聽,下面在重寫

setButton()

中會有說明

DatePickerDialog 不重寫setButton()

效果圖

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

代碼

Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(context, onDateSetListener, year, month, dayOfMonth);

datePickerDialog.setCanceledOnTouchOutside(false);
datePickerDialog.setCancelable(false);
datePickerDialog.show();
           

DatePickerDialog 重寫setButton()

重寫

setButton()

, 通過

getDatePicker()

擷取到

DatePicker

對象,進而擷取到year+month+day,是以不需要

OnDateSetListener

注意:

TimePickDialog

确沒有相似的方法

getTimePicker()

,是以需要

OnTimeSetListener

重寫

setButton(...)

後,監聽

OnDateSetListener

OnTimeSetListener

就無效了。是以如果重寫剛方法,那麼不需要寫listener,直接傳null。

dialog預設有2個Button,如果我們隻重寫了一個

setButton(...)

,那麼另一個“确定”/“取消”也會顯示出來,那麼怎麼不讓它顯示出來呢,還是不設定為 “”,會顯示預設文字
dialog.setButton2("", new DialogInterface.OnClickListener() {
     @Override
      public void onClick(DialogInterface dialog, int which) {
         //不寫
      }
});
           

但是不能是:

dialog.setButton2("",null);
           

效果圖

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

代碼

Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
MyOnDateSetListener onDateSetListener = new MyOnDateSetListener();
//可以不傳參數OnDateSetListener, 第2個參數: int themeResId, 第三個參數:OnDateSetListener
final DatePickerDialog dialog = new DatePickerDialog(context, , null, year, month, day);

dialog.setButton("自定義Button:确定", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog2, int which) {
        DatePicker datePicker = dialog.getDatePicker();
        int year = datePicker.getYear();
        int month = datePicker.getMonth() + ;
        int dayOfMonth = datePicker.getDayOfMonth();
        Log.d(TAG, "日期:" + year + "年" + month + "月" + dayOfMonth + "日");
    }
});
dialog.setButton2("自定義Button:取消", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Log.d(TAG, "取消" + ",which=" + which);
    }
});
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
           

TimePickerDialog

TimePickDialog:不重寫setButton()

效果圖

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

代碼

Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
MyOnTimeSetListener timeSetListener = new MyOnTimeSetListener();

TimePickerDialog dialog = new TimePickerDialog(context, timeSetListener, hour, minute, true);
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
           

TimePickDialog:重寫setButton()

效果圖

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

代碼

DatePickerDialog

通過方法

getDatePicker()

擷取

DatePicker

對象,今兒擷取year+month+day,但是

TimePickDialog

沒有方法

getTimePicker()

,是以我們不能像DatePickerDialog那樣擷取hour+minute,那麼該怎麼做呢,就是修改

SetButton()

的第二個參數,不傳

OnClickListener

,直接傳入

TimePickDialog

對象。

Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
MyOnTimeSetListener timeSetListener = new MyOnTimeSetListener();
TimePickerDialog dialog = new TimePickerDialog(context, timeSetListener, hour, minute, true);
//有效方法,第2個參數不傳OnClickListener,直接傳入dialog本身
dialog.setButton("自定義Button:确定", dialog);
dialog.setButton2("自定義Button:取消", dialog);
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
           

MyOnTimeSetListener:

private class MyOnTimeSetListener implements TimePickerDialog.OnTimeSetListener {
    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        Log.d(TAG, "時間:" + hourOfDay + "時" + minute + "分");
    }
}
           

其它

Demo: http://git.oschina.net/AndroidUI/DatePickerDialogTimePickerDialog

參考:

Android程式設計之TimePickerDialog設定确定鍵導緻OnTimeSetListener不響應問題

Android:Picker(DatePicker、TimerPicker、NumberPicker)

重寫DatePickerDialog 解決OnDateSetListener隻有完成,沒有取消回調問題

DialogFragment

自定義類繼承

DialogFragment

,重寫

onCreateDialog()

或者

onCreateView()

建立dialog

第一種:

onCreateDialog()

中建立

dialog

第二種:

onCreateDialog()

中建立

dialog

第三種:在

onCreateView()

中自定義

view

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.frag_dialog_3, container, false);
    return rootView;
}
           

顯示dialog

DialogFragment01 frag = new DialogFragment01();
frag.show(getSupportFragmentManager(), "frag");
           

Demo

DialogFragment01

public class DialogFragment01 extends DialogFragment implements View.OnClickListener {

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.setTitle("Title");
        dialog.setContentView(R.layout.frag_dialog_3);
        dialog.setCanceledOnTouchOutside(false);
        dialog.setCancelable(false);

        TextView tv1 = dialog.findViewById(R.id.tv1);
        TextView tv2 = dialog.findViewById(R.id.tv2);
        tv1.setOnClickListener(this);
        tv2.setOnClickListener(this);
        return dialog;
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.tv1:
                Toast.makeText(getActivity(), "tv1", Toast.LENGTH_SHORT).show();
                break;
            case R.id.tv2:
                Toast.makeText(getActivity(), "tv2", Toast.LENGTH_SHORT).show();
                break;
        }
    }
}
           

DialogFragment02

public class DialogFragment02 extends DialogFragment {

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog dialog = new AlertDialog.Builder(getActivity())
                .setTitle("Title")
                .setMessage("message")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                    }
                })
                .setCancelable(false)
                .create();
        dialog.setCanceledOnTouchOutside(false);
        return dialog;
    }
}
           

DialogFragment03

public class DialogFragment03 extends DialogFragment {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NO_TITLE,);//去掉dialog的Title,也可以使用style
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.frag_dialog_3, container, false);
        return rootView;
    }
}
           

Demo:https://git.oschina.net/AndroidUI/dialogfragment01.git

使用DialogFragment怎麼把value傳給Activity?

采用的接口的方式,讓Activity實作給接口,把DialogFragment對象返給Activity

public class NoticeDialogFragment extends DialogFragment {

    private static final String TAG = "Fragment";
    private String[] provinces;
    public String province="京";//預設

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        provinces = ((MainActivity) getActivity()).provinces;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
                .setTitle(R.string.app_name)
                .setSingleChoiceItems(provinces, -, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        province = provinces[which];
                    }
                })
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        mListener.onDialogPositiveClick(NoticeDialogFragment.this);
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        mListener.onDialogNegativeClick(NoticeDialogFragment.this);
                    }
                });
        return builder.create();
    }


    interface DialogListener {
        void onDialogPositiveClick(DialogFragment dialog);

        void onDialogNegativeClick(DialogFragment dialog);
    }

    DialogListener mListener;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // Verify that the host activity implements the callback interface
        try {
            // Instantiate the NoticeDialogListener so we can send events to the host
            mListener = (DialogListener) context;
        } catch (ClassCastException e) {
            // The activity doesn't implement the interface, throw exception
            throw new ClassCastException(context.toString()
                    + " must implement NoticeDialogListener");
        }
    }
}
           
@Override
public void onDialogPositiveClick(DialogFragment dialog) {
    Log.d(TAG, ((NoticeDialogFragment)dialog).province);
}

@Override
public void onDialogNegativeClick(DialogFragment dialog) {

}
           

仿ios透明加載框

效果圖

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

工具類

為了友善以後使用,寫成工具類。

public class ProgressDialogUtil {

    private static Dialog mDialog;
    private static ProgressDialogUtil dialogUtil;

    private ProgressDialogUtil() {
        super();
    }

    public static ProgressDialogUtil getInstance(Context context) {
        if (mDialog == null) {
            dialogUtil = new ProgressDialogUtil();
            AlertDialog.Builder mBuilder = new AlertDialog.Builder(context, R.style.full_screen_dialog);
            View view = LayoutInflater.from(context).inflate(R.layout.custom_progress_dialog_2, null);
            mBuilder.setView(view);
            mBuilder.setCancelable(true);

            mDialog = mBuilder.create();
            mDialog.setCanceledOnTouchOutside(false);

            Window win = mDialog.getWindow();
            //顯示對話框時,後面的Activity不變暗,可選操作。
            win.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

            //擷取對話框目前的參數值,下面代碼不加也可以
//            WindowManager.LayoutParams params = win.getAttributes();
//            params.gravity = Gravity.CENTER;
//            win.setAttributes(params);
        }
        return dialogUtil;
    }

    public void showProgressDialog() {
        if (!mDialog.isShowing()) {
            mDialog.show();
        }
    }

    public void dismissProgressDialog() {
        if (mDialog.isShowing()) {
            mDialog.dismiss();
        }
    }
}
           

**R.style.full_screen_dialog**

<style name="full_screen_dialog">
    <item name="android:windowFrame">@null</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
    <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
</style>
           

**R.layout.custom_dialog**

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:background="#78909C"
    android:padding="5dp"
    android:orientation="horizontal">


    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="加載中..."
        android:layout_marginLeft="5dp"
        android:textSize="16sp"/>
</LinearLayout>
           

custom_progress_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="#80000000" />
    <corners android:radius="8dip" />

</shape>
           

顯示和隐藏

ProgressDialogUtil.getInstance(context).showProgressDialog();
ProgressDialogUtil.getInstance(context).dismissProgressDialog();
           

WindowManager.LayoutParams.FLAG_DIM_BEHIND

當使用系統的progressDialog時,目前的activity會變暗,這是因為預設的

WindowManager.LayoutParams.FLAG_DIM_BEHIND

,DIM是

dimmed

的縮寫,是變暗的意思

二:采用了幀動畫

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

需要複制的内容

下載下傳Demo複制

  • mipmap中的12張圖檔
  • drawable中2個檔案,

    progress_drawable_list.xml

    custom_progress_dialog_bg.xml

  • dialog的自定義布局
  • color
  • style
  • ProgressDialogUtil2

progress_drawable_list.xml 幀動畫

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@mipmap/app_loading_001"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_002"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_003"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_004"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_005"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_006"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_007"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_008"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_009"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_0010"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_0011"
        android:duration="100"/>
    <item
        android:drawable="@mipmap/app_loading_0012"
        android:duration="100"/>
</animation-list>
           

ProgressDialogUtil2

public class ProgressDialogUtil2 {
    private static ProgressDialogUtil2 instance = null;
    private static Dialog dialog;
    private static View view;
    private TextView tv;

    public synchronized static ProgressDialogUtil2 getInstance(Context context) {

        if (instance == null) {
            instance = new ProgressDialogUtil2();
            dialog = new Dialog(context, R.style.CustomDialogStyle);
            view = LayoutInflater.from(context).inflate(R.layout.custom_progress_dialog_1, null);
            dialog.setContentView(view);

            ImageView progressImageView = (ImageView) view.findViewById(R.id.iv_loading);
            AnimationDrawable animationDrawable = (AnimationDrawable) progressImageView.getDrawable();
            animationDrawable.start();

            //要放在動畫後面,否則無效
            dialog.setCanceledOnTouchOutside(false);
        }
        return instance;
    }

    public void show() {
        dialog.show();
    }

    public void showstr(String str) {
        if (tv == null) {
            tv = (TextView) view.findViewById(R.id.tv_loading);
            tv.setText(str);
        } else {
            tv.setText(str);
        }
        dialog.show();
    }

    public void cancle() {
        if (dialog == null) {
            return;
        } else {
            dialog.cancel();
        }
    }
}
           

顯示和隐藏

ProgressDialogUtil2.getInstance(context).show();
ProgressDialogUtil2.getInstance(context).cancle();
           

Demo: http://git.oschina.net/AndroidUI/customdialog01

系統級的Dialog

我們都知道dialog是依賴activity而存在的,但是系統級的Dialog不依賴Activity,是以當按下Button的同時,我們彈出此Dialog,同時進入MainActivity2頁面,這是會發現,在activity的切換過程中,Dialog一直都存在。

效果圖

Android_UI:DialogDialog :Builder模式建立Dialog:構造方法建立DialogFragment仿ios透明加載框系統級的Dialog注意

權限+Type

需要權限:

需要設定

TYPE_SYSTEM_ALERT

設定完type後,在360、小米、魅族手機上

dialog

仍然不顯示,這是因為廠家對系統走了修改,解決方方法是在設定

TYPE_TOAST

下面來自android不用context彈dialog

無意中用了一個4.0系統(<19)的手機測試了一下,dialog能彈出來,但是界面裡面的button根本不能點選!這就尴尬了!經過一番資料的查找問題終于找到了:

1.WindowManager.LayoutParams.TYPE_TOAST僅在 API level >= 19 時可以正常顯示,API level 19 以下因無法接收無法接收觸摸(點選)和按鍵事件!

2.API level 19 後做了調整,當我們使用 TYPE_TOAST, Android 會偷偷給我們加上 FLAG_NOT_FOCUSABLE 和 FLAG_NOT_TOUCHABLE , 4.0.1 開始, 會額外再去掉FLAG_WATCH_OUTSIDE_TOUCH。 這樣真的是什麼事件都沒了。

3.對于 API level < 19 的機器(MIUI除外),想要達到目的,需要:

a.要有 android.permission.SYSTEM_ALERT_WINDOW 權限

b.将 type 設定為 WindowManager.LayoutParams.TYPE_PHONE 或者 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    //解決Android 起不能再用Toast的問題(先解決crash)
    if(Build.VERSION.SDK_INT > ){
        md.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
    }else{
        md.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
    }
} else {
    md.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
}
           

其它

參考:android不用context彈dialog

Demo:https://git.oschina.net/AndroidUI/buglyupdate01

注意

dialog的Context不能使用

getApplicationContext()

dialog

中不能使用

getApplicationContext()

,會報錯。因為

dialog

是依附于

activity

而存在的。

dialog.setCanceledOnTouchOutside(false)無效

原因:

1. 在dialog.show()之前調用無效

2. 自定義的dialog有動畫

animation-list

也會導緻其無效

解決方法:

在show()後面

dialog.show();
dialog.setCanceledOnTouchOutside(false);
           

在動畫後面

AnimationDrawable animationDrawable = (AnimationDrawable) progressImageView.getDrawable();
animationDrawable.start();
dialog.setCanceledOnTouchOutside(false);