我在 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)
elseEditText
获得了 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/