天天看點

Android基于DialogFragment封裝一個通用的Dialog

一、背景

Dialog是項目中最常用的一個功能之一了,接手項目的時候發現項目中是封裝了一個dialog的,但是發現是用單例封裝的,大緻如下:

private MyDialog() {

}

public static MyDialog getInstance() {
return DialogHolder.instance;

}

private static class DialogHolder {
private static MyDialog instance = new MyDialog();

}

public void show(){}
public void dismiss(){}
           

使用單例除了可能會有記憶體洩漏問題,在使用過程中還發現一個問題:不同頁面的dialog可以互相影響,想想也對,因為全局隻有一個

dialog

嘛,項目中有一個場景:A頁面跳B頁面,一進B頁面的

onCreate()

時需要彈一個dialog,發現每次都彈不出來,debug發現原來在A頁面的

onStop()

方法裡調用了

dismiss()

方法,A頁面跳B頁面生命周期走的是:

A頁面: onPause()

B頁面: onCreate()

B頁面: onStart()

B頁面: onResume()

A頁面: onStop()
           

是以原因也找到了,每次在B的

onCreate()

裡面剛調用了

show()

,緊接着又調用了A的

onStop()

中的

dismiss()

給關掉了,用單例方式顯然不太合适。趁着版本大改版,花了點時間重新撸了一個。根據我們的項目需要,調研了下,大概需要符合以下場景:

1、

不用提供布局,内置項目中常用預設的樣式

2、 

支援自定義複雜的布局、動畫、對話框大小、背景色等設定

3、

統一管理多個dialog并順序彈出

第一點:大部分情況下,使用對話框的樣式都是一緻的,是以内置了預設的

dialog

樣式,可以避免調用方每次再去找布局檔案,盡可能的簡化調用。ps:内置

dialog

樣式可以根據需求自行修改。

第二點:如果需要自定義複雜的布局,需要支援布局子View的建立及一系列互動事件。

第三點: 項目中有個需求,可能一次會産生多個

dialog

,需要依次彈出

dialog

基于以上需求點,使用

DialogFragment

封裝了一個通用

Dialog

——

SYDialog

,先看最終效果圖

二、效果圖
Android基于DialogFragment封裝一個通用的Dialog

gif圖比較模糊,直接掃二維碼下載下傳APK吧!

三、為什麼選擇DialogFragment?

DialogFragment

繼承自

Fragment

,即可以用

Fragment

來展示

Dialog

,相比于用

AlertDialog

或者

Dialog

DialogFragment

 更有優勢:

 ●  當手機配置變化導緻

Activity

重建時(比如旋轉螢幕)或點選實體傳回鍵時,

DialogFragment

可以管理好自己的生命周期

 ●  

DialogFragment

Fragment

,是以

DialogFragment

也可以當做一個内嵌的元件來使用,是以

DialogFragment

有更好的複用性

四、UML圖

用一個UML圖大緻來表示一下類之間的關系:

Android基于DialogFragment封裝一個通用的Dialog
五、使用文檔 1、使用内置dialog:

 ●  内置一個Button的樣式:

new SYDialog.Builder(this)

.setTitle("我是标題")

.setContent("您好,我們将在30分鐘處理,稍後通知您訂單結果!")

.setPositiveButton(new IDialog.OnClickListener() {
@Override
public void onClick(IDialog dialog) {

dialog.dismiss();

}

})

.show();
           

效果圖:

Android基于DialogFragment封裝一個通用的Dialog

内置二個Button的樣式:

new SYDialog.Builder(this)

.setTitle("我是标題")

.setContent("您好,我們将在30分鐘處理,稍後通知您訂單結果!")

.setPositiveButton(new IDialog.OnClickListener() {
@Override
public void onClick(IDialog dialog) {

dialog.dismiss();

}

})

.setNegativeButton(new IDialog.OnClickListener() {
@Override
public void onClick(IDialog dialog) {

dialog.dismiss();

}

})

.show();
           
Android基于DialogFragment封裝一個通用的Dialog
2、使用自定義布局的樣式:
new SYDialog.Builder(this)

.setDialogView(R.layout.layout_dialog)//設定dialog布局

.setAnimStyle(R.style.translate_style)//設定動畫 預設沒有動畫

.setScreenWidthP(0.85f) //設定螢幕寬度比例 0.0f-1.0f

.setGravity(Gravity.CENTER)//設定Gravity

.setWindowBackgroundP(0.2f)//設定背景透明度 0.0f-1.0f 1.0f完全不透明

.setCancelable(true)//設定是否屏蔽實體傳回鍵 true不屏蔽 false屏蔽

.setCancelableOutSide(true)//設定dialog外點選是否可以讓dialog消失

.setBuildChildListener(new IDialog.OnBuildListener() {
//設定子View
@Override
public void onBuildChildView(final IDialog dialog, View view, int layoutRes) {
//dialog: IDialog
//view: DialogView
//layoutRes :Dialog的資源檔案 如果一個Activity裡有多個dialog 可以通過layoutRes來區分
final EditText editText = view.findViewById(R.id.et_content);

Button btn_ok = view.findViewById(R.id.btn_ok);

btn_ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

String editTextStr = null;
if (!TextUtils.isEmpty(editText.getText())) {

editTextStr = editText.getText().toString();

}

dialog.dismiss();

Toast.makeText(MyApplication.getApplication(), editTextStr, Toast.LENGTH_SHORT).show();

}

});

}

}).show();
           

代碼中注釋已經很詳細了,如果是自定義布局并且需要處理互動事件,可以通過設定

setBuildChildListener

并實作其回調,并在回調接口中建立子View并處理互動事件,使用起來還是很友善的。

3、統一管理多個Dialog依次彈出
SYDialog.Builder builder1 = new SYDialog.Builder(this);

SYDialog.Builder builder2 = new SYDialog.Builder(this)
//添加第一個Dialog

SYDialogsManager.getInstance().requestShow(new DialogWrapper(builder1));
//添加第二個Dialog

SYDialogsManager.getInstance().requestShow(new DialogWrapper(builder2));
           

DialogWrapper

 來包裝一層

Dialog

,友善後續添加資料資訊。

SYDialogsManager

通過單例來實作,確定隻有一個執行個體,内部有一個容器隊列

ConcurrentLinkedQueue

來儲存多個

Dialog

requestShow()

方法中首先會判斷目前是否有正在顯示的彈窗,如果有,則在隊列中等待,否則從隊列中取出并展示,并在隊列中清空該資料,當一個

Dialog

展示完畢,會繼續嘗試在隊列中取出

Dialog

并展示,直到隊列是空為止。

六、源碼位址

上述例子源碼:

https://github.com/crazyqiang/AndroidStudy

原文釋出時間為:2018-09-26

本文作者:mmmqqq

本文來自雲栖社群合作夥伴“

安卓巴士Android開發者門戶

”,了解相關資訊可以關注“

”。

繼續閱讀