预计onUserInteraction
任何用户交互都会调用它。它在PreferenceActivity
. 但是,当 aDialogPreference
弹出时,onUserInteraction
即使有触摸事件等用户交互,也不再调用。
这似乎 DialogPreference
不是唯一的情况。无论何时Dialog
显示,它都不会将用户交互报告给活动。
但是,如果我真的需要它,我该怎么办。谢谢你。
预计onUserInteraction
任何用户交互都会调用它。它在PreferenceActivity
. 但是,当 aDialogPreference
弹出时,onUserInteraction
即使有触摸事件等用户交互,也不再调用。
这似乎 DialogPreference
不是唯一的情况。无论何时Dialog
显示,它都不会将用户交互报告给活动。
但是,如果我真的需要它,我该怎么办。谢谢你。
据我所知,onUserInteraction()
在用户与对话框交互时(甚至从Activity
您正在监视交互的位置开始)根本不会调用。
我知道的两个解决方案是:
子类Dialog
/DialogPreference
类和覆盖dispatchTouchEvent()
。
通过发出以下命令实现Window.Callback
接口并将其设置为s 窗口回调:Dialog
dialog.getWindow().setCallback(callbackImplementation);
注意:这个实现应该通过调用适当的对话框方法来处理所有接收到的事件,或者以你自己的方式处理事件(例如通过手动调用onUserInteraction()
)。
编辑
您有几种方法可以Activity
从自定义PreferenceDialog
实例中获取。
调用DialogPreference.getPreferenceManager()
返回的方法PreferenceManager
。它有一个getActivity()
方法,但它是包私有的,因此您必须将自定义DialogPreference
放入android.preference
包中才能访问它。
在中PreferenceActivity.onCreate()
,膨胀首选项后,使用按键findPreference()
找到您的自定义DialogPreference
。然后将其转换为您的自定义类并this
通过访问器将活动设置为。
我会选择第二个选项。
这是 a 的完整解决方案,它在触摸时DialogFragment
触发 Activity并保留默认回调的行为:onUserInteraction()
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);
}
}
这是一个更独立、更完整的 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
}
}
}