前言
關于Dialog的使用可謂是相當的廣泛,可以用來做各種處理,其中也衍生了許多種的處理方式,有好有壞,自己有必要加以拿捏,熟練了以后,便可謂是招之即來,揮之即去。
Dialog搭配一些個性化風格與簡單動畫會有一些神奇效果(Pics from Baidu_Pics):
實現類似的展示效果并不難,接下來會在頁面的基礎上加入一些回調設置的說明,在開始之后還是先來看下其繼承結構吧:
java.lang.Object
? android.app.Dialog
-->implements DialogInterface, KeyEvent.Callback, View.OnCreateContextMenuListener, Window.Callback
由此可知,Dialog是一個可以獨立的控件,而DialogInterface和KeyEvent.Callback也說明其是一個回調性很強的Object,在諸多的Dialog實例中,其子類AlertDialog是一種很好的實現方式,下面會具體介紹。
Dialog的初始化
Dialog和普通的View不同,它有自己的生命周期。
通過onCreate( )創建
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_dialog);
}
可以看出和Activity的onCreate( )類似,也可以在其中加入一些init( )方法對layout文件中的子控件進行監聽等。下面看一下調用方式:
MyDialog myDialog = new MyDialog(this);
myDialog.setCanceledOnTouchOutside(false);
myDialog.show();
// 具體邏輯通過構造方法創建
public MyDialog(Activity activity, int resLayout) {
super(activity, R.style.myDialog);
this.activity = activity;
this.resLayout = resLayout;
}
構造方法中的參數可以根據需求來定義,一般不超過5個,不然會影響性能,下面看一下調用方式:
MyDialog myDialog = new MyDialog(this, R.style.myDialog, R.layout.my_dialog);
myDialog.show();-
創建與銷毀時的細節
而這兩種創建方法卻有一點不同:onCreate( )創建的Dialog的邏輯處理需在show( )之后,相當于調用了show( )之后才會真正的創建出來,而通過構造方法創建的Dialog的show( )可以放在最后的位置,相當于一個整體的展示。
而一般自定義的Dialog由于個性化需求較大,所以其style一般需要簡單定制一下:<!-- 自定義Dialog的Theme定義 --> <style name="myDialog" parent="android:Theme.Dialog"> <item name="android:windowFrame">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowIsFloating">true</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowBackground">@android:color/transparent</item> </style>
對于Dialog的銷毀,有兩種方法:dismiss( )和cancel( ),仔細的童鞋會發現cancel( )其實中調用了dismiss( )的,只是加了一個對mCancelMessage的判斷,看下該源碼:
public void setOnCancelListener(final OnCancelListener listener) {
if (listener != null) {
mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);
} else {
mCancelMessage = null;
}
}
public void setCancelMessage(final Message msg) {
mCancelMessage = msg;
}
也就是說,如果調用了setOnCancelListener,這個mCancelMessage變量有作用,否則dismiss( )和cancel( )等同。
此外,還可以對Dialog的透明,展出方向(上下左右)等進行設置,如下圖便是一個底部彈出的Dialog:
Dialog的回調監聽
Keep your eyes on......重點來了,關于Dialog最重要的除了展示效果外無非就是其回調的設置了,而其回調方式有很多種,有把Dialog當作Activity的方式來處理的,有使用DialogInterface來處理的,有把Dialog當作View的方式來處理,還有使用loop/handler的方式來處理的......總之有很多種方式,具體的邏輯與效率總有優劣之處,請大家自己掌控~下面來一一介紹:
Dialog VS Handler
使用Handler的方式,可以通過構造函數傳遞參數,然后在消息隊列中捕獲并處理,這種方式比較簡潔,在調用的位置加上:
myDialog.setHandler(mHandler);
在Dialog中:
private void setHandler(mHandler) {
this.mHandler = mHandler;
}
然后便是在Activity中通過handleMessage(msg)方法進行處理,當然可以在此進行優化,使用靜態內部類InnerHandler + 弱引用WeakReference的方式(附參考鏈接),將具體的回調設置在此處處理。Dialog VS DialogFragment
DialogFragment集Dialog與Fragment于一身,貌似很強大。DialogFragment配合DialogInterface使用比較切合,在調用的位置:
MyDialog myDialog = new MyDialog(this, R.style.myDialog, R.layout.my_dialog);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
myDialog.show(fragmentTransaction, null);
而此時的MyDialog需要繼承自DialogFragment,即按Fragment的方式來初始化Dialog,在我們需要回調處理的地方:
MyActivity instance = (MyActivity) getActivity();
instance.onDialogBack();
即相當于回調了Activity中的onDialogBack( )方法:
public void onDialogBack() {
// 具體邏輯
}-
Dialog VS setListener( )
看過我以前自定義View的童鞋一定也了解其實現思路,即在Dialog中加入一些setListener( )方法,然后在實例化后直接該用內部的setListener( )方法即可,兩種創建方式都可行,只需將myDialog對象調用MyDialog中的方法:
Dialog中:
public void setMyVisibility(boolean visibility) {
mView.setVisibility(visibility ? View.VISIBLE : View.GONE);
}Activity中: myDialog.setMyVisibility(true);
-
Example
結合了以上各個思路,下面給出兩種可以拿來封裝的樣式,底部彈出的Dialog與居中彈出的Dialog:
dialog_style1.png
dialog_style2.png
AlertDialog初探
AlertDialog是一種極其個性化的Dialog,相當于一個樣式封裝好的Dialog,便于調用,默認的風格便是一種最簡單的處理,當然也可以自定義,在其初始化時使用了強大且神奇的Build-建造者模式。
AlertDialog的構造方法全部是Protected的,所以不能直接通過new一個AlertDialog來創建出一個AlertDialog,需要用到AlertDialog.Builder中的create()方法:
Dialog alertDialog = new AlertDialog.Builder(this)
.setTitle("Title") // 標題
.setMessage("Content") // 內容
.setPositiveButton("OK", this) // Positive Button
.setNegativeButton("Cancel", this); // Negative Button
.setNeutralButton("Neutral", this); // Neutral Button
.setItems(new String[] {"A", "B", "C"}, this); // 條目
.setIcon(R.drawable.ic_launcher) // 圖標
.create();
alertDialog.show();
因為是建造者模式,所以上面這些Build的內容都是Optional的,而其中若想添加監聽,可以這樣實現:
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
})
針對于其中的setItem( ),也可以有這樣的擴展,效果如下:
.setSingleChoiceItems(new String[] {"A", "B", "C", "D"}, 0, this); // 單選條目
.setMultiChoiceItems(new String[] {"A", "B", "C", "D"}, 0, this); // 多選條目
此外值得一說的是,若是繼承了DialogFragment,則在使用了AlertDialog的setButton( )后,可以重寫父類的onClick( )方法直接回調,感覺很強大的樣子:
@Override
public void onClick(DialogInterface dialog, int which) {
switch(which) {
case AlertDialog.BUTTON_NEGATIVE:
// TODO
break;
case AlertDialog.BUTTON_NEGATIVE:
// TODO
break;
// TODO
}
}
當然AlertDialog還有很多方法,這里就不一一介紹了,其中pedant大神對其有仔細研究,有興趣的可以去看看他的sweet-alert-dialog。我以前也參考過一些用例,簡單寫過一個AlertDialogDemo,大家也可以參考一下~
尾聲
關于Dialog這部分自己是一點一點踩過了許多坑,然后總結了許多種實現方式從而最終Get到其強大之處,由此寫來給大家分享一下小小的心得~
Github地址:
https://github.com/IvorfasonGithub博客:
http://ivorfason.github.io個人郵箱:(我覺得QQ郵箱很高大上,You can you up!)
justforyouymr@qq.com雜談一下
關于Dialog的實現與自定義控件、自定義View其實也有一定的相似之處,當然更多的是Dialog的整體性較高,回調性與多元性可以很復雜,具體邏輯需要自己結合項目實際需求加以調控,這樣的Personality便會很有意義。后期會不定期更新自己的學習心得,歡迎大家查漏補缺......
最后再來看一張很好看的效果~