【问题标题】:Reopen ActionMode (or CAB) after onDestroyActionMode is called调用 onDestroyActionMode 后重新打开 ActionMode(或 CAB)
【发布时间】:2014-04-12 11:19:40
【问题描述】:

让我们看看这种情况:您在屏幕上打开了一个带有 DONE 和 DISCARD 选项的 CAB,并且您将不接受某个字段的错误值。因此,用户应该填写一个有效值(然后按 Back/Done 以使其被接受)或按 CAB 上的 Discard。

按下 DONE 会立即启动 onDestroyActionMode(),然后关闭 CAB。 所以,这是启动有效性检查的地方(在onBackPressed() 旁边)。

问题是,如果在那里创建一个新的 ActionMode(如果表单有效性检查失败),则将启动递归循环(因为新的 CAB 将首先开始关闭旧的 CAB,依此类推) --> StackOverflowError.

我尝试创建一个状态变量来防止 StackOverflowError,但在这种情况下,它只会每秒钟工作一次(并且只有 onBackPressed()):-/

所以,问题:我如何在调用onDestroyActionMode() 后立即保持 CAB 处于打开状态(或如何重新打开新的 CAB)?

【问题讨论】:

  • 你应该重新考虑你当前的逻辑。从用户体验的角度来看,当用户输入错误时重新打开 CAB 听起来并不清楚(因为我认为 CAB 不适合数据输入表单)。您可能希望在用户输入数据时当场进行验证,并且如果用户仍然继续单击完成,则向他显示输入不正确的消息(尽管看到实时有效性指示器可能会让他不单击完成)。
  • 感谢您的评论。 CAB 是这种场景(创建条目)的合适模式。有问题的字段已经具有验证和错误指示。问题是正确的操作是在用户按下后退按钮时始终保存/创建数据(与完成相同),但错误禁止完成此操作(例如,由于键违规)。因此,在错误按下 Back/Done 之后想要/需要保留 CAB。
  • 我知道另一种可能性:在按下 Back/Done 时丢弃错误数据并通知用户,但这似乎有点笨拙,因为用户确实有意图(编辑/创建条目)并进行自动丢弃似乎过于轻率了。
  • “CAB 是这种场景的合适模式(创建条目)”——DONE & DISCARD 不是动作模式/CAB,而是一个程式化的动作栏,正如 Roman Nurik 描述的那样以前:plus.google.com/u/0/+RomanNurik/posts/R49wVvcDoEW

标签: android contextual-action-bar android-actionmode


【解决方案1】:

第一个评论者确实是正确的。动作模式是瞬态的,用户可以随时根据设计完成。它们用于表示诸如批量选择之类的内容,您可以在对整个集合执行操作之前添加或删除它,邮件分类和文本编辑是两个示例。完成一个动作模式应该是非破坏性的,就像取消一个对话框一样。不应将其视为确认步骤。

谈到文本编辑,您在很大程度上暗示您的表单包含文本字段。当用户突出显示某些文本并且 TextView 启动自己的编辑操作模式时会发生什么?启动一个动作模式将隐式结束任何当前的动作模式。

您应该使用另一种可供性来表达正在进行的编辑。

【讨论】:

  • 会将 CAB 重新设计为 AB(正如@CommonsWare 正确观察到的那样),并将使其对错误表现得宽容,即当按下 Back/Done 时数据出现错误时丢弃表单并通知/敬酒用户关于它。
【解决方案2】:

回答核心问题:如何在背压后重新创建 ActionMode:

您可以将 Runnable 延迟到 Handler 以重新创建 ActionMode。所需的延迟在设备之间可能会有所不同,我发现 200 毫秒可以处理我尝试过的所有内容。在 Activity 或 FragmentActivity 中尝试这些 sn-ps:

RepeatActionModeRunnable mRepeatActionModeRunnable;
Handler mHandler = new Handler();

@Override
protected void onPause() {
    mHandler.removeCallbacks(mRepeatActionModeRunnable);
    super.onPause();
}

private class RepeatActionModeRunnable implements Runnable {
    ActionMode.Callback mRepeatActionMode;
    public RepeatActionModeRunnable(ActionMode.Callback actionMode) {
        mRepeatActionMode = actionMode;
    }
    @Override
    public void run() {
        mActionMode = startActionMode(mRepeatActionMode);
    }
}

然后在 onDestroyActionMode 中,您可以在需要时使用它(即,您无疑需要一些逻辑包装它来检测是否应该重新创建它):

mHandler.removeCallbacks(mRepeatActionModeRunnable);
mRepeatActionModeRunnable = new RepeatActionModeRunnable(new SomeActionMode());
mHandler.postDelayed(mRepeatActionModeRunnable, 200);

至于 CAB 是否用于表单/数据输入,这种情况非常适合“行动呼吁”,这也是 ActionMode 模式存在的原因。障碍/细微差别/错误的存在,例如在按下后退按钮后重新创建以及用户选择要编辑的文本不应构成不能使用的理由,而应将其视为可能不是阻力最小的路径就解决方案而言(这是一个挑战!)。单独存在“完成并丢弃”模式也不应该构成在涉及数据输入的情况下不使用 ActionMode 的理由。这些都是可能更适合您的情况的可能性,而不是正确或错误的方式。

PS:关于如何处理TextSelectionCAB,这里有一个解决方案:Detect ActionMode nesting

【讨论】:

  • 感谢您根据问题提供答案。希望有人能从中受益。
【解决方案3】:

其实你可以这样做,这样就不会再有StackOverflowException了:

 @Override
        public void onDestroyActionMode(ActionMode mode) {
            //your code
            new Handler().post(new Runnable() {
                @Override
                public void run() {
                    startSupportActionMode(mActionCallBack);
                }
            });
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 1970-01-01
    • 2019-01-14
    相关资源
    最近更新 更多