Android 擼起袖子,自己封裝 DialogFragment

前言

具體的代碼以及示例我都放上 Github 了,有需要的朋友可以去看一下 DialogFragmentDemos,歡迎 star 和 fork.

本文的主要內容

  • DialogFragment 是什么
  • 創建通用的 CommonDialogFragment
  • 實現各種類型的 DialogFragment

在寫正文之前,先來一波效果展示吧
DialogFragmentDemos.gif

一、DialogFragment 是什么

DialogFragment 在 Android 3.0 時被引入,是一種特殊的 Fragment,用于在 Activity 的內容之上顯示一個靜態的對話框。例如:警告框、輸入框、確認框等。

1、DialogFragment 的優點

其實在 Android 中顯示對話框有兩種類型可供使用,一種是 DialogFragment,而另一種則是 Dialog。在 DialogFragment 產生之前,我們創建對話框一般采用 Dialog,而且從代碼的編寫角度來看,Dialog 使用起來其實更加簡單,但是 Google 卻是推薦盡量使用 DialogFragment,是不是感覺很奇怪,其實原因也很簡單, DialogFragment 有著 Dialog 所沒有的非常好的特性

  • DialogFragment 本身是 Fragment 的子類,有著和 Fragment 基本一樣的生命周期,使用 DialogFragment 來管理對話框,當旋轉屏幕和按下后退鍵的時候可以更好的管理其生命周期
  • 在手機配置變化導致 Activity 需要重新創建時,例如旋轉屏幕,基于 DialogFragment 的對話框將會由 FragmentManager 自動重建,然而基于 Dialog 實現的對話框卻沒有這樣的能力

2、DialogFragment 的使用

使用 DialogFragment 至少需要實現 onCreateView() 或者 onCreateDialog() 方法,onCreateView() 即使用自定義的 xml 布局文件來展示 Dialog,而 onCreateDialog() 即使用 AlertDialog 或者 Dialog 創建出 我們想要的 Dialog,因為這篇文章主要是講 DialogFragment 的封裝,至于 DialogFragment 具體的使用,可以參考下洋神的這篇文章 Android 官方推薦 : DialogFragment 創建對話框

二、創建通用的 CommonDialogFragment

這個類是 DialogFragment 的子類,對 DialogFragment 進行封裝,依賴外部傳入的 AlertDialog 來構建,同時也處理了 DialogFragment 中 AlertDialog 不能設置外部取消的問題

public class CommonDialogFragment extends DialogFragment {/*** 監聽彈出窗是否被取消*/private OnDialogCancelListener mCancelListener;/*** 回調獲得需要顯示的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以下的版本會出現白色背景邊框,若在5.0以上設置則會造成文字部分的背景也變成透明if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {//目前只有這兩個dialog會出現邊框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,前者用于監聽彈出窗是否被取消,后者則可以讓我們回調獲得想要顯示的 Dialog,可以看到在 onCreateDialog() 中我們返回的 是 mOnCallDialog.getDialog(getActivity);,當我們在傳入 Dialog 的時候,便會回調到此處,讓 onCreateDialog() 返回我們傳入的 Dialog,對接口回調不是很清楚的朋友,可以看下這篇文章 一個經典例子讓你徹徹底底理解java回調機制

接著在 onStart() 中進行了一些特殊性的處理,因為在 5.0 以下的版本,ProgressDialog 和 DatePickerDialog 會出現白色的邊框,這使得用戶體驗非常不好,所以我們要在此處進行相應的處理

最后便是封裝我們的構造函數
newInstance(OnCallDialog call, boolean cancelable, OnDialogCancelListener cancelListener),當我們要使用這個 CommonDialogFragment 的時候,先 new 一個 OnCallDialog,將我們想要顯示的 Dialog 傳進去,cancelable,用于設置對話框是否能被取消,可以看到在 onCancel() 有這樣一段代碼

if(mCancelListener != null){mCancelListener.onCancel();
}

這便是我們在構造函數中傳入 OnCancelListener 的原因,當我們想要做一些取消對話框后的處理時,只要在構造函數中傳入 OnCancelListener,實現 onCancel() 方法就行了

三、實現各種類型的 DialogFragment

既然前面我們創建了 CommonFragment 作為所有 DialogFragment 的基類,那么接下來我們當然要好好地來實現各種類型的 DialogFragment 了,我的思路是創建一個 DialogFragmentHelper 作為實現提示框的幫助類,幫我們把代碼都封裝起來,使用的時候只需要關注與 AlertDialog 的交互,Helper 會幫助我們用 DialogFragment 來進行顯示,這樣既能統一整個應用的 Dialog 風格,又能讓我們實現各種各樣的對話框變得相當的簡單

在實現 DialogFragmentHelper 之前我們有兩件事先要做一下

1、在 styles 文件中定義我們定義我們對話框的風格樣式
<style name="Base_AlertDialog" parent="Base.Theme.AppCompat.Light.Dialog"><!--不設置在6.0以上會出現,寬度不充滿屏幕的情況--><item name="windowMinWidthMinor">90%</item><!-- 取消標題欄,如果在代碼中settitle的話會無效 --><item name="android:windowNoTitle">true</item><!-- 標題的和Message的文字顏色 --><!--<item name="android:textColorPrimary">@color/black</item>--><!-- 修改頂部標題背景顏色,具體顏色自己定,可以是圖片 --><item name="android:topDark">@color/app_main_color_deep</item><!--<item name="android:background">@color/white</item>--><!-- 在某些系統上面設置背景顏色之后出現奇怪的背景,處這里設置背景為透明,為了隱藏邊框 --><!--<item name="android:windowBackground">@android:color/transparent</item>--><!--<item name="android:windowFrame">@null</item>--><!-- 進入和退出動畫,左進右出(系統自帶) --><!--<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>--><!-- 按鈕字體顏色,全部一起改,單個改需要在Java代碼中修改 --><item name="colorAccent">@color/app_main_color</item></style>

我已經打上了詳細的注釋,相信應該很容易理解

2、寫一個接口,用于 DialogFragmentHelper 與邏輯層之間進行數據監聽
public interface IDialogResultListener<T> {void onDataResult(T result);
}

準備工作做完了,就讓我們開工擼 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);}
}

可以看到因為我們實現封裝了 CommonFragment,所有這些效果的實現都變得相當的簡單嗎,這便是封裝給我們帶來的便利和好處。

就以 加載中的彈出窗 為例,來看看我們是怎么實現的

    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;}

我們先調用了 CommonDialogFragment 的構造函數,將一個 ProgressDialog 傳進去,然后依次傳入 cancelable 和 cancelListener,最后調用 show() 函數,將DialogFragment 顯示出來,因為我們使用了構造函數的重載,可以看到最簡單的構造函數只需要傳入兩個參數就行了,是不是相當的簡潔啊。

應該還沒忘了我們上面創建了一個 IDialogResultListener&lt;T&gt; 用于 DialogFragment 與邏輯層之間進行數據監聽吧,為了能傳入各種各樣類型的數據,這里我使用了 泛型 來進行處理,就以 帶輸入框的彈出窗 為例來看看究竟要怎么使用吧

    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&lt;String&gt; resultListener,當我們想要處理輸入的內容的時候,只要在外部調用的時候,new 一個IDialogResultListener 傳進去,然后實現 onDataResult() 方法就行了

以上便是全文的內容,具體的代碼以及示例我都放上 Github 了,有需要的朋友可以去看一下 DialogFragmentDemos,如果覺得對你有所幫助的話,就賞個 star 吧!


猜你喜歡

  • 手把手教你從零開始做一個好看的 APP
  • Android 能讓你少走彎路的干貨整理
  • Android 一款十分簡潔、優雅的日記 APP

轉載于:https://blog.51cto.com/11365063/2072445

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/539390.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/539390.shtml
英文地址,請注明出處:http://en.pswp.cn/news/539390.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

as模擬器文件夾路徑_EGG Switch手機模擬器怎么用?中文教程來了......

大家好&#xff0c;小雞妹我又來啦。自從昨天曝光了美國NX工作室的EGG模擬器之后&#xff0c;推文底下就多了一千多條留言&#xff0c;說啥的都有。不過小雞妹大概總結了一下&#xff0c;發現下面這幾條問題&#xff0c;出現的頻率最高&#xff1a;① 找不到網址&#xff1b;②…

xml文件c語言讀取函數,讀寫xml文件的2個小函數

#region 讀寫xml文件的2個小函數&#xff0c;2005 4 2 by hycpublic void SetXmlFileValue(string xmlPath,string AppKey,string AppValue)//寫xmlPath是文件路徑文件名&#xff0c;AppKey是 Key Name&#xff0c;AppValue是Value{XmlDocument xDoc new XmlDocument();xDoc.L…

Java導入導出Excel工具類ExcelUtil

前段時間做的分布式集成平臺項目中&#xff0c;許多模塊都用到了導入導出Excel的功能&#xff0c;于是決定封裝一個ExcelUtil類&#xff0c;專門用來處理Excel的導入和導出 本項目的持久化層用的是JPA&#xff08;底層用hibernate實現&#xff09;&#xff0c;所以導入和導出也…

郁金香匯編代碼注入怎么寫看雪_世界黑客編程大賽冠軍的匯編代碼 你見過嗎?...

前幾天發布了一篇“雷軍22年前寫的匯編代碼”的文章&#xff0c;引起網友的熱議。有人說匯編是最牛逼的編程語言&#xff0c;沒有之一。匯編語言確實厲害&#xff0c;不知道你有沒有見過世界黑客編程大賽冠軍的作品?雷軍編寫的的匯編代碼有 網友分享了97年Mekka ’97 4K Intro…

變位齒輪重合度計算公式_齒輪“模數”是如何計算的?

模數是決定齒輪大小的因素。齒輪模數被定義為模數制輪齒的一個基本參數&#xff0c;是人為抽象出來用以度量輪齒規模的數。目的是標準化齒輪刀具&#xff0c;減少成本。直齒、斜齒和圓錐齒齒輪的模數皆可參考標準模數系列表。工業定義&#xff1a;齒輪的分度圓是設計、計算齒輪…

c語言改錯和填空能運行嗎,C語言改錯填空編程

改錯題1、在考生文件夾下&#xff0c;給定程序MODI.C的功能是&#xff1a;從低位開始取出長整型變量s中奇數位上的數&#xff0c;依次構成一個新數放在t中。例如&#xff0c;當s中的數為&#xff1a;7654321時&#xff0c;t中的數為&#xff1a;7531。請修改并運行該程序&#…

@Autowired注解實現原理

在討論代碼細節之前&#xff0c;我們再來了解下基礎知識。Spring管理可用于整個應用程序的Java對象bean。他們所在的Spring容器&#xff0c;被稱為應用程序上下文。這意味著我們不需要處理他們的生命周期(初始化&#xff0c;銷毀)。該任務由此容器來完成。另外&#xff0c;該上…

獲取freemarker處理后的內容

相信很多人都用過freemarker&#xff0c;或做視圖&#xff0c;或模板&#xff0c;或生成靜態文件等,但是有多少人做過這樣的應用&#xff0c;通過模板后&#xff0c;不是要輸出靜態的內容&#xff0c;而是直接在代碼中獲取處理模板后的內容&#xff0c;研究了下API,freemarker里…

c4.5算法python實現_算法:用Python實現—最優化算法

今天給大家分享一下算法&#xff0c;用python來實現最優化算法。廢話不多說&#xff0c;直接上代碼&#xff1a;一、二分法函數詳見rres&#xff0c;此代碼使該算法運行了兩次def asdf(x): rres8*x**3-2*x**2-7*x3 return rresi2left0right1while i>0 : i i-1 …

comsol臨時文件夾中有不支持的字符_文件名中不能包含的字符

文件名是為了方便人們區分計算機中的不同文件&#xff0c;而給每個文件設定一個指定的名稱。由文件主名和擴展名組成。DOS操作系統規定文件名由文件主名和擴展名組成&#xff0c;文件主名由1~8個字符組成&#xff0c;擴展名由1~3個字符組成&#xff0c;主名和擴展名之間由一個小…

linux 星號 通配符,如何在bash中轉義通配符/星號字符?

簡短的回答像其他人所說的那樣 - 你應該總是引用變量來防止奇怪的行為。所以使用echo“$ foo”代替echo $ foo。長期回答我確實認為這個例子值得進一步解釋&#xff0c;因為它的表面看起來比它看起來更多。我可以看到你的困惑在哪里&#xff0c;因為在你運行你的第一個例子后&a…

PYTHON面試

大部分的面試問題&#xff0c;有最近要找事的老鐵嗎&#xff1f;python語法以及其他基礎部分可變與不可變類型&#xff1b; 淺拷貝與深拷貝的實現方式、區別&#xff1b;deepcopy如果你來設計&#xff0c;如何實現&#xff1b; __new__() 與 __init__()的區別&#xff1b; 你知…

vs怎么更改編譯的堆空間_再見吧 buildSrc, 擁抱 Composing builds 提升 Android 編譯速度...

前言長期以來困擾我們的一個問題就是構建速度&#xff0c;AndroidStudio 的構建速度嚴重影響 Android 開發者的工作效率&#xff0c;尤其是更新一個版本號&#xff0c;導致整個項目重新構建&#xff0c;在網絡慢的情況下&#xff0c;這是無法忍受的。buildSrc 這種方式&#xf…

java map的遍歷

轉載地址&#xff1a;http://www.cnblogs.com/shenliang123/archive/2012/08/28/2660705.html -------------------------------------------------------------------------------------------------------------------- java中的遍歷 import java.util.Collection; import j…

python循環for...in_python循環while和forin實例

python 循環while和for in簡單實例#!/uer/bin/env python# _*_ coding: utf-8 _*_lucknumber 5b 0while b <3:print(guss count:,b)a int(input(you guse number))if a > lucknumber:print (youaerbiger)elif a lucknumber:print (youare righet)break #跳出這個層級…

android懸浮功能實現,Android實現系統級懸浮按鈕

本文實例為大家分享了Android系統級懸浮按鈕的具體代碼&#xff0c;供大家參考&#xff0c;具體內容如下具體的需求1、就是做一個系統級的懸浮按鈕&#xff0c;就像iPhone 桌面的那個懸浮按鈕效果一樣&#xff0c;能隨意拖動&#xff0c;并且手一放開&#xff0c;懸浮按鈕就自動…

oracle decode_錯過血虧!一文搞懂Oracle鎖相關視圖及相關操作

本文主要研究鎖的相關視圖&#xff0c;以及鎖的相關操作&#xff0c;通過視圖查鎖的問題。 一、v$transaction視圖第一個視圖是v$transaction&#xff0c;就是Oracle數據庫所有活動的事務數&#xff0c;所有活動的事務每一個活動的事務在這里有一行。v$transactionXIDUSN表示當…

Linux文件系統與命令行

什么是命令行? 接收鍵盤命令并將其傳給操作系統執行的程序(用于輸入和管理命令的程序),統稱命令行,也叫: Shell&#xff0c;幾乎所有Linux發行版都提供了一個 Shell 程序,叫做: Bash (Bourne-Again Shell, 因為最初的 Shell 是由 Steve Bourne 編寫的原始 Unix 程序, Again 表…

freeMarker 遍歷 list,map,listmap

List List<String> clientSourceDatanew ArrayList<String>();clientSourceData.add("field字段");clientSourceData.add("title標題");ftl&#xff1a; <#if clientSourceData?exists><#list clientSourceData as key> <tr&g…

qtableview不選中_如何選中/取消選中QTableView并觸發setData()

我有一個自定義的QTableModel&#xff0c;我在PyQt中使用QTableView顯示它。我有一些字段設置為可檢查&#xff0c;我想添加“全部檢查”和“不檢查”按鈕。我覺得應該有一種方法可以使setData()從代碼中被調用&#xff0c;這樣檢查狀態就會改變&#xff0c;就像我已經用setDat…