疫情概要
国内疫情
6月20日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例26例,其中境外输入病例1例(在福建),本土病例25例(北京22例,河北3例);无新增死亡病例;新增疑似病例3例,均为本土病例(均在北京)。
国际疫情
世界卫生组织20日公布的最新数据显示,中国以外新冠确诊病例达到8440072例。
世卫组织每日疫情报告显示,截至欧洲中部时间20日10时(北京时间16时),中国以外新冠确诊病例较前一日增加138950例,达到8440072例;中国以外死亡病例较前一日增加6271例,达到452328例。 全球范围内,新冠确诊病例较前一日增加138980例,达到8525042例;死亡病例较前一日增加6271例,达到456973例。
前言
本篇主要记录使用DialogFragment实现的弹框,对点击非内容区域事件的监听和控制。
这个需求在着手实现之初,就断定是需要从事件的分发机制处展开的。
实现过程分析
DialogFragment 显示Dialog的具体流程为:
FragmentManager.java
1 | void moveToState(Fragment f, int newState, int transit, int transitionStyle, |
Fragment.java
1 | void performCreate(Bundle savedInstanceState) { |
从上面可以看出Fragment的部分生命周期回调:
onAttach(mHost.getContext())
performCreate(f.mSavedFragmentState)
performCreate
内部则回调了onCreate
- f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState) 这个是重点,DialogFragment会重写getLayoutInflater -> performGetLayoutInflater -> onGetLayoutInflater 调用顺序调用到的
onGetLayoutInflater
方法创建Dialog对象(onCreateDialog
),并将performCreateView
返回的view保存到Fragmnet内。即onViewCreated
的第一个入参。performCreateView
内会回调onCreateView
onViewCreated(f.mView, f.mSavedFragmentState)
performActivityCreated(f.mSavedFragmentState)
performActivityCreated
内部会回调onActivityCreated
DialogFragment.java
1 | /** @hide */ |
根据Fragment内主要生命周期方法调用顺序和DialogFragment重写的具体方法,可以确定一个调用顺序:(注:括号表示的是括号内的为括号前表示方法内部调用,不是表示入参)
onAttach -> onCreate -> performCreateView( onGetLayoutInflater(onCreateDialog) -> onCreateView) -> onViewCreated -> onActivityCreated -> onStart
而且DialogFragment显示对话框主要还是通过内部创建Dialog对象来实现。
从Dialog的 dispatchTouchEvent
入手:
Dialog.java
1 | /** |
其中mWindow
在Android中的具体实现类为PhoneWindow,关于事件分发的详细说明可查看文章 Android事件分发机制源码解析。由于我们点击的是外部区域,所以superDispatchTouchEvent
不会消费此事件,从而转交给onTouchEvent
处理。
onTouchEvent内主要看mWindow.shouldCloseOnTouch(mContext, event)
,由于PhoneWindow
没有重写该方法,所以看Window
内的具体实现
1 | /** @hide */ |
Window#shouldCloseOnTouch主要是判断了点击位置是否在DecorView范围内。
实现方案
通过上述分析,可以通过重写DialogFragment#onCreateDialog(Bundle)
方法,返回重写了onTouchEvent
的Dialog对象OutsideClickDialog。通过onTouchEvent
拦截事件。
OutsideClickDialog具体代码如下:
1 | public static class OutsideClickDialog extends Dialog { |
在DialogFragment子类SimpleDialogFragment内:
1 |
|
其中Builder 为SimpleDialogFragment静态内部类。
并通过OnKeyListener监听返回按键。
具体使用如下:
1 |
|