预期任何用户交互都将调用onUserInteraction。它在PreferenceActivity中工作正常。但是,当DialogPreference是弹出窗口时,即使存在用户交互(如触摸事件),也不再调用onUserInteraction。看起来DialogPreference并不是唯一的情况,无论何时显示Dialog,它都不会将用户交互报告给Activity。但是如果我真的需要它,我能做什么呢?谢谢。
onUserInteraction
PreferenceActivity
DialogPreference
Dialog
dgtucam11#
据我所知,当用户与对话框交互时(甚至从监视交互的Activity开始),onUserInteraction()不会被调用。我知道的两个解决方案是:
Activity
onUserInteraction()
dispatchTouchEvent()
Window.Callback
dialog.getWindow().setCallback(callbackImplementation);
**注意:**此实现应通过调用适当的对话框方法来处理所有接收到的事件,或以您自己的方式处理事件(例如,通过手动调用onUserInteraction())。编辑
您有几种方法可以从自定义PreferenceDialog示例中获取Activity。1.调用返回PreferenceManager的DialogPreference.getPreferenceManager()方法。它有一个getActivity()方法**,但它是包私有的**,因此您必须将自定义的DialogPreference放在android.preference包中才能访问它。1.在PreferenceActivity.onCreate()中,膨胀首选项后,使用findPreference()通过键找到自定义的DialogPreference,然后将其强制转换为自定义类,并通过访问器将activity设置为this。我会选择第二个选项。
PreferenceDialog
PreferenceManager
DialogPreference.getPreferenceManager()
getActivity()
android.preference
PreferenceActivity.onCreate()
findPreference()
this
lsmepo6l2#
下面是DialogFragment的完整解决方案,它在触摸时触发Activity的onUserInteraction(),并保留默认回调的行为:
DialogFragment
public abstract class BaseDialogFragment extends DialogFragment { @Override public void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final Window window = getDialog().getWindow(); if (window != null) { window.setCallback(new UserInteractionAwareCallback(window.getCallback(), getActivity())); } } }
下面是回调本身:
public class UserInteractionAwareCallback implements Window.Callback { private final Window.Callback originalCallback; private final Activity activity; public UserInteractionAwareCallback(final Window.Callback originalCallback, final Activity activity) { this.originalCallback = originalCallback; this.activity = activity; } @Override public boolean dispatchKeyEvent(final KeyEvent event) { return originalCallback.dispatchKeyEvent(event); } @Override public boolean dispatchKeyShortcutEvent(final KeyEvent event) { return originalCallback.dispatchKeyShortcutEvent(event); } @Override public boolean dispatchTouchEvent(final MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: if (activity != null) { activity.onUserInteraction(); } break; default: } return originalCallback.dispatchTouchEvent(event); } @Override public boolean dispatchTrackballEvent(final MotionEvent event) { return originalCallback.dispatchTrackballEvent(event); } @Override public boolean dispatchGenericMotionEvent(final MotionEvent event) { return originalCallback.dispatchGenericMotionEvent(event); } @Override public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) { return originalCallback.dispatchPopulateAccessibilityEvent(event); } @Nullable @Override public View onCreatePanelView(final int featureId) { return originalCallback.onCreatePanelView(featureId); } @Override public boolean onCreatePanelMenu(final int featureId, final Menu menu) { return originalCallback.onCreatePanelMenu(featureId, menu); } @Override public boolean onPreparePanel(final int featureId, final View view, final Menu menu) { return originalCallback.onPreparePanel(featureId, view, menu); } @Override public boolean onMenuOpened(final int featureId, final Menu menu) { return originalCallback.onMenuOpened(featureId, menu); } @Override public boolean onMenuItemSelected(final int featureId, final MenuItem item) { return originalCallback.onMenuItemSelected(featureId, item); } @Override public void onWindowAttributesChanged(final WindowManager.LayoutParams attrs) { originalCallback.onWindowAttributesChanged(attrs); } @Override public void onContentChanged() { originalCallback.onContentChanged(); } @Override public void onWindowFocusChanged(final boolean hasFocus) { originalCallback.onWindowFocusChanged(hasFocus); } @Override public void onAttachedToWindow() { originalCallback.onAttachedToWindow(); } @Override public void onDetachedFromWindow() { originalCallback.onDetachedFromWindow(); } @Override public void onPanelClosed(final int featureId, final Menu menu) { originalCallback.onPanelClosed(featureId, menu); } @Override public boolean onSearchRequested() { return originalCallback.onSearchRequested(); } @TargetApi(Build.VERSION_CODES.M) @Override public boolean onSearchRequested(final SearchEvent searchEvent) { return originalCallback.onSearchRequested(searchEvent); } @Nullable @Override public ActionMode onWindowStartingActionMode(final ActionMode.Callback callback) { return originalCallback.onWindowStartingActionMode(callback); } @TargetApi(Build.VERSION_CODES.M) @Nullable @Override public ActionMode onWindowStartingActionMode(final ActionMode.Callback callback, final int type) { return originalCallback.onWindowStartingActionMode(callback, type); } @Override public void onActionModeStarted(final ActionMode mode) { originalCallback.onActionModeStarted(mode); } @Override public void onActionModeFinished(final ActionMode mode) { originalCallback.onActionModeFinished(mode); } }
0md85ypi3#
下面是一个更加独立和完整的Kotlin实现:
/** * Sets up the receiver's [window][Dialog.getWindow] to call [Activity.onUserInteraction] * at appropriate times, mirroring the calls made in [Activity] itself. * This method should be called immediately after [Dialog.show]. */ fun Dialog.reportUserInteraction() { window?.let { window -> val activity = window.decorView.activity val wrappedCallback = window.callback window.callback = object : Window.Callback by wrappedCallback { override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean { activity.onUserInteraction() return wrappedCallback.dispatchGenericMotionEvent(event) } override fun dispatchKeyEvent(event: KeyEvent): Boolean { activity.onUserInteraction() return wrappedCallback.dispatchKeyEvent(event) } override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean { activity.onUserInteraction() return wrappedCallback.dispatchKeyShortcutEvent(event) } override fun dispatchTouchEvent(event: MotionEvent): Boolean { if (event.action == ACTION_DOWN) activity.onUserInteraction() return wrappedCallback.dispatchTouchEvent(event) } override fun dispatchTrackballEvent(event: MotionEvent): Boolean { activity.onUserInteraction() return wrappedCallback.dispatchTrackballEvent(event) } } } }
依赖于:
val View.activity: Activity get() = context.activityOrNull!! val Context.activityOrNull: Activity? get() { var context = this while (true) { if (context is Application) { return null } if (context is Activity) { return context } if (context is ContextWrapper) { val baseContext = context.baseContext // Prevent Stack Overflow. if (baseContext === this) { return null } context = baseContext } else { return null } } }
brccelvz4#
这对我很有效,Kotlin版本:在对话框中:
override fun onStart() { super.onStart() UserInteractionInterceptor.wrapWindowCallback(dialog.window, activity) }
和UserInteractionInterceptor类别:
object UserInteractionInterceptor { fun wrapWindowCallback(window: Window, activity: FragmentActivity?) { val originalCallback: Window.Callback = window.callback window.callback = object : Window.Callback { override fun dispatchKeyEvent(event: KeyEvent?): Boolean { return originalCallback.dispatchKeyEvent(event) } override fun dispatchKeyShortcutEvent(event: KeyEvent?): Boolean { return originalCallback.dispatchKeyShortcutEvent(event) } override fun dispatchTouchEvent(event: MotionEvent): Boolean { if (event.action == MotionEvent.ACTION_DOWN) { activity?.onUserInteraction() } return originalCallback.dispatchTouchEvent(event) } override fun dispatchTrackballEvent(event: MotionEvent?): Boolean { return originalCallback.dispatchTrackballEvent(event) } override fun dispatchGenericMotionEvent(event: MotionEvent?): Boolean { return originalCallback.dispatchGenericMotionEvent(event) } override fun dispatchPopulateAccessibilityEvent(event: AccessibilityEvent?): Boolean { return originalCallback.dispatchPopulateAccessibilityEvent(event) } @Nullable override fun onCreatePanelView(featureId: Int): View? { return originalCallback.onCreatePanelView(featureId) } override fun onCreatePanelMenu(featureId: Int, p1: Menu): Boolean { return originalCallback.onCreatePanelMenu(featureId, p1) } override fun onPreparePanel(featureId: Int, view: View?, p2: Menu): Boolean { return originalCallback.onPreparePanel(featureId, view, p2) } override fun onMenuOpened(featureId: Int, p1: Menu): Boolean { return originalCallback.onMenuOpened(featureId, p1) } override fun onMenuItemSelected(featureId: Int, p1: MenuItem): Boolean { return originalCallback.onMenuItemSelected(featureId, p1) } override fun onWindowAttributesChanged(attrs: WindowManager.LayoutParams?) { originalCallback.onWindowAttributesChanged(attrs) } override fun onContentChanged() { originalCallback.onContentChanged() } override fun onWindowFocusChanged(hasFocus: Boolean) { originalCallback.onWindowFocusChanged(hasFocus) } override fun onAttachedToWindow() { originalCallback.onAttachedToWindow() } override fun onDetachedFromWindow() { originalCallback.onDetachedFromWindow() } override fun onPanelClosed(featureId: Int, p1: Menu) { originalCallback.onPanelClosed(featureId, p1) } override fun onSearchRequested(): Boolean { return originalCallback.onSearchRequested() } @TargetApi(Build.VERSION_CODES.M) override fun onSearchRequested(searchEvent: SearchEvent?): Boolean { return originalCallback.onSearchRequested(searchEvent) } @Nullable override fun onWindowStartingActionMode(callback: ActionMode.Callback?): ActionMode? { return originalCallback.onWindowStartingActionMode(callback) } @TargetApi(Build.VERSION_CODES.M) @Nullable override fun onWindowStartingActionMode(callback: ActionMode.Callback?, type: Int): ActionMode? { return originalCallback.onWindowStartingActionMode(callback, type) } override fun onActionModeStarted(mode: ActionMode?) { originalCallback.onActionModeStarted(mode) } override fun onActionModeFinished(mode: ActionMode?) { originalCallback.onActionModeFinished(mode) } } }
}
4条答案
按热度按时间dgtucam11#
据我所知,当用户与对话框交互时(甚至从监视交互的
Activity
开始),onUserInteraction()
不会被调用。我知道的两个解决方案是:
Dialog
/DialogPreference
类并覆盖dispatchTouchEvent()
。Window.Callback
接口并将其设置为Dialog
的窗口回调:**注意:**此实现应通过调用适当的对话框方法来处理所有接收到的事件,或以您自己的方式处理事件(例如,通过手动调用
onUserInteraction()
)。编辑
您有几种方法可以从自定义
PreferenceDialog
示例中获取Activity
。1.调用返回
PreferenceManager
的DialogPreference.getPreferenceManager()
方法。它有一个getActivity()
方法**,但它是包私有的**,因此您必须将自定义的DialogPreference
放在android.preference
包中才能访问它。1.在
PreferenceActivity.onCreate()
中,膨胀首选项后,使用findPreference()
通过键找到自定义的DialogPreference
,然后将其强制转换为自定义类,并通过访问器将activity设置为this
。我会选择第二个选项。
lsmepo6l2#
下面是
DialogFragment
的完整解决方案,它在触摸时触发Activity的onUserInteraction()
,并保留默认回调的行为:下面是回调本身:
0md85ypi3#
下面是一个更加独立和完整的Kotlin实现:
依赖于:
brccelvz4#
这对我很有效,Kotlin版本:
在对话框中:
和UserInteractionInterceptor类别:
}