官方没有给我们提供一个这样的API,一切都靠自己想逻辑啦!
我是这样想的:
用户无操作实际上就是用户不在编辑,也不在屏幕上点击或摩擦(Move);
监听点击和摩擦时间就是要用activity的API,但是特么像dialog和popuWindow这种弹窗的点击和摩擦就不归activity管的。
然而需求是 当有弹窗出现时,认为用户有操作。那么有两个办法:
1.基类管理法:自定义一个基类BaseDialog继承自Dialog,或者基类BasePopuWindow继承自PopuWindow,然后重写show()(如果是popuWindow就是showAtLocation()或showAsDropDown())和dismiss()方法,在里面加自己的boolean值标志符。然后项目中所有的dialog和popuWindow全部继承对应基类即可。
2.activity焦点管理法:这个方法也需要写一个activity的基类BaseActivity,里面重写方法
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//activity发生焦点变化监听
Log.e(TAG, "onWindowFocusChanged: activity焦点变化=="+hasFocus );
}
应用里全部activity都去继承BaseActivity。
在这个onWindowFocusChanged(boolean hasFocus)方法里加你自己定的boolean值标志符,以后既可以拿这个标志符作为判断是否activity的焦点被弹窗所抢。从而判断弹窗是否弹出来或者应用是否进入后台了。
我用的是第二种方法,省事儿…
那么在没有弹窗的情况下,监听用户是否在点击activity或摩擦activity呢?
<通过Window的回调!>
以下自定义一个Window的回调:
public class WinCallback implements Window.Callback {
Window.Callback callback;
public WinCallback(Window.Callback callback) {
this.callback = callback;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
return callback.dispatchKeyEvent(event);
}
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
return callback.dispatchKeyShortcutEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return callback.dispatchTouchEvent(event);
}
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
return callback.dispatchTrackballEvent(event);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
return callback.dispatchGenericMotionEvent(event);
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
return callback.dispatchPopulateAccessibilityEvent(event);
}
@Override
public View onCreatePanelView(int featureId) {
return callback.onCreatePanelView(featureId);
}
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
return callback.onCreatePanelMenu(featureId, menu);
}
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
return callback.onPreparePanel(featureId, view, menu);
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
return callback.onMenuOpened(featureId, menu);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
return callback.onMenuItemSelected(featureId, item);
}
@Override
public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
callback.onWindowAttributesChanged(attrs);
}
@Override
public void onContentChanged() {
callback.onContentChanged();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
callback.onWindowFocusChanged(hasFocus);
}
@Override
public void onAttachedToWindow() {
callback.onAttachedToWindow();
}
@Override
public void onDetachedFromWindow() {
callback.onDetachedFromWindow();
}
@Override
public void onPanelClosed(int featureId, Menu menu) {
callback.onPanelClosed(featureId, menu);
}
@Override
public boolean onSearchRequested() {
return callback.onSearchRequested();
}
@Override
public boolean onSearchRequested(SearchEvent searchEvent) {
return false;
}
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
return this.callback.onWindowStartingActionMode(callback);
}
@Nullable
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
return null;
}
@Override
public void onActionModeStarted(ActionMode mode) {
callback.onActionModeStarted(mode);
}
@Override
public void onActionModeFinished(ActionMode mode) {
callback.onActionModeFinished(mode);
}
}
怎么用呢?
请看:
Activity activity = ContextBean.getInstance().getActivity();
if (activity == null) { return; }
Window win = activity.getWindow();
Log.e(TAG, "touchOnclick: activity="+activity );
win.setCallback(new WinCallback(win.getCallback()) {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "dispatchTouchEvent:activity窗口被触摸");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "dispatchTouchEvent:手指离开activity窗口");
break;
}
return super.dispatchTouchEvent(event);
}
});
ContextBean.getInstance().getActivity()就是上一篇文章全局获取当前展示的activity。
还有一种情况,就是EditText这个控件被编辑的时候,是不归以上的触摸监听管的。
整个工程那么多EditText,总不能一个一个去写监听,那么还是用基类管理的思路,写一个自定义基类MyEditText继承自AppCompatEditText:
public class MyEditText extends AppCompatEditText {
private static final String TAG = "MyEditText";
public MyEditText(Context context) {
super(context);
setOnFocusChangeListener(listener);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
setOnFocusChangeListener(listener);
}
public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOnFocusChangeListener(listener);
}
OnFocusChangeListener listener = new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
//是否在编辑editText,editText被销毁时不调用这个,调用onDetachedFromWindow()
Log.e(TAG, "EditText是否被编辑=="+hasFocus);
}
};
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.e(TAG, "EditText被销毁==");
}
}
同理,这儿可以加boolean值标志符,作为你判断用户是否在编辑的依据。
然后,整个工程里所有用到EditText的布局文件,全部“<EditText ” 改为“<你的app包名.MyEditText”即可。