DialogFragment——...
本⽂旨在介绍Android中的两种弹窗PopupWindow和Dialog的区别。以及关于写代码的⼀些思考。
其实之前各类弹窗,都是使⽤PopupWindow来实现的。因为PopupWindow能实现这些需求,虽然有的时候有些⿇烦,⽐如前⾯的⽂章有写到PopupWindow去实现蒙版遮罩的问题。它本⾝是没有蒙版提供的。
我们项⽬中使⽤各种⽅法去给它增加遮盖层。如今看来确实是有些愚蠢的。我不介意说出以前存在的问题,因为发现问题并改进问题才是学习的过程。当然也希望看到这篇⽂章的⼩伙伴有⾃⼰的想法可以多多沟通,如果也有跟过去的我⼀样盲⽬的使⽤PopupWindow来做需求的同学,可以从这篇⽂章中学到东西。
这次遇到PopupWindow中的输⼊框⽆法复制粘贴,惯例先去⽹上搜了⼀下,发现很多⼈遇到同样的问题,解决⽅案全部都是换成DialogFragment就好了。得到这个结果后我有点不服⽓,为啥我PopupWindow复制粘贴就不⾏,为啥就⾮得换成DialogFragment。关于为啥PopupWindow复制粘贴不⾏,我开始各种搜索,也去学习了⼀下长按复制粘贴的源码,但是感觉⾃⼰的智商不是很够,到现在也没弄明⽩到底为啥不⾏。如果有知道的⼩伙伴希望不吝赐教。
通过这个问题我开始思考,为什么我不管什么弹窗类的需求都⽤PopupWindow来实现,到底它有啥好的?既然它这么好,那dialog存在的意义⼜是什么呢。其实以前的做法说⽩了,就是有项⽬⾥有了⼀套没什么问题的类似代码以后,再来相关的需求,不外乎就是复制粘贴去实现。所以就导致了⼀直⽤PopupWindow的这个问题。其实在⽤的时候,尤其是在强⾏给PopupWindow加⼊灰⾊蒙版的时候,我就有个疑问,为什么PopupWindow不⾃带蒙版,还要⾃⼰去实现,⽽且⽹上处理这类问题的⽂章并不多。这次真的想弄明⽩官⽅为什么要提供两种弹窗以后,这些疑惑也就想通了。
简单介绍:
Dialog
默认带灰⾊遮盖层,会覆盖整个屏幕,使dialog下层的内容不可点击,只有先取消dialog才能继续点击其他内容。
所以当你的需求,是需要⼀个灰⾊覆盖层的时候,优先考虑使⽤Dialog。
Dialog可以指定显⽰在屏幕个各个位置,可以通过设置偏移实现显⽰在屏幕的某个位置上。
灰⾊蒙层的透明度可控,展⽰位置可控,页⾯布局可控。
AlertDialog
没啥说的,是Dialog的⼀个⼦类,就是为了更⽅便使⽤⽽存在的。
DialogFragment
⾕歌官⽹推荐的Dialog实现⽅式,使⽤这个可以让Dialog的⽣命周期可控。
PopupWindow
不带灰⾊遮盖层,可以显⽰在屏幕的任意位置,也可以基于某个view的位置显⽰。
其他能实现的功能基本与dialog⼀致。所以其实这两个确实是可以互相替代的。
总结,我的理解:
⼀般来说,我们开发需求的时候很少会使⽤到系统⾃带的样式,基本上都需要⾃定义样式的。在这⼀点上,Dialog和PopupWindow并没什么区别,都是可以做到的。
1.那么通常当需求中需要实现灰⾊蒙版的时候,建议使⽤DialogFragment实现,⾃带蒙版。
2.当需求的弹窗⾥⾯有输⼊框的时候,建议使⽤DialogFragment(因为⼀般正常都需要⽀持复制粘贴的)
3.如果需求是要求基于某个view的位置去显⽰,那么建议使⽤PopupWindow。如果不带蒙版效果,建议使⽤PopupWindow。
具体情况还是具体分析啦。不过通过这次让我明⽩⼀个道理,官⽅提供的同类View是针对不同情况下存在更合适使⽤的。虽然很多功能我们通过⼀套逻辑就能实现,但是还是应该多去思考⼀下不同的实现⽅式到底有什么不同,选⼀个更合适更合理的⽅法。
下⾯附⼀下我学习了DialogFragment后,对它的⼀个简单基类封装,旨在对同类弹窗的⼀个封装,减少每个弹窗都要去初始化dialog代码,让⼦类只需要处理业务逻辑。
```
/**
* 基于DialogFragment实现的dialog基类(⽬的:基类完成初始化弹窗等⼀些配置⼯作,⼦类做逻辑处理)
* 通过实现getLayoutId()返回布局⽂件,实现⾃定义布局
* 通过实现initView()完成布局初始化。
* 通过调⽤ show(FragmentManager manager, String tag) ⽅法展⽰弹窗。
* DialogFragment的dismiss处理了fragment的移除操作,因此每次使⽤时直接New对象即可,不需考虑复⽤问题(亲试:考虑的话会存在⼀些问题)。
*
* 可配置,弹窗位置(当居顶部显⽰的时候,可配置距顶部的百分⽐setMarginTop)
* 可配置是否可取消
* 可配置灰⾊蒙版透明度
*
* Time:2021/2/4
* Author:yang.dong
*/
public abstract class BaseDialogFragmentextends DialogFragment {
protected ViewmLayout;
private AlertDialogdialog;
@NonNull
@Override
public DialogonCreateDialog(@Nullable Bundle savedInstanceState) {
if(dialog ==null){
AlertDialog.Builder builder =new AlertDialog.Builder(getActivity());
alertdialog使用方法LayoutInflater inflater = getActivity().getLayoutInflater();
mLayout = inflater.inflate(getLayoutId(), null);
builder.setView(mLayout);
dialog = ate();
Window dialogWindow =Window();
WindowManager.LayoutParams lp = Attributes();
dialogWindow.setDimAmount(alpha); //设置灰⾊遮盖层的透明度
dialogWindow.setBackgroundDrawableResource(ansparent); //dialog会有默认背景,设置透明后,可以完美展⽰⾃⼰的布局
dialogWindow.setGravity(gravity); //设置居顶部显⽰
if(gravity == Gravity.TOP){//距离屏幕顶部
Display d = getActivity().getWindowManager().getDefaultDisplay(); // 获取屏幕宽、⾼⽤
lp.y = (int)(d.getHeight() *marginTop); // 新位置Y坐标
}
dialogWindow.setAttributes(lp);
dialog.setCanceledOnTouchOutside(cancelable);
}
initView();
return dialog;
}
@Override
public void show(FragmentManager manager, String tag) {
//防⽌重复添加fragment崩溃
FragmentTransaction transaction = manager.beginTransaction();
Fragment fragment = manager.findFragmentByTag(tag);
if(fragment !=null){
}
transactionmit();
super.show(manager, tag);
}
private float alpha =0.3f;
private float marginTop =0.3f; // 距离顶部的⾼度(当Gravity为top时,⽣效)
private int gravity = Gravity.TOP;
private boolean cancelable =false; //点击灰⾊区域是否可以取消,默认不取消
private void setAlpha(float alpha){
this.alpha = alpha;
}
protected void setMarginTop(float marginTop){
this.marginTop = marginTop;
}
protected void setGravity(int gravity){//Gravity.TOP
}
protected void setCancel(boolean cancelable){//Gravity.TOP
this.cancelable = cancelable;
}
protected abstract int getLayoutId();
protected abstract void initView();
}
```
另外在使⽤的过程中,遇到两个问题:
1.⼀直觉得在实例化对象的时候(也就是点击按钮出现弹窗的时候),不应该每次都去创建fragment实例,⽽应该去判⼀个空,创建过⼀次以后,再次点击就只去修改UI。之前使⽤PopupWindow的时候⼀直采⽤这种做法。但是这次真的是,去这样处理感觉给⾃⼰挖了⼀个好⼤的坑。具体现象就是,第⼆次点击后UI⽆法正常刷新。
尝试解决了好久,最后我妥协了。还是每次都去new⼀个新的吧!也去看了⼀下dismiss⽅法的源码,dismiss后是会把fragment给移除掉的。并且在Profiler中去观察了我疯狂点击按钮,⼀直出弹窗的情况下内存变化。确实真的没啥变化。放⼼去new就好了。(欢迎指教)
2.快速点击导致闪退。其实这个问题我是为了解决第⼀个问题,在⽹上答案的时候,看别⼈使⽤这个遇到的坑,说快速连着点两下就会闪退。我试了⼀下 , 果然特喵的闪退了。还真的是。。。我想不出来当时的⼼情。感觉这种问题真的不该我们来处理的。⼀个⽅案是别⼈帮我踩的坑,如上对show()⽅法的⼀个重写。重写了以后连续点两次以后确实不闪退了。不过感觉体验也不是特别好,弹窗还是
会出现两次,第⼀个先消失然后出现第⼆个。所以我⼜给点击事件加上了防⽌连续点击的处理。两⼿准备吧算是~
这次的分享就到这⾥啦,欢迎指教,⼤家加油哦
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论