廢話時間###
有一段時間沒好好敲代碼了序调,處理完手頭上一些瑣事,終于可以潛心修行余舶,就從這篇簡單而飽滿的技術文章開始我的簡書之旅吧啊鸭。
最近在不同項目做了一些不同的對話框,剛好來總結一下匿值。方便自己赠制,幫助他人。
本文由作者三汪首發(fā)于簡書千扔。
總覽###
1.什么是AlertDialog
2.AlertDialog入門以及基本使用(快速創(chuàng)建Dialog)
3.AlertDialog的進階(自定義布局憎妙、位置、大小曲楚、動畫厘唾、style)
1.什么是AlertDialog###
Google官方的開發(fā)文檔是這樣描述的:
A subclass of Dialog that can display one, two or three buttons. If you only want to display a String in this dialog box, use the setMessage() method. If you want to display a more complex view, look up the FrameLayout called "custom" and add your view to it:
FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom); fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
The AlertDialog class takes care of automatically setting WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM for you based on whether any views in the dialog return true from View.onCheckIsTextEditor(). Generally you want this set for a Dialog without text editors, so that it will be placed on top of the current input method UI. You can modify this behavior by forcing the flag to your desired mode after calling onCreate(Bundle).
翻譯如下(手動翻譯的,可能不夠信達雅):
AlertDialog是Dialog的一個子類龙誊,可以顯示一到三個button抚垃。如果你只想在對話框中顯示一個字符串,使用serMessage()這個方法。如果你想要顯示更復雜的視圖鹤树,找到這個叫"custom"的幀布局并把你的視圖添加進去:
FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom); fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
AlertDialog這個類根據(jù)是否有視圖從View.onCheckIsTextEditor()返回true來為你自動設置WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM通常你會想要為一個沒有文本編輯欄的對話框設置這個屬性铣焊,以便于該對話框被放置在當前輸入法界面的頂部。你可以在調(diào)用onCreate(Bundle)以后通過設置這個flag修改這一動作罕伯。
從官方文檔的描述中我們可以知道AlertDialog的這么幾個信息:
- 直接繼承自Dialog
- 可以有三個原生的button
- 可以顯示文字也可以在原生的FrameLayout布局中添加自定義視圖
官方文檔沒有告訴我們的是:
- 自定義布局可以不使用官方提供的FrameLayout
- 可以自定義對話框出現(xiàn)和消失時的動畫
- 可以設置對話框的大小曲伊、位置和style
下面我們來逐一說明。
2.快速創(chuàng)建你的Dialog###
代碼如下(可直接copy進你的項目使用):
AlertDialog dialog = new AlertDialog.Builder(this).create();//創(chuàng)建對話框
dialog.setIcon(R.mipmap.ic_launcher);//設置對話框icon
dialog.setTitle("這是一個AlertDialog");//設置對話框標題
dialog.setMessage("Hello world");//設置文字顯示內(nèi)容
//分別設置三個button
dialog.setButton(DialogInterface.BUTTON_POSITIVE,"確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();//關閉對話框
}
});
dialog.setButton(DialogInterface.BUTTON_NEUTRAL,"點我試試", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) { }
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();//關閉對話框
}
});
dialog.show();//顯示對話框
效果圖
Tips
- AlertDialog的三個button對應DialogInterface中的三個常量追他,分別是:
BUTTON_NEUTRAL
,BUTTON_POSITIVE
,BUTTON_NEGATIVE
坟募。不同的常量所對應的button位置不同。其中邑狸,BUTTON_NEUTRAL
在對話框左側懈糯,另外兩個在右側(不同版本的系統(tǒng)可能對應的位置不同,以實際情況為準)单雾。
-
AlertDialog dialog = new AlertDialog.Builder(this).create();
的Builder()中傳入的context參數(shù)必須來自activity赚哗,而不能是application的,否則會報錯硅堆。 - 當你什么都不設置的時候屿储,會彈出一個“白茫茫大地真干凈”的對話框。
- 調(diào)用
dismiss()
方法可以關閉對話框硬萍。除了在button點擊事件中扩所,還可以用在CheckBox、RadioButton的onCheckedChanged事件中等朴乖,以實現(xiàn)在用戶完成選擇以后自動關閉對話框的功能。 - setTitle助赞、setMessage买羞、setPositiveButton等這類設置動作還可以用builder對象來做,寫法不同雹食,效果一樣畜普。此處不再贅述。
3.簡單列表群叶、單選列表與復選列表對話框的實現(xiàn)示例###
簡單列表代碼如下:
//初始化字符串數(shù)組
final String[] strArray = new String[]{"床前明月光","意識地上霜","舉頭望明月","低頭思故鄉(xiāng)"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);//實例化builder
builder.setIcon(R.mipmap.ic_launcher);//設置圖標
builder.setTitle("簡單列表");//設置標題
//設置列表
builder.setItems(strArray, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this,strArray[which],Toast.LENGTH_SHORT).show();
}
});
builder.create().show();//創(chuàng)建并顯示對話框
單選列表代碼如下:
//初始化字符串數(shù)組
final String[] strArray = new String[]{"離離原上草","一歲一枯榮","野火燒不盡","春風吹又生"};
final AlertDialog.Builder builder = new AlertDialog.Builder(this);//實例化builder
builder.setIcon(R.mipmap.ic_launcher);//設置圖標
builder.setTitle("單選列表");//設置標題
//設置單選列表
builder.setSingleChoiceItems(strArray, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
//創(chuàng)建對話框
AlertDialog dialog = builder.create();
//設置確定按鈕
dialog.setButton(DialogInterface.BUTTON_POSITIVE,"確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog.show();//顯示對話框
復選列表代碼如下:
//初始化字符串數(shù)組
final String[] strArray = new String[]{"白日依山盡","黃河入海流","欲窮千里目","更上一層樓"};
final AlertDialog.Builder builder = new AlertDialog.Builder(this);//實例化builder
builder.setIcon(R.mipmap.ic_launcher);//設置圖標
builder.setTitle("多選列表");//設置標題
//設置多選列表
builder.setMultiChoiceItems(strArray, new boolean[]{false, false, false, false}, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
}
});
//創(chuàng)建對話框
AlertDialog dialog = builder.create();
//設置確定按鈕
dialog.setButton(DialogInterface.BUTTON_POSITIVE,"確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog.show();//顯示對話框
效果圖:
4.自定義布局對話框的簡單示例###
對于AlertDialog的自定義布局吃挑,官方提供了原生的FrameLayout(說明與使用方式參見前文開發(fā)文檔描述部分)供大家使用。但是街立,F(xiàn)rameLayout有時候并不能滿足大家的需求舶衬。因此,我們需要自己引入布局文件赎离。本文僅提供如何通過引入布局文件來實現(xiàn)自定義布局的示例逛犹。
代碼如下:
//實例化布局
View view = LayoutInflater.from(this).inflate(R.layout.item_custom,null);
//找到并對自定義布局中的控件進行操作的示例
EditText account = (EditText) view.findViewById(R.id.account);
account.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
//創(chuàng)建對話框
AlertDialog dialog = new AlertDialog.Builder(this).create();
dialog.setIcon(R.mipmap.ic_launcher);//設置圖標
dialog.setTitle("自定義布局對話框");//設置標題
dialog.setView(view);//添加布局
//設置按鍵
dialog.setButton(AlertDialog.BUTTON_POSITIVE, "登陸", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show();
效果圖:
5.如何設置Dialog的位置、大小、動畫###
通過幾小段代碼來說明虽画,以供參考舞蔽。
代碼片段1:
Window dialogWindow = dialog.getWindow();//獲取window對象
dialogWindow.setGravity(Gravity.BOTTOM);//設置對話框位置
dialogWindow.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);//設置橫向全屏
dialogWindow.setWindowAnimations(R.style.share_animation);//設置動畫
styles.xml
<style name="share_animation" 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"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="100%p" <!-- %p指相對于父容器-->
android:duration="600" <!-- 持續(xù)時間-->
/>
</set>
dialog_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:toYDelta="100%p"
android:duration="600"
/>
</set>
代碼片段2:
(片段2與片段3轉載自:angeldevil)
/*
* 將對話框的大小按屏幕大小的百分比設置
*/
// WindowManager m = getWindowManager();
// Display d = m.getDefaultDisplay(); // 獲取屏幕寬、高用
// WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 獲取對話框當前的參數(shù)值
// p.height = (int) (d.getHeight() * 0.6); // 高度設置為屏幕的0.6
// p.width = (int) (d.getWidth() * 0.65); // 寬度設置為屏幕的0.65
// dialogWindow.setAttributes(p);
代碼片段3:
(片段2與片段3轉載自:angeldevil)
Window dialogWindow = dialog.getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
dialogWindow.setGravity(Gravity.LEFT | Gravity.TOP);
/*
* lp.x與lp.y表示相對于原始位置的偏移.
* 當參數(shù)值包含Gravity.LEFT時,對話框出現(xiàn)在左邊,所以lp.x就表示相對左邊的偏移,負值忽略.
* 當參數(shù)值包含Gravity.RIGHT時,對話框出現(xiàn)在右邊,所以lp.x就表示相對右邊的偏移,負值忽略.
* 當參數(shù)值包含Gravity.TOP時,對話框出現(xiàn)在上邊,所以lp.y就表示相對上邊的偏移,負值忽略.
* 當參數(shù)值包含Gravity.BOTTOM時,對話框出現(xiàn)在下邊,所以lp.y就表示相對下邊的偏移,負值忽略.
* 當參數(shù)值包含Gravity.CENTER_HORIZONTAL時
* ,對話框水平居中,所以lp.x就表示在水平居中的位置移動lp.x像素,正值向右移動,負值向左移動.
* 當參數(shù)值包含Gravity.CENTER_VERTICAL時
* ,對話框垂直居中,所以lp.y就表示在垂直居中的位置移動lp.y像素,正值向右移動,負值向左移動.
* gravity的默認值為Gravity.CENTER,即Gravity.CENTER_HORIZONTAL |
* Gravity.CENTER_VERTICAL.
*
* 本來setGravity的參數(shù)值為Gravity.LEFT | Gravity.TOP時對話框應出現(xiàn)在程序的左上角,但在
* 我手機上測試時發(fā)現(xiàn)距左邊與上邊都有一小段距離,而且垂直坐標把程序標題欄也計算在內(nèi)了,
* Gravity.LEFT, Gravity.TOP, Gravity.BOTTOM與Gravity.RIGHT都是如此,據(jù)邊界有一小段距離
*/
lp.x = 100; // 新位置X坐標
lp.y = 100; // 新位置Y坐標
lp.width = 300; // 寬度
lp.height = 300; // 高度
lp.alpha = 0.7f; // 透明度
// 當Window的Attributes改變時系統(tǒng)會調(diào)用此函數(shù),可以直接調(diào)用以應用上面對窗口參數(shù)的更改,也可以用setAttributes
// dialog.onWindowAttributesChanged(lp);
dialogWindow.setAttributes(lp);
以上码撰。
歡迎留言探討渗柿,指正。
希望我總結的東西能夠對你有所幫助脖岛。