10

预计onUserInteraction任何用户交互都会调用它。它在PreferenceActivity. 但是,当 aDialogPreference弹出时,onUserInteraction即使有触摸事件等用户交互,也不再调用。

这似乎 DialogPreference不是唯一的情况。无论何时Dialog显示,它都不会将用户交互报告给活动。

但是,如果我真的需要它,我该怎么办。谢谢你。

4

3 回答 3

10

据我所知,onUserInteraction()在用户与对话框交互时(甚至从Activity您正在监视交互的位置开始)根本不会调用。

我知道的两个解决方案是:

  • 子类Dialog/DialogPreference类和覆盖dispatchTouchEvent()

  • 通过发出以下命令实现Window.Callback接口并将其设置为s 窗口回调:Dialog

    dialog.getWindow().setCallback(callbackImplementation);
    

    注意:这个实现应该通过调用适当的对话框方法来处理所有接收到的事件,或者以你自己的方式处理事件(例如通过手动调用onUserInteraction())。

编辑

您有几种方法可以Activity从自定义PreferenceDialog实例中获取。

  1. 调用DialogPreference.getPreferenceManager()返回的方法PreferenceManager。它有一个getActivity()方法,但它是包私有的,因此您必须将自定义DialogPreference放入android.preference包中才能访问它。

  2. 在中PreferenceActivity.onCreate(),膨胀首选项后,使用按键findPreference()找到您的自定义DialogPreference。然后将其转换为您的自定义类并this通过访问器将活动设置为。

我会选择第二个选项。

于 2013-02-12T09:32:05.737 回答
8

这是 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);
    }
}
于 2018-06-01T16:08:50.223 回答
3

这是一个更独立、更完整的 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
      }
    }
  }
于 2021-02-08T22:40:09.310 回答