某些运行 Jelly Bean/4.2.1 的设备的 Android 操作系统错误 - TextView.setError(CharSequence error) 缺少图标

标签 android android-edittext textview android-4.2-jelly-bean

一些(但不是全部)运行 Jelly Bean (4.2.1) 的设备似乎缺少应该出现在 TextView(或更常见的是 上的感叹号错误图标) EditText) 通过 TextView.setError(CharSequence error) 设置了错误.

enter image description here enter image description here

Galaxy Nexus 显然缺少图标。

效果是 setError 设置的错误状态只有在 EditText 有焦点时才明显。这使得 setError(...) 的用处大大降低,因为它通常用于鼓励用户返回该 EditText 以解决问题。例如,您有一个标准登录屏幕,其中包含用户单击提交按钮时验证的用户名和密码表单条目。除非用户单击返回该表单,否则不会显示在用户名表单上设置的验证错误消息——这是错误图标旨在鼓励他们这样做的!

测试:(可能有一个更容易访问的 EditText,但这个非常广泛)

  1. 打开设置
  2. 选择“添加帐户”(在旧设备的“帐户和同步”中)
  3. 选择“Google”作为帐户类型
  4. 选择“现有”(在旧设备上单击“下一步”和“登录”后)
  5. 将“电子邮件”EditText留空,点击“密码”EditText

此时,在“电子邮件”EditText 上设置了一个错误,说明它不能为空。在没有此问题的设备上,会显示通常的错误图标,当 EditText 具有焦点时,该图标会扩展为完整的错误消息。在运行 Jelly Bean 的 Galaxy Nexuses 上,不显示任何图标,并且该错误仅在“电子邮件”EditText 再次获得焦点且此时仍缺少图标时才可见。

这看起来像一个错误,但我想检查其他人是否可以重现它,了解问题可能是什么,并有一个好的解决方法。

使用 setError(CharSequence error, Drawable icon)可能会解决问题,但如果能够在不同的 Android 版本中使用库存错误图形,那就太好了。

最佳答案

临时解决方案! EditTextErrorFixed.java

虽然这确实是一个 SDK 错误,但我已经设法使用反射方法让图标按预期工作。我检查了它是否适用于 4.2 和 4.2.1,并确认它适用于我更新的 Galaxy Nexus。

来源可以找到here.

截图显示底部EditTextErrorFixed的图标在焦点改变时仍然存在。此外,它还包含另一个修复,如果用户在已经为空的 EditText 上按 Delete,错误就会消失(另一个错误?)。

Demo image

为方便起见,这里是 EditTextErrorFixed 源码;该类可以很容易地在 XML 中使用:

package com.olegsv.showerrorfixeddemo;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.EditText;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * EditText which addresses issues with the error icon
 * (http://stackoverflow.com/q/13756978/832776) and also the error icon
 * disappearing on pressing delete in an empty EditText
 */
public class EditTextErrorFixed extends EditText {
    public EditTextErrorFixed(Context context) {
        super(context);
    }

    public EditTextErrorFixed(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public EditTextErrorFixed(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Don't send delete key so edit text doesn't capture it and close error
     */
    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (TextUtils.isEmpty(getText().toString()) && keyCode == KeyEvent.KEYCODE_DEL)
            return true;
        else
            return super.onKeyPreIme(keyCode, event);
    }

    /**
     * Keep track of which icon we used last
     */
    private Drawable lastErrorIcon = null;

    /**
     * Resolve an issue where the error icon is hidden under some cases in JB
     * due to a bug http://code.google.com/p/android/issues/detail?id=40417
     */
    @Override
    public void setError(CharSequence error, Drawable icon) {
        super.setError(error, icon);
        lastErrorIcon = icon;

        // if the error is not null, and we are in JB, force
        // the error to show
        if (error != null /* !isFocused() && */) {
            showErrorIconHax(icon);
        }
    }

    /**
     * In onFocusChanged() we also have to reshow the error icon as the Editor
     * hides it. Because Editor is a hidden class we need to cache the last used
     * icon and use that
     */
    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        showErrorIconHax(lastErrorIcon);
    }

    /**
     * Use reflection to force the error icon to show. Dirty but resolves the
     * issue in 4.2
     */
    private void showErrorIconHax(Drawable icon) {
        if (icon == null)
            return;

        // only for JB 4.2 and 4.2.1
        if (android.os.Build.VERSION.SDK_INT != Build.VERSION_CODES.JELLY_BEAN &&
                android.os.Build.VERSION.SDK_INT != Build.VERSION_CODES.JELLY_BEAN_MR1)
            return;

        try {
            Class<?> textview = Class.forName("android.widget.TextView");
            Field tEditor = textview.getDeclaredField("mEditor");
            tEditor.setAccessible(true);
            Class<?> editor = Class.forName("android.widget.Editor");
            Method privateShowError = editor.getDeclaredMethod("setErrorIcon", Drawable.class);
            privateShowError.setAccessible(true);
            privateShowError.invoke(tEditor.get(this), icon);
        } catch (Exception e) {
            // e.printStackTrace(); // oh well, we tried
        }
    }
}

关于某些运行 Jelly Bean/4.2.1 的设备的 Android 操作系统错误 - TextView.setError(CharSequence error) 缺少图标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13756978/

相关文章:

java - EditText 插入点与文本颜色相同(@null 不起作用)

java - 从 EditText 获取文本字符串?

java - 在类之间传递 TextView 值时出错

android - 如何使用 Compound Drawable 垂直对齐 TextView 中的文本

android - 根据数据库大小计算ProgressBar大小

java - 无法在 Android 中使用 Picasso 从 URL 加载图像

java - 下面代码的算法名称是什么?

android - 如何使必填字段的 TextInputLayout 提示星号为红色

java - Android View 添加 child

android - 我怎样才能知道手机的电量消耗