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

时间:2013-12-16 11:45:45

标签: java android android-fragments android-edittext

我在Fragment内有一个ViewPager

在该片段中,我有几个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 instanciated 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 s'右{{1当他们的输入有效并且我希望他们彼此一致时。

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

尽管如此,我不喜欢这种方法(例如在未来的版本中,indicator_input_error.png图标可能会有所不同),我无法理解为什么在setError()重新启动时我会继续获取默认图标-created。奇怪的是,第一次重新创建Fragment时,如果EditText验证失败并且使用非空消息调用validateUsername(),我会获得自定义图标。在第二次(依此类推)重新创建Fragment时,我获得了Android的默认图标。如果我输入了一些无效的文字,我会再次获得自定义图标,这很奇怪。

1 个答案:

答案 0 :(得分:4)

真麻烦!我遇到了同样的问题。除了内置的错误图标外,我还有一个自定义图标来表示警告,并根据条件显示相应的图标。

当您进入时,在您的活动中调用onSave / onRestoreInstanceState()时,setError()会运行(即:旋转屏幕时)。

事实证明,大多数(所有?)股票Android小工具都会创建自己的可分配状态,以便在轮换期间保留其弹珠。这意味着许多简单的布局不需要实现他们自己的parcelable / serializable对象,就像你最有可能经历的那样。

如果深入查看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(错误)进行恢复。简而言之,您的自定义图标在保存期间不会被分区,因此窗口小部件不会还原它 - 导致显示标准红色错误图标。鉴于TextView代码的年龄,我怀疑这是Google的疏忽。

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

我通过在视图的队列中放置我自己的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(...);
            .
            .
            .
        }
    });
}

这要消化很多。希望这有帮助!