安卓中的彈窗介面介紹
AlertDialog的使用
介紹
AlertDialog可以在當前介面彈出一個對話方塊,這個對話方塊是置頂於所有的介面元素上,可以遮蔽掉其他控制元件的互動能力,在程式碼中使用靈活簡單。
推薦
這裡推薦一個Git專案,上面提供的比較多的功能:
material-dialogs
基本使用
AlertDialog.Builder builder= new AlertDialog.Builder(MainActivity.this);
builder.setTitle("這是一個DiaLog");
//設定標題
builder.setMessage("你確定你知道了嗎" );
//設定內容
builder.setIcon(R.mipmap.ic_launcher);
//設定頭像Icon
builder.show();
/**解釋說明:
AlertDialog是通說Builder構建者模式來建立的,其中使用builder來建立Dialog,
通過show()方法展示*/
新增按鈕
上面都是簡單使用,在彈出框上還可以新增事件按鈕,一共可以監聽四種事件
在上面基礎上新增在builder.show()之前
//新增一個確定按鈕,列印log發現是 i=-1
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main","使用者點選了確定按鈕");
Log.d("Main","使用者點選了確定按鈕"+i);
}
});
//新增一個取消按鈕,列印log 發現是 i=-2
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main","使用者點選了取消按鈕");
Log.d("Main","使用者點選了取消按鈕"+i);
}
});
//新增一箇中立按鈕,列印log,發現是 i=-3
builder.setNeutralButton("中立", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main","使用者點選了中立");
Log.d("Main","使用者點選了中立"+i);
}
});
//這個方法是監聽當用戶點選了dialog窗體之外的方法,
// dialog.setCancelable(false);如果存在這句話的話,那麼這個監聽就無效了,
//哪怕使用者按回退鍵
//注意的是,這個監聽所指窗體之外也包括了使用者按回退鍵這個動作
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
Log.d("Main","使用者點選了檢視外面");
}
});
/**你會發現你可以使用好多setNegativeButton,方法來設定按鈕,但是最終有效果
最後新增或執行的。這樣你就可以根據不同的情況來展示不同的AlertDialog介面了
另外你點了哪一個按鈕,那麼AlertDialog窗體就會消失*/
修改內容主題部分
當然,那就不能使用setMessage()這個方法了。
第一種:展示列表內容
builder.setItems(ss, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main","點選了內容區域");
Log.d("Main","點選了"+i); //會發現下角標是從0、1、2開始變化的
}
});
//說明這裡的ss其實: private String [] ss = {"項羽","劉邦","韓信"};
展示單選框內容
builder.setSingleChoiceItems(ss, 1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main","最後確定的是"+i);
//這個的特色是選中之後,dialog並不會消失,但是會確定i,用來定位的。
}
});
//這個是帶有單選框的,引數二是預設選中哪一個,比如1就是預設選中1位置的
展示覆選框內容
builder.setMultiChoiceItems(ss, dd, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i, boolean b) {
Log.d("Main",""+dialogInterface);
Log.d("Main",""+i);
Log.d("Main",""+b);
}
//這裡面引數二是預設選中哪幾項,是一個Boolean型別的陣列
//當用戶改變一個item 的條目的時候,就會走一遍監聽,將改變的那一個item的位置i以及變化變化之後的
//狀態true 或者 false 都可以知道
//前面的ss有多長,那麼dd就應該有多長,要不然就會存在陣列越界
});
//附上陣列dd: private boolean []dd ={true,false,true};
使用自定義內容區域
如果上面的內容還不是能過滿足你,可以使用自己定義佈局樣式
首先準備一個佈局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#47ec38"/>
<EditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="請輸入你的建議"
android:background="@null"
/>
<EditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="請輸入你的建議"
android:background="@null"
/>
</LinearLayout>
其次在show()方法執行之前呼叫這個方法:
builder.setView(R.layout.sd);
***這裡注意的是,在AlertDialog展示的內容區域,只能放一個內容,要不然就會出問題的***,
如何讓dialog從底部彈出
需要注意的是,前面的都可以通過builder來完成,但是這個需要通過AlertDialog來完成,
其實,可以是在builder的基礎上,新建一個AlertDialog(也就是說,你在builder.create方法之後在呼叫builder修改屬性,對於生成的dialog是沒有意義的,沒有效果),因為你同時呼叫builder.show()還有dialog.show(),你會發現,兩個窗體都會出現,誰先呼叫誰現出來,但是都會出來。當然了,AlertDialog 物件有許多值是不能設定的,是要builder來完成基礎的搭建,並且builder也不能完成許多操作,比如呼叫dismiss()方法,還比如下面的,讓dialog從底部彈出,這種修改窗體的。
/*介紹了這麼多,其實最簡單來講:你前面構建了一個builder,然後你也得到了一個dialog物件,但是你最後在使用的時候使用builder.show(),那麼最後展示出來的是builder配置的樣式,和dialog配置的一點關係沒有/
AlertDialog mDialog = builder.create(); //得到一個新建的AlertDialog窗體物件
Window window = mDialog.getWindow();
window.setGravity(Gravity.BOTTOM);
window.setWindowAnimations(R.style.mydialog);
mDialog.setCanceledOnTouchOutside(true);
mDialog.show();
這裡引用了style格式檔案,
<style name="mystyle" parent="android:Animation">
<item name="@android:windowEnterAnimation">@anim/dialog_enter
</item> //進入時的動畫
<item name="@android:windowExitAnimation">@anim/dialog_exit
</item> //退出時的動畫
</style>
進入時候動畫,根據具體需求來寫,這裡只是例子罷了
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate
android:duration = "300"
android:fromYDelta="100%p"
android:toYDelta="0"
/>
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0"
/>
</set>
退出時候動畫
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate
android:duration="300"
android:fromYDelta="0"
android:toYDelta="50%"
/>
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0"
/>
</set>
讓Dialog和螢幕一樣寬
在使用AlertDialog時候很大情況不僅需要從底部彈出,還希望的是要鋪滿全屏,先看幾張效果圖:
(1)使用 alertDialog.setView(views);
(2)alertDialog.setView(views,40,40,40,40);
發現我在佈局的時候,確實是讓其match_parent了,但是展示出來卻沒有效果,從網上找了程式碼如下:
View views = LayoutInflater.from(this).inflate(R.layout.myitem,null,false);
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("這是一個測試的例子");
builder.setNegativeButton("哈哈", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(MainActivity.this,"點選了哈哈",Toast.LENGTH_SHORT).show();
}
});
builder.setView(views);//也可以展示出來
AlertDialog alertDialog = builder.create();
Window window = alertDialog.getWindow();
window.setGravity(Gravity.BOTTOM);
window.setWindowAnimations(R.style.mystyle);
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
alertDialog.show();
執行發現,還是原樣,如圖一,沒有達到自己想要的結果。
其實,在寫程式碼時候:
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this,R.style.DialogTheme);
給其使用上主題就可以了,
/**
< style name=”DialogTheme” parent=”@android:style/Theme.Dialog”>
< item name=”android:windowFrame”>@null移除邊框
< item name=”android:windowNoTitle”>true去除頂部標題欄
< item name=”android:windowIsTranslucent”>true窗體透明
< item name=”android:background”>@android:color/white背景透明
< item name=”android:windowBackground”>@android:color/transparent窗體背景透明
< item name=”android:windowIsFloating”>false窗體是否浮動
< item name=”android:backgroundDimEnabled”>true背景是否昏暗
< item name=”android:backgroundDimAmount”>0.6昏暗數量
< /style>
*/
如何讓讓dialog不退出
前面知道dialog可以有三個按鈕的監聽,但是你會發現,當你點選了某一個按鈕之後,它就會消失,這是因為:
這裡以設定setPositiveButton為例子,
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this;
}
//可以發現:設定的text賦給了mPositiveButteonText,
//設定的監聽賦給了mPositiveButtonListener
關鍵是p:
//這個是在AlertDialog的Builder裡面,這是在AlertController中定義的內部類,裡面定義了大量的屬性
private final AlertController.AlertParams P;
在AlertParams 中有一個方法:
public void apply(AlertController dialog) {
if (mCustomTitleView != null) {
dialog.setCustomTitle(mCustomTitleView);
} else {
if (mTitle != null) {
dialog.setTitle(mTitle);
}
if (mIcon != null) {
dialog.setIcon(mIcon);
}
if (mIconId != 0) {
dialog.setIcon(mIconId);
}
if (mIconAttrId != 0) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
if (mMessage != null) {
dialog.setMessage(mMessage);
}
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText, mPositiveButtonListener, null);
}
if (mNegativeButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,mNegativeButtonListener, null);
}
if (mNeutralButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,mNeutralButtonListener, null);
}
// For a list, the client can either supply an array of items or an
// adapter or a cursor
if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
createListView(dialog);
}
if (mView != null) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
} else if (mViewLayoutResId != 0) {
dialog.setView(mViewLayoutResId);
}
}
//可以發現,在這個名為應用的方法中,有如下程式碼
//dialog.setButton(DialogInterface.BUTTON_POSITIVE, //mPositiveButtonText, mPositiveButtonListener, null);
//而setButton方法是AlertController中定義的方法,如下:
public void setButton(int whichButton, CharSequence text, DialogInterface.OnClickListener listener, Message msg) {
if (msg == null && listener != null) {
msg = mHandler.obtainMessage(whichButton, listener);
}//如果msg不為空,並且存在聽者,可以得到相對應的msg
switch (whichButton) {
//針對與各種不同的按鈕whichButton,通過前面的呼叫,可以發現,
//whichButton就是一些int數值,下面完成賦值操作
case DialogInterface.BUTTON_POSITIVE:
mButtonPositiveText = text;
mButtonPositiveMessage = msg;
break;
case DialogInterface.BUTTON_NEGATIVE:
mButtonNegativeText = text;
mButtonNegativeMessage = msg;
break;
case DialogInterface.BUTTON_NEUTRAL:
mButtonNeutralText = text;
mButtonNeutralMessage = msg;
break;
default:
throw new IllegalArgumentException("Button does not exist");
}
}
上述表示,設定完監聽的底層操作,用於接下來的點選事件。
在AlertDialog類中的onCreate方法中,存在:
mAlert.installContent();
在AlertController類中找到這個方法,裡面呼叫了,
setupView();
裡面存在:
setupButtons(buttonPanel);
在這個方法中會發現:
mButtonPositive.setOnClickListener(mButtonHandler);
然後,會發現mButtonHandler引數
private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
@Override
public void onClick(View v) {
final Message m;
if (v == mButtonPositive && mButtonPositiveMessage != null) {
m = Message.obtain(mButtonPositiveMessage);
} else if (v == mButtonNegative && mButtonNegativeMessage != null) {
m = Message.obtain(mButtonNegativeMessage);
} else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
m = Message.obtain(mButtonNeutralMessage);
} else {
m = null;
}
if (m != null) {
m.sendToTarget();
} mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialog).sendToTarget();
}
};
//會對於前面準備的相對應的msgt進行判斷,然後,要是存在的話,就會呼叫sendToTarget()方法。非同步的方式通知Handler的handleMessage方法執行我們最開始設定的監聽器中的onClick()方法。通過傳送MSG_DISMISS_DIALOG訊息,在Handler的handleMessage()方法中呼叫dismiss()方法退出dialog,這就是為什麼點選按鈕之後對話方塊無條件退出的原因。
總結:dialog的時候一般會呼叫setPositiveButton()方法傳入我們自己的監聽器,然後在create()(show會首先執行create)的時候該監聽器會被賦值給dialog內部AlertParams物件的mPositiveButtonListener屬性,然後該物件的apply()方法將該賦值後的mPositiveButtonListener封裝在一個message物件中,
//上述是準備工作,下述是刺激事件,
在按鈕被點選之後,就會獲取我們先前message物件中封裝的監聽器,進而呼叫該監聽器的onClick()方法執行我們在setPositiveButton()中傳入的監聽器邏輯,同時傳送訊息呼叫dismiss()方法讓對話方塊消失。
解決辦法:
使用者輸入不滿意的話就通過反射修改mShowing的值為false,再手動呼叫dismiss(),由於mShowing為false,對話方塊就不會消失
mBuilder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Field field = null;
try {
field = dialogInterface.getClass().getSuperclass().getSuperclass().getDeclaredField("mShowing");
field.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
if (is != 3) {
try {
field.set(dialogInterface, false);
dialogInterface.dismiss();
Toast.makeText(MainActivity.this, "還不夠,現在是" + is, Toast.LENGTH_SHORT).show();
is++;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "還不夠,現在是" + is, Toast.LENGTH_SHORT).show();
try {
field.set(dialogInterface,true);
dialogInterface.dismiss();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
});
通過上述就可以不退出了
注意:
(1)setView和setContentView()兩者的區別:
setView()覆蓋AlertDialog的Title和Button之間的部分,而setContentView()全部覆蓋。
如果不注意這點的話,很容易在使用自定義樣式的時候,出現黑框。
ProgressDialog的使用
介紹
與AlertDialog類似,都是可以在介面上彈出一個對話方塊,都能夠遮蔽掉其他空間愛你的互動能力。
基本使用
progressDialog = new ProgressDialog(MainActivity.this);
//這是建立方式之一,還有一種,是需要兩個引數,引數二是主題,int theme;
progressDialog.setTitle("這是一個ProgressDialog");
//設定題目
progressDialog.setMessage("這裡面是內容區域");
//設定內容區域
progressDialog.setIcon(R.mipmap.ic_launcher);
//設定Icon
progressDialog.show();
新增按鈕
與AlertDialog類似,也是提供了三個按鈕的操作,一共可以有四個監聽事件
progressDialog.setButton(ProgressDialog.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main",""+i);//-2
}
});
progressDialog.setButton(ProgressDialog.BUTTON_POSITIVE, "確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main",""+i);//-1
}
});
progressDialog.setButton(ProgressDialog.BUTTON_NEUTRAL, "其他", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.d("Main",""+i);//-3
}
});
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
Log.d("Main","點選了空白區域");
}
});
//上述四個動作一點,progressDialog也是消失
//除非設定progressDialog.setCancelable(false);當然設定這個屬性,表示的是
//針對於點選空白處和回退鍵處無效了,那麼點選三個按鈕還是一樣會隱藏dialog窗體
改變中間顯示內容
可以根據不同的style確定不同的style
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
//會展示一個條形狀
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
//就是預設的,不斷轉圈的樣式()就是圖一的樣式
看看ProgressDialog.SYTLE_HORIZONTAL是什麼??
通過上面,你會發現,類似於下載的那個progress,
在show()方法之前,可以
progressDialog.setIndeterminate(false);
//這樣就可以保證可以修改進度了
在show方法之後可以呼叫:
progressDialog.setProgress(10);
//改變進度條的樣式
// 通過下面方法可以改變進度條的顏色。progressDialog.setProgressDrawable(getResources().getDrawable(R.drawable.ss));