java - EditText .setError() 未在重新创建时应用我的自定义错误图标

标签 java android android-fragments android-edittext

我在 ViewPager 中有一个 Fragment

在该 fragment 中,我有几个 EditText 的 OnTextChanged 监听器(添加到 onViewCreated 方法中)执行一些验证工作并调用一个函数来设置/删除一个错误如:

// Sets or removes an error message in the nameField EditText 
public void validateUsername(String message)
{
    if(message == null)
    {
        nameField.setError(null);
    }
    else
    {
        nameField.setError(message,errorIcon);
    }
}

errorIcon 是一个 Drawable 实例化的 onCreate,如下所示:

errorIcon = getResources().getDrawable(R.drawable.ic_wrong_input);
errorIcon.setBounds(new Rect(0, 0, errorIcon.getIntrinsicWidth(), errorIcon.getIntrinsicHeight()));

当我在 EditText 中键入内容时,验证工作正常:显示我的错误消息和我的自定义图标。

但是当我旋转设备时,validateUsername() 函数被调用(预期行为), 中的 nameField.setError(message,errorIcon) else 分支被执行但是 EditText 获得了 Android 的默认错误图标而不是我的(是的,在调试时我可以看到我的 errorIcon Drawable 被实例化了)。在那之后,如果我在 EditText 中输入无效的内容,验证方法将再次被调用,这次我再次获得自定义错误图标。如果我再次旋转设备,同样的事情:重新创建默认图标,输入无效内容后自定义图标...

谁能解释这种行为?为什么在设备旋转导致重新创建后我会收到 Android 的默认错误图标,即使我明确设置了自定义图标?

编辑:

我已经尝试在我的 validateUsername() 方法中实例化 Drawable,但没有成功。

编辑 2:

我想使用自定义错误图标,以便它与我的 UI 更好地融合,还因为我正在使用显示为 EditText 右侧的另一个自定义图标(绿色图标) Drawable 当它们的输入有效并且我希望它们彼此一致时。

现在我已经辞职了,我让 Android 使用默认的错误图标(即我没有在 setError() 方法上指定任何 Drawable)。当输入有效时,我将 EditText 的右侧 Drawable 设置为我自定义的“输入有效”图标,为了保持一致性,我将其修改为与 Android 的 indicator_input_error.png 具有相同的大小。

我仍然不喜欢这种方法(例如,在未来的版本中,indicator_input_error.png 图标可能会有所不同)而且我不明白为什么当 Fragment 重新创建。奇怪的是,第一次重新创建 Fragment 时,如果 EditText 验证失败并且使用非空消息调用 validateUsername(),我会得到自定义图标。在第二次(以此类推)重新创建 Fragment 时,我得到了 Android 的默认图标。如果我输入了一些无效的文本,我又得到了我的自定义图标,这很奇怪。

最佳答案

太麻烦了!我遇到了同样的问题。除了内置的错误图标外,我还有一个自定义图标来表示警告,并且会根据情况显示适当的图标。

当您遇到问题时,当在您的 Activity 中调用 onSave/onRestoreInstanceState() 时(即:当屏幕旋转时),setError() 运行异常。

事实证明,大多数(所有?)常用的 Android 小部件都会创建自己的可打包状态,以在旋转期间保留它们的弹珠。这意味着许多简单的布局不需要实现它们自己的可打包/可序列化对象,正如您很可能已经体验过的那样。

如果深入到 TextView 类,您将在其 onRestoreInstanceState() 实现的末尾看到以下内容:

      if (ss.error != null) {
        final CharSequence error = ss.error;
        // Display the error later, after the first layout pass
        post(new Runnable() {
            public void run() {
                setError(error);
            }
        });

如您所见,仅检查 ss.error(在 TextView 的 onSaveInstanceState() 期间保存)以查看它是否不为空。如果是这样,它会通过调用 setError(error) 来恢复。简而言之,您的自定义图标在保存期间没有被打包,因此它不会被小部件恢复——导致显示标准的红色错误图标。考虑到 TextView 代码的年代,我怀疑这是 Google 的疏忽。

可以尝试在您自己覆盖的 onRestoreInstanceState() 中重置错误文本和图标,但由于小部件正在排队其 setError() 调用(通过调用 post() ),你的直接调用会超过它,导致你的图标显示一瞬间,只有在队列处理发生后才会被覆盖。

我通过在我的 View 队列中放置我自己对 setError() 的调用(也使用 post() )解决了这个问题。这在学术上可能不合适,而且完全同步(因为我依赖消息队列的顺序处理),但它解决了这个问题。

简而言之,在你的 onRestoreInstanceState() 中做这样的事情:

protected void onRestoreInstanceState(Bundle savedInstanceState)
{
    // Call super first, to ensure that all the widget updates get in the queue first...
    super.onRestoreInstanceState(savedInstanceState);

    View view = getWindow().getDecorView().getRootView();

    view.post(new Runnable() 
    {
        public void run() 
        {
            myEditText.setError(...);
            .
            .
            .
        }
    });
}

要消化的东西太多了。希望这对您有所帮助!

关于java - EditText .setError() 未在重新创建时应用我的自定义错误图标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20610171/

相关文章:

java - 如何在 JSoup 中打印 UTF-8 编码的字符

java - 在 JavaFX 中获取当前阶段的 GraphicsDevice

java - 在 RecyclerView 中从 Firebase 加载图像时出现问题

java - 带客户端身份验证的 HTTPS 在 Android 上不起作用

java - R.java 中分配给属性的值的含义

android - 如何使用 pagertabstrip 更新 View 寻呼机中的 fragment View ?

java - 初始化可能失败的惰性单例的哪种实现?

java - 如何在 spring webflux webclient 中发送 "fire and forget"请求?

java - Android 如何加载 ListView 标题的新 fragment onClick

java - 如何在 Android fragment 和服务中请求注入(inject)?