Android 撸起袖子,自己封装 DialogFragment
前言
具體的代碼以及示例我都放上 Github 了,有需要的朋友可以去看一下 DialogFragmentDemos,歡迎 star 和 fork.
本文的主要內(nèi)容
- DialogFragment 是什么
- 創(chuàng)建通用的 CommonDialogFragment
- 實現(xiàn)各種類型的 DialogFragment
在寫正文之前,先來一波效果展示吧
一、DialogFragment 是什么
DialogFragment 在 Android 3.0 時被引入,是一種特殊的 Fragment,用于在 Activity 的內(nèi)容之上顯示一個靜態(tài)的對話框。例如:警告框、輸入框、確認(rèn)框等。
1、DialogFragment 的優(yōu)點
其實在 Android 中顯示對話框有兩種類型可供使用,一種是 DialogFragment,而另一種則是 Dialog。在 DialogFragment 產(chǎn)生之前,我們創(chuàng)建對話框一般采用 Dialog,而且從代碼的編寫角度來看,Dialog 使用起來其實更加簡單,但是 Google 卻是推薦盡量使用 DialogFragment,是不是感覺很奇怪,其實原因也很簡單, DialogFragment 有著 Dialog 所沒有的非常好的特性
- DialogFragment 本身是 Fragment 的子類,有著和 Fragment 基本一樣的生命周期,使用 DialogFragment 來管理對話框,當(dāng)旋轉(zhuǎn)屏幕和按下后退鍵的時候可以更好的管理其生命周期
- 在手機配置變化導(dǎo)致 Activity 需要重新創(chuàng)建時,例如旋轉(zhuǎn)屏幕,基于 DialogFragment 的對話框?qū)?FragmentManager 自動重建,然而基于 Dialog 實現(xiàn)的對話框卻沒有這樣的能力
2、DialogFragment 的使用
使用 DialogFragment 至少需要實現(xiàn) onCreateView() 或者 onCreateDialog() 方法,onCreateView() 即使用自定義的 xml 布局文件來展示 Dialog,而 onCreateDialog() 即使用 AlertDialog 或者 Dialog 創(chuàng)建出 我們想要的 Dialog,因為這篇文章主要是講 DialogFragment 的封裝,至于 DialogFragment 具體的使用,可以參考下洋神的這篇文章 Android 官方推薦 : DialogFragment 創(chuàng)建對話框
二、創(chuàng)建通用的 CommonDialogFragment
這個類是 DialogFragment 的子類,對 DialogFragment 進行封裝,依賴外部傳入的 AlertDialog 來構(gòu)建,同時也處理了 DialogFragment 中 AlertDialog 不能設(shè)置外部取消的問題
public class CommonDialogFragment extends DialogFragment {/*** 監(jiān)聽彈出窗是否被取消*/private OnDialogCancelListener mCancelListener;/*** 回調(diào)獲得需要顯示的dialog*/private OnCallDialog mOnCallDialog;public interface OnDialogCancelListener {void onCancel();}public interface OnCallDialog {Dialog getDialog(Context context);}public static CommonDialogFragment newInstance(OnCallDialog call, boolean cancelable) {return newInstance(call, cancelable, null);}public static CommonDialogFragment newInstance(OnCallDialog call, boolean cancelable, OnDialogCancelListener cancelListener) {CommonDialogFragment instance = new CommonDialogFragment();instance.setCancelable(cancelable);instance.mCancelListener = cancelListener;instance.mOnCallDialog = call;return instance;}@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {if (null == mOnCallDialog) {super.onCreateDialog(savedInstanceState);}return mOnCallDialog.getDialog(getActivity());}@Overridepublic void onStart() {super.onStart();Dialog dialog = getDialog();if (dialog != null) {//在5.0以下的版本會出現(xiàn)白色背景邊框,若在5.0以上設(shè)置則會造成文字部分的背景也變成透明if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {//目前只有這兩個dialog會出現(xiàn)邊框if(dialog instanceof ProgressDialog || dialog instanceof DatePickerDialog) {getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));}}Window window = getDialog().getWindow();WindowManager.LayoutParams windowParams = window.getAttributes();windowParams.dimAmount = 0.0f;window.setAttributes(windowParams);}}@Overridepublic void onCancel(DialogInterface dialog) {super.onCancel(dialog);if (mCancelListener != null) {mCancelListener.onCancel();}}}可以看到這個類的代碼量也是很少的,先定義了兩個接口 OnDialogCancelListener,OnCallDialog,前者用于監(jiān)聽彈出窗是否被取消,后者則可以讓我們回調(diào)獲得想要顯示的 Dialog,可以看到在 onCreateDialog() 中我們返回的 是 mOnCallDialog.getDialog(getActivity);,當(dāng)我們在傳入 Dialog 的時候,便會回調(diào)到此處,讓 onCreateDialog() 返回我們傳入的 Dialog,對接口回調(diào)不是很清楚的朋友,可以看下這篇文章 一個經(jīng)典例子讓你徹徹底底理解java回調(diào)機制
接著在 onStart() 中進行了一些特殊性的處理,因為在 5.0 以下的版本,ProgressDialog 和 DatePickerDialog 會出現(xiàn)白色的邊框,這使得用戶體驗非常不好,所以我們要在此處進行相應(yīng)的處理
最后便是封裝我們的構(gòu)造函數(shù)
newInstance(OnCallDialog call, boolean cancelable, OnDialogCancelListener cancelListener),當(dāng)我們要使用這個 CommonDialogFragment 的時候,先 new 一個 OnCallDialog,將我們想要顯示的 Dialog 傳進去,cancelable,用于設(shè)置對話框是否能被取消,可以看到在 onCancel() 有這樣一段代碼
這便是我們在構(gòu)造函數(shù)中傳入 OnCancelListener 的原因,當(dāng)我們想要做一些取消對話框后的處理時,只要在構(gòu)造函數(shù)中傳入 OnCancelListener,實現(xiàn) onCancel() 方法就行了
三、實現(xiàn)各種類型的 DialogFragment
既然前面我們創(chuàng)建了 CommonFragment 作為所有 DialogFragment 的基類,那么接下來我們當(dāng)然要好好地來實現(xiàn)各種類型的 DialogFragment 了,我的思路是創(chuàng)建一個 DialogFragmentHelper 作為實現(xiàn)提示框的幫助類,幫我們把代碼都封裝起來,使用的時候只需要關(guān)注與 AlertDialog 的交互,Helper 會幫助我們用 DialogFragment 來進行顯示,這樣既能統(tǒng)一整個應(yīng)用的 Dialog 風(fēng)格,又能讓我們實現(xiàn)各種各樣的對話框變得相當(dāng)?shù)暮唵?/p>
在實現(xiàn) DialogFragmentHelper 之前我們有兩件事先要做一下
1、在 styles 文件中定義我們定義我們對話框的風(fēng)格樣式
<style name="Base_AlertDialog" parent="Base.Theme.AppCompat.Light.Dialog"><!--不設(shè)置在6.0以上會出現(xiàn),寬度不充滿屏幕的情況--><item name="windowMinWidthMinor">90%</item><!-- 取消標(biāo)題欄,如果在代碼中settitle的話會無效 --><item name="android:windowNoTitle">true</item><!-- 標(biāo)題的和Message的文字顏色 --><!--<item name="android:textColorPrimary">@color/black</item>--><!-- 修改頂部標(biāo)題背景顏色,具體顏色自己定,可以是圖片 --><item name="android:topDark">@color/app_main_color_deep</item><!--<item name="android:background">@color/white</item>--><!-- 在某些系統(tǒng)上面設(shè)置背景顏色之后出現(xiàn)奇怪的背景,處這里設(shè)置背景為透明,為了隱藏邊框 --><!--<item name="android:windowBackground">@android:color/transparent</item>--><!--<item name="android:windowFrame">@null</item>--><!-- 進入和退出動畫,左進右出(系統(tǒng)自帶) --><!--<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>--><!-- 按鈕字體顏色,全部一起改,單個改需要在Java代碼中修改 --><item name="colorAccent">@color/app_main_color</item></style>我已經(jīng)打上了詳細(xì)的注釋,相信應(yīng)該很容易理解
2、寫一個接口,用于 DialogFragmentHelper 與邏輯層之間進行數(shù)據(jù)監(jiān)聽
public interface IDialogResultListener<T> {void onDataResult(T result); }準(zhǔn)備工作做完了,就讓我們開工擼 DialogFragmentHelper 吧,因為篇幅有限,我只是代表性的選了其中的一些效果來講,具體的代碼,可以參考下 DialogFragmentDemos
public class DialogFragmentHelper {private static final String TAG_HEAD = DialogFragmentHelper.class.getSimpleName();/*** 加載中的彈出窗*/private static final int PROGRESS_THEME = R.style.Base_AlertDialog;private static final String PROGRESS_TAG = TAG_HEAD + ":progress";public static CommonDialogFragment showProgress(FragmentManager fragmentManager, String message){return showProgress(fragmentManager, message, true, null);}public static CommonDialogFragment showProgress(FragmentManager fragmentManager, String message, boolean cancelable){return showProgress(fragmentManager, message, cancelable, null);}public static CommonDialogFragment showProgress(FragmentManager fragmentManager, final String message, boolean cancelable, CommonDialogFragment.OnDialogCancelListener cancelListener){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {ProgressDialog progressDialog = new ProgressDialog(context, PROGRESS_THEME);progressDialog.setMessage(message);return progressDialog;}}, cancelable, cancelListener);dialogFragment.show(fragmentManager, PROGRESS_TAG);return dialogFragment;}/*** 帶輸入框的彈出窗*/private static final int INSERT_THEME = R.style.Base_AlertDialog;private static final String INSERT_TAG = TAG_HEAD + ":insert";public static void showInsertDialog(FragmentManager manager, final String title, final IDialogResultListener<String> resultListener, final boolean cancelable){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {// ...AlertDialog.Builder builder = new AlertDialog.Builder(context, INSERT_THEME);builder.setPositiveButton(DIALOG_POSITIVE, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if(resultListener != null){resultListener.onDataResult(editText.getText().toString());}}});builder.setNegativeButton(DIALOG_NEGATIVE, null);return builder.create();}}, cancelable, null);dialogFragment.show(manager, INSERT_TAG);} }可以看到因為我們實現(xiàn)封裝了 CommonFragment,所有這些效果的實現(xiàn)都變得相當(dāng)?shù)暮唵螁?#xff0c;這便是封裝給我們帶來的便利和好處。
就以 加載中的彈出窗 為例,來看看我們是怎么實現(xiàn)的
public static CommonDialogFragment showProgress(FragmentManager fragmentManager, final String message, boolean cancelable, CommonDialogFragment.OnDialogCancelListener cancelListener){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {ProgressDialog progressDialog = new ProgressDialog(context, PROGRESS_THEME);progressDialog.setMessage(message);return progressDialog;}}, cancelable, cancelListener);dialogFragment.show(fragmentManager, PROGRESS_TAG);return dialogFragment;}我們先調(diào)用了 CommonDialogFragment 的構(gòu)造函數(shù),將一個 ProgressDialog 傳進去,然后依次傳入 cancelable 和 cancelListener,最后調(diào)用 show() 函數(shù),將DialogFragment 顯示出來,因為我們使用了構(gòu)造函數(shù)的重載,可以看到最簡單的構(gòu)造函數(shù)只需要傳入兩個參數(shù)就行了,是不是相當(dāng)?shù)暮啙嵃 ?/p>
應(yīng)該還沒忘了我們上面創(chuàng)建了一個 IDialogResultListener<T> 用于 DialogFragment 與邏輯層之間進行數(shù)據(jù)監(jiān)聽吧,為了能傳入各種各樣類型的數(shù)據(jù),這里我使用了 泛型 來進行處理,就以 帶輸入框的彈出窗 為例來看看究竟要怎么使用吧
public static void showInsertDialog(FragmentManager manager, final String title, final IDialogResultListener<String> resultListener, final boolean cancelable){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {// ... 這里省略一部分代碼AlertDialog.Builder builder = new AlertDialog.Builder(context, INSERT_THEME);builder.setPositiveButton(DIALOG_POSITIVE, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if(resultListener != null){resultListener.onDataResult(editText.getText().toString());}}});builder.setNegativeButton(DIALOG_NEGATIVE, null);return builder.create();}}, cancelable, null);dialogFragment.show(manager, INSERT_TAG);}可以看到我們在 showInsertDialog() 方法中傳入了IDialogResultListener<String> resultListener,當(dāng)我們想要處理輸入的內(nèi)容的時候,只要在外部調(diào)用的時候,new 一個IDialogResultListener 傳進去,然后實現(xiàn) onDataResult() 方法就行了
以上便是全文的內(nèi)容,具體的代碼以及示例我都放上 Github 了,有需要的朋友可以去看一下 DialogFragmentDemos,如果覺得對你有所幫助的話,就賞個 star 吧!
猜你喜歡
- 手把手教你從零開始做一個好看的 APP
- Android 能讓你少走彎路的干貨整理
- Android 一款十分簡潔、優(yōu)雅的日記 APP
轉(zhuǎn)載于:https://blog.51cto.com/11365063/2072445
總結(jié)
以上是生活随笔為你收集整理的Android 撸起袖子,自己封装 DialogFragment的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: keepalived配置高可用集群
- 下一篇: JavaSE基础知识学习-----泛型