前言
本文已經(jīng)收錄到我的 Github 個(gè)人博客嚷堡,歡迎大佬們光臨寒舍:
思維導(dǎo)圖
一琳水、為什么要學(xué)習(xí) DialogFragment
你還在用 Dialog
嗎几颜?
你還在經(jīng)常煩惱于屏幕翻轉(zhuǎn)的時(shí)候秒拔,Dialog
的各種奇葩情況嗎?
你想降低耦合嗎咽弦?
如果你有其中的一個(gè)煩惱,那么恭喜你胁出,遇見了 DialogFragment
型型,他恰巧就解決了上面所說的問題,如果感興趣的話全蝶,隨筆者來看下吧闹蒜!
二、背景
Android 官方推薦使用 DialogFragment
來代替 Dialog
抑淫,可以讓它具有更高的可復(fù)用性(降低耦合)和更好的便利性(很好的處理屏幕翻轉(zhuǎn)的情況)绷落。
而創(chuàng)建 DialogFragment
有兩種方式:
- 法一:覆寫其
onCreateDialog
方法
一般用于創(chuàng)建替代傳統(tǒng)的
Dialog
對(duì)話框的場(chǎng)景,UI 簡單始苇,功能單一,不適用于使用了多線程(例如網(wǎng)絡(luò)請(qǐng)求)的情況下(因?yàn)椴荒苷_的獲取當(dāng)前Fragment
的狀態(tài)砌烁,會(huì)產(chǎn)生空指針異常)
- 法二:覆寫其
onCreateView
方法
一般用于創(chuàng)建復(fù)雜內(nèi)容彈窗或全屏展示效果的場(chǎng)景,UI 復(fù)雜催式,功能復(fù)雜函喉,一般有網(wǎng)絡(luò)請(qǐng)求等異步操作
三避归、應(yīng)用
3.1 基本用法是什么
法一:
a.創(chuàng)建一個(gè)簡單的 Dialog
并返回它即可
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// 設(shè)置主題的構(gòu)造方法
// AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.CustomDialog);
builder.setTitle("注意:")
.setMessage("是否退出應(yīng)用?")
.setPositiveButton("確定", null)
.setNegativeButton("取消", null)
.setCancelable(false);
//builder.show(); // 不能在這里使用 show() 方法
return builder.create();
}
b.你也可以使用自定義 View
來創(chuàng)建:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// 設(shè)置主題的構(gòu)造方法
// AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.CustomDialog);
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_dialog, null);
builder.setView(view)
// Do Someting,eg: TextView tv = view.findViewById(R.id.tv);
return builder.create();
}
PS:創(chuàng)建 Dialog
的方式有多種函似,比如下面這種槐脏,使用時(shí)略有差異喉童,需要自己注意:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_dialog, null);
Dialog dialog = new Dialog(getActivity());
// 設(shè)置主題的構(gòu)造方法
// Dialog dialog = new Dialog(getActivity(), R.style.CustomDialog);
dialog.setContentView(view);
// Do Someting
return dialog;
}
這種情況撇寞,標(biāo)題內(nèi)容上面的白色部分,其實(shí)是默認(rèn)的標(biāo)題欄堂氯,如果需要的話蔑担,可以設(shè)置隱藏標(biāo)題欄(將在下文說到)
3.2 如何處理屏幕翻轉(zhuǎn)
如果使用傳統(tǒng)的 Dialog
,需要我們手動(dòng)處理屏幕翻轉(zhuǎn)的情況咽白,但使用 DialogFragment
的話啤握,則不需要我們進(jìn)行任何處理,FragmentManager
會(huì)自動(dòng)管理 DialogFragment
的生命周期晶框。
3.3 如何隱藏標(biāo)題欄
在基本用法里代碼注釋有設(shè)置主題的地方排抬,下面詳細(xì)說下兩種方法下設(shè)置無標(biāo)題欄的方式:
法一:
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = Objects.requireNonNull(getActivity()).getLayoutInflater();
@SuppressLint("InflateParams") View view = inflater.inflate(R.layout.fragment_i_o_s_dialog, null);
Dialog dialog = new Dialog(getActivity());
// 關(guān)閉標(biāo)題欄,setContentView() 之前調(diào)用
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
法二:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, 0);
}
3.4 如何實(shí)現(xiàn)全屏
常用的形式大多是寬度上和屏幕一樣寬授段,高度自適應(yīng)蹲蒲,下面直接看代碼:
法一:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_dialog, null);
Dialog dialog = new Dialog(getActivity(), 0);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(true);
//Do something
// 設(shè)置寬度為屏寬、位置靠近屏幕底部
Window window = dialog.getWindow();
//設(shè)置了窗口的背景色為透明侵贵,這一步是必須的
// <color name="transparent">#50000000</color>
window.setBackgroundDrawableResource(R.color.transparent);
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.BOTTOM;
//設(shè)置窗口的寬度為 MATCH_PARENT,效果是和屏幕寬度一樣大
wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(wlp);
return dialog;
}
法二:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, 0);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().setCanceledOnTouchOutside(true);
View rootView = inflater.inflate(R.layout.fragment_dialog, container, false);
//Do something
// 設(shè)置寬度為屏寬届搁、靠近屏幕底部。
final Window window = getDialog().getWindow();
//這步是必須的
window.setBackgroundDrawableResource(R.color.transparent);
//必要窍育,設(shè)置 padding卡睦,這一步也是必須的,內(nèi)容不能填充全部寬度和高度
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.BOTTOM;
wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(wlp);
return rootView;
}
3.5 應(yīng)用場(chǎng)景的區(qū)別是什么
文章一開始簡單總結(jié)了法一 和法二的應(yīng)用場(chǎng)景漱抓,這里說明下:
- 法一:為簡單的替代
Dialog
提供了非常方便的創(chuàng)建方式表锻,但是在使用了多線程(例如網(wǎng)絡(luò)請(qǐng)求)的情況下,不能正確的獲取當(dāng)前Fragment
的狀態(tài)乞娄,會(huì)產(chǎn)生空指針異常 - 法二:則沒有如上空指針的問題浩嫌,而且,其創(chuàng)建方式默認(rèn)使用了自定義
View
补胚,更便于應(yīng)對(duì)復(fù)雜UI
的場(chǎng)景
3.6 如何與 Activity 進(jìn)行交互码耐?
使用回調(diào)的方式
a.在 DialogFragment
中:
public interface OnDialogListener {
void onDialogClick(String person);
}
private OnDialogListener mlistener;
public void setOnDialogListener(OnDialogListener dialogListener){
this.mlistener = dialogListener;
}
在 DialogFragment
的點(diǎn)擊事件中:
public OnDialogListener mlistener;
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv1:
mlistener.onDialogClick("1");
dismiss();
break;
case R.id.tv2:
mlistener.onDialogClick("2");
dismiss();
break;
case R.id.tv3:
mlistener.onDialogClick("3");
dismiss();
break;
case R.id.tv4:
mlistener.onDialogClick("4");
dismiss();
break;
}
}
b.在 Activity
中
dialogFragment.setOnDialogListener(new PersonDialogFragment.OnDialogListener() {
@Override
public void onDialogClick(String person) {
ToastUtil.showToast(person);
}
});
3.7 如何結(jié)合動(dòng)畫使用
a.設(shè)置從下到上彈出的動(dòng)畫
private void slideToUp(View view) {
Animation slide = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0);
slide.setDuration(400);
slide.setFillEnabled(true);
slide.setFillAfter(true);
view.startAnimation(slide);
}
b.設(shè)置從上到下彈出的動(dòng)畫
private boolean isAnimation = false;//用來判斷是否多次點(diǎn)擊。防止多次執(zhí)行
public void slideToDown(View view) {
Animation slide = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 1.0f);
slide.setDuration(400);
slide.setFillEnabled(true);
slide.setFillAfter(true);
view.startAnimation(slide);
slide.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
//用來判斷是否多次點(diǎn)擊溶其。防止多次執(zhí)行
isAnimation = false;
//彈框消失
IOSDialogFragment.this.dismiss();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
c.封裝從上到下彈出的動(dòng)畫
加上判斷是否多次點(diǎn)擊骚腥。防止多次執(zhí)行
private void dialogFinish() {
if (isAnimation) {
return;
}
isAnimation = true;
slideToDown(rootView);
}
3.8 如何在 Activity 彈出 DialogFragment ?
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
IOSDialogFragment fragment = new IOSDialogFragment();
//第二個(gè)參數(shù)是 tag
fragment.show(getSupportFragmentManager(), "android");
}
});
3.9 如何點(diǎn)擊空白處時(shí)關(guān)閉的時(shí)候,還能使用動(dòng)畫瓶逃?
直接對(duì)
DecorView
設(shè)置onTouchListener
window.getDecorView().setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
//彈框消失的動(dòng)畫執(zhí)行相關(guān)代碼
....
....
}
return true;
}
});
四束铭、結(jié)語
終于看完了鴨廓块!累死鴨了!如果還有什么不是很清楚的話契沫,可以看下筆者寫的示例 Demo
如果文章對(duì)您有一點(diǎn)幫助的話带猴,希望您能點(diǎn)一下贊,您的點(diǎn)贊懈万,是我前進(jìn)的動(dòng)力
本文參考鏈接: