Android入門——AlertDialog、ProgressDialog及自定義Dialog總結


引言

在我們程序開發中,用戶體驗始終是一項十分重要的指標,通常為了良好的用戶體驗,在確認一些敏感或者數據操作更新之前允許客戶反悔即讓用戶擁有更多的自主性,而Android開發中是借助對話框Dialog系、Popupwindow和Dialog樣式的Activity來實現。

一、Dialog及其衍生類

Android里Dialog作為對話框系的基類,我們一般不會直接去使用Dialog而是使用他的子類,比如說AlertDialog, DatePickerDialog, ProgressDialog, TimePickerDialog,CharacterPickerDialog,MediaRouteChooserDialog, MediaRouteControllerDialog, Presentation,其中前四者使用比較頻繁,使用方法也大同小異,接下來就以AlertDialog為例總結下。

1、AlertDialog

1.1、AlertDialog的部分源碼結構

AlertDialog 其實也是采用了建造者模式,AlertDialog是我們最終想要生產得到的產品,但是我們不能直接通過它的構造方法來new,同時我們看到AlertDialog里有一個內部類Builder,Builder內部類里封裝了一系列的方法用於初始化,然后再通過Builder內部類里有一個create方法返回Dialog

public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
protected AlertDialog(Context context) {
this(context, 0);
}//請注意AlertDialog的構造方法是protected
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
this(context, 0);
setCancelable(cancelable);
setOnCancelListener(cancelListener);
}
...
protected AlertDialog(Context context, @StyleRes int themeResId) {
this(context, themeResId, true);
}
public static class Builder {
private final AlertController.AlertParams P;
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setIcon(Drawable icon) {
P.mIcon = icon;
return this;
}
/**
* @param context the parent context
*
*/

public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
...
public AlertDialog create() {
// Context has already been wrapped with the appropriate theme.
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
}
}

1.2、使用系統AlertDialog

我們都知道Android中的所有的View,首先是一個class,要使用一個class我們首先得先得到他的對象(初學的時候照着教材敲了彈出對話框的窗口,但是對於為什么是用builder而不是直接new一無所知,曾經困惑了蠻久),然后進行一系列的初始化,最后再顯示。步驟簡記:一系列初始化Builder——>create得到Dialog對象——>顯示

1.2.1、setMessage一般對話框

private void showDialog(){
/**需要注意的是構造AlertDialog.Builder對象時傳入的參數可以理解成*說依附的父容器,比如說在Activity上顯示就傳入this,在Fragment上顯示就傳入*Fragment的父級即getActivity()至於是否都是父級的,我還得需要測試下,比如說嵌套Fragment的,測試完畢之后再行更新!!!!
*/

AlertDialog.Builder builder= new AlertDialog.Builder(this);//得到Builder對象

/*一系列初始化工作*/
builder.setIcon(R.mipmap.bcg)
.setTitle(R.string.dialog_title)
.setMessage(R.string.dialog_msg)
.setPositiveButton(R.string.dialog_btn_positive,new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogActivity.this,"Yes",Toast.LENGTH_LONG).show();
}
})
.setNegativeButton(R.string.dialog_btn_negative, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogActivity.this,"No",Toast.LENGTH_LONG).show();
}
})
.create()/*得到dialog*/
.show();/*居中顯示於Activity*/
}

這里寫圖片描述
也可以把監聽器單獨封裝成一個類

 class DialogBtnClicklistener implements DialogInterface.OnClickListener{
@Override
public void onClick(DialogInterface dialog, int which){
switch(which){
case Dialog.BUTTON_POSITIVE
case Dialog.BUTTON_NEGATIVE
...
}
}
}

1.2.2、setItems列表對話框

 private void showDialog(){
final String items[]={"Dota2","Dota","War3"};
AlertDialog.Builder builder= new AlertDialog.Builder(this);//得到DIalog對象
builder.setIcon(R.mipmap.bcg)
.setTitle(R.string.dialog_title)
.setItems(items, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogActivity.this, items[which], Toast.LENGTH_LONG).show();
}
})
.create()
.show();
}

這里寫圖片描述

1.2.3 setSingleChoiceItems單選、setMultiChoiceItems多選對話框

.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(DialogActivity.this, items[which], Toast.LENGTH_LONG).show();
}
})

這里寫圖片描述

    private void showDialog(){
//final String items[]={"Dota2","Dota","War3"};
final String[] items = getResources().getStringArray(R.array.items);
final boolean selected[]={true,false,true};
AlertDialog.Builder builder= new AlertDialog.Builder(this);//得到DIalog對象
builder.setIcon(R.mipmap.bcg)
.setTitle(R.string.dialog_title)
/*selected是默認的對應的選中狀態。當你選擇時,系統會自動幫你把selected中的值做相應改變,所以在勾選框中可以得到所有的選擇狀態。*/
.setMultiChoiceItems(items, selected, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
Toast.makeText(DialogActivity.this, items[which]+isChecked, Toast.LENGTH_LONG).show();
}
})
.create()
.show();
}

這里寫圖片描述

1.3、setView顯示自定義Dialog

先定義Dialog需要顯示的界面布局文件,再通過 View view = LayoutInflater.from(DialogActivity.this).inflate(R.layout.dialog_main, null)把布局文件加載進來,得到一個View對象,然后通過 AlertDialog.Builder 的setView方法來設置,最后還可以通過Window對象調整對話框的大小、透明度等等。

private void showCustomDialog(){
AlertDialog.Builder builder= new AlertDialog.Builder(this);//得到DIalog對象
// 通過LayoutInflater來加載一個xml的布局文件作為一個View對象
View view = LayoutInflater.from(DialogActivity.this).inflate(R.layout.dialog_main, null);
final Button btn= (Button) view.findViewById(R.id.btn_test);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(DialogActivity.this,"Costom Button clicked",Toast.LENGTH_LONG).show();
}
});
/**!!!!!!!!!
Window dialogWindow=builder.create().getWindow();
WindowManager.LayoutParams layoutParams = dialogWindow.getAttributes();
layoutParams.width=800;
layoutParams.height=600;
layoutParams.alpha=0.8f;
dialogWindow.setAttributes(layoutParams);
Log.e("layoutParams",layoutParams.width+"--1---"+layoutParams.height);//此時輸出 800 --1--- 600
dialog.show();
Log.e("layoutParams",layoutParams.width+"--2---"+layoutParams.height);//此時值改變了-2 --1--- -2
//dialogWindow.setLayout(layoutParams.width,layoutParams.height);如果用這這段代碼則無法調整對話框的大小
dialogWindow.setLayout(800,600);
*/

// 設置我們自己定義的布局文件作為彈出框的Content
builder.setView(view)
.show();
}

這里寫圖片描述
我們首先需要寫一個xml的布局文件,我們不需要在布局文件里定義Button按鈕,可以通過 AlertDialog.Builder 來設置 action buttons。

通過 View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.dialog, null); 我們可以將我們的布局文件加載進來,得到一個View對象,然后通過 AlertDialog.Builder 的setView方法來設置我們的自定義彈出框

2、ProgressDialog

2.1、ProgressDialog部分源碼結構

ProgressDialog直接繼承自AlertDialog並實現了DialogInterface接口,支持旋轉的圓形進度條水平進度條,從代碼結構來看我們可以通過兩種方式來得到ProgressDialog對象:構造方法靜態方法show

private Handler mViewUpdateHandler;
public class ProgressDialog extends AlertDialog {
/** Creates a ProgressDialog with a circular, spinning progress
* bar. This is the default.
*/

private Handler mViewUpdateHandler;
public ProgressDialog(Context context) {
...
}
public ProgressDialog(Context context, int theme) {
...
}
public static ProgressDialog show(Context context, CharSequence title,
CharSequence message, boolean indeterminate, boolean cancelable) {
...
}
public static ProgressDialog show(Context context, CharSequence title,
CharSequence message, boolean indeterminate,
boolean cancelable, OnCancelListener cancelListener) {
ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle(title);
dialog.setMessage(message);
dialog.setIndeterminate(indeterminate);
dialog.setCancelable(cancelable);
dialog.setOnCancelListener(cancelListener);
dialog.show();
return dialog;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(mContext);
TypedArray a = mContext.obtainStyledAttributes(null,
com.android.internal.R.styleable.AlertDialog,
com.android.internal.R.attr.alertDialogStyle, 0);
if (mProgressStyle == STYLE_HORIZONTAL) {
/* Use a separate handler to update the text views as they
* must be updated on the same thread that created them.
*/

mViewUpdateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
/* Update the number and percent */
int progress = mProgress.getProgress();
int max = mProgress.getMax();
if (mProgressNumberFormat != null) {
String format = mProgressNumberFormat;
mProgressNumber.setText(String.format(format, progress, max));
} else {
mProgressNumber.setText("");
}
if (mProgressPercentFormat != null) {
double percent = (double) progress / (double) max;
SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent));
tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mProgressPercent.setText(tmp);
} else {
mProgressPercent.setText("");
}
}
};
...
View view = inflater.inflate(a.getResourceId(
com.android.internal.R.styleable.AlertDialog_horizontalProgressLayout,
R.layout.alert_dialog_progress), null);
mProgress = (ProgressBar) view.findViewById(R.id.progress);
mProgressNumber = (TextView) view.findViewById(R.id.progress_number);
mProgressPercent = (TextView) view.findViewById(R.id.progress_percent);
setView(view);
} else {
View view = inflater.inflate(a.getResourceId(
com.android.internal.R.styleable.AlertDialog_progressLayout,
R.layout.progress_dialog), null);
mProgress = (ProgressBar) view.findViewById(R.id.progress);
mMessageView = (TextView) view.findViewById(R.id.message);
setView(view);
}
...
setIndeterminate(mIndeterminate);
onProgressChanged();
super.onCreate(savedInstanceState);
}
}

2.2、使用ProgressDialog

步驟簡記:得到ProgressDialog對象——>顯示

2.2.1、創建ProgressDialog對象

  • 通過構造方法new
ProgressDialog dialog = new ProgressDialog(this);  
  • 通過ProgressDialog的靜態方法show
//創建進度對話框(只能是圓形條)並設置title和Message提示內容 
ProgressDialog logDialog = ProgressDialog.show(this, "Notice", "Loging……");

//創建進度對話框(只能是圓形條)並設置title和Message提示內容,最后一個參數boolean indeterminate設置是否是不明確的狀態
ProgressDialog logDialog = ProgressDialog
.show(this,"Notice", "Loging……", false);

//創建進度對話框(只能是圓形條)並設置title和Message提示內容,最后一個參數boolean cancelable 設置進度條是否是可以取消的
ProgressDialog logDialog = ProgressDialog
.show(this,"Notice", "Loging……", false,true);

還可以監聽進度條取消的事件

private OnCancelListener cancelListener = new OnCancelListener(){  
@Override
public void onCancel(DialogInterface dialog) {
Toast.makeText(DialogActivity.this, "ProgressBar canceled", Toast.LENGTH_LONG).show();
}
};
// cancelListener用於監聽進度條被取消
ProgressDialog logDialog = ProgressDialog.show(this, "Notice", "Loging……", true,
true, cancelListener);

2.2.2、圓形進度條對話框

private void showProgressDialog(){
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 設置進度條的形式為圓形轉動的進度條
dialog.setCancelable(true);// 設置是否可以通過點擊Back鍵取消
dialog.setCanceledOnTouchOutside(false);// 設置在點擊Dialog外是否取消Dialog進度條
dialog.setIcon(R.mipmap.ic_launcher);//
// 設置提示的title的圖標,默認是沒有的,需注意的是如果沒有設置title的話只設置Icon是不會顯示圖標的
dialog.setTitle("Notice");
// dismiss監聽
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {

@Override
public void onDismiss(DialogInterface dialog) {
}
});
// 監聽Key事件被傳遞給dialog
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {

@Override
public boolean onKey(DialogInterface dialog, int keyCode,
KeyEvent event) {
return false;
}
});
// 監聽cancel事件
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

@Override
public void onCancel(DialogInterface dialog) {
}
});
//設置可點擊的按鈕,最多有三個(默認情況下)
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Confirm",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, "Natrue",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setMessage("Loging in ...");
dialog.show();
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(6666);
/*cancel和dismiss方法本質都是一樣的,都是從屏幕中刪除Dialog,唯一的區別是
調用cancel方法會回調DialogInterface.OnCancelListener如果注冊的話,dismiss方法不會回掉*/

dialog.cancel();
// dialog.dismiss();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}

這里寫圖片描述

2.2.3、水平進度條對話框

private void showHorProgressDialog(){
final ProgressDialog dialog = new ProgressDialog(this);
///dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 設置進度條的形式為圓形轉動的進度條
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setProgress(R.mipmap.ic_launcher);
dialog.setSecondaryProgress(R.mipmap.image002);//設置二級進度條的背景
dialog.setCancelable(true);// 設置是否可以通過點擊Back鍵取消
dialog.setCanceledOnTouchOutside(false);// 設置在點擊Dialog外是否取消Dialog進度條
dialog.setIcon(R.mipmap.ic_launcher);//
// 設置提示的title的圖標,默認是沒有的,需注意的是如果沒有設置title的話只設置Icon是不會顯示圖標的
dialog.setTitle("Notice");
dialog.setMax(100);
// dismiss監聽
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {

@Override
public void onDismiss(DialogInterface dialog) {
}
});
// 監聽Key事件被傳遞給dialog
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {

@Override
public boolean onKey(DialogInterface dialog, int keyCode,
KeyEvent event) {
return false;
}
});
// 監聽cancel事件
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

@Override
public void onCancel(DialogInterface dialog) {
}
});
//設置可點擊的按鈕,最多有三個(默認情況下)
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Confirm",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, "Natrue",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setMessage("Downloading ...");
dialog.show();
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (i < 100) {
try {
Thread.sleep(200);
// 更新進度條的進度,可以在子線程中更新進度條進度
dialog.incrementProgressBy(1);
dialog.incrementSecondaryProgressBy(15);//二級進度條更新方式
i++;

} catch (Exception e) { }
}
// 在進度條走完時刪除Dialog
dialog.dismiss();
}
}).start();
}

這里寫圖片描述


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com