Ошибка ОС Android на некоторых устройствах под управлением Jelly Bean/4.2.1 - TextView.setError(ошибка CharSequence) Отсутствует значок

На некоторых, но не на всех устройствах с Jelly Bean (4.2.1) отсутствует значок ошибки восклицательного знака, который должен отображаться на TextView (или, чаще, EditText) на котором установлена ​​ошибка через TextView.setError(CharSequence error),

В Galaxy Nexus определенно не хватает иконки.

В результате состояние ошибки устанавливается setError очевидно только тогда, когда EditText имеет фокус. Это делает setError(...) гораздо менее полезный, поскольку он часто используется, чтобы побудить пользователей вернуться к этому EditText чтобы решить проблему. Например, у вас есть стандартный экран входа в систему с записями имени пользователя и пароля, которые проверяются, когда пользователь нажимает кнопку отправки. Сообщение об ошибке проверки, установленное в форме имени пользователя, не будет отображаться до тех пор, пока пользователь не вернется к этой форме - это то, для чего предназначен значок ошибки!

Для проверки: (может быть более доступный EditText, но этот очень широко доступен)

  1. Открыть настройки
  2. Выберите "Добавить аккаунт" (это в "Аккаунтах и ​​синхронизации" на старых устройствах)
  3. Выберите "Google" в качестве типа учетной записи
  4. Выберите "Существующий" (после нажатия "Далее" и "Вход" на старых устройствах)
  5. Оставив "Email" EditText пусто, нажмите на "Пароль" EditText

На данный момент, ошибка установлена ​​на "Email" EditText говоря, что это не может быть пустым. На устройствах, у которых нет этой проблемы, отображается обычный значок ошибки, который расширяется до полного сообщения об ошибке, когда EditText имеет фокус. На Galaxy Nexuses под управлением Jelly Bean значок не отображается, а ошибка видна только при "электронной почте". EditText снова сфокусирован и до сих пор не имеет иконки.

Это похоже на ошибку, но я хотел проверить, могут ли другие люди воспроизвести ее, иметь представление о том, в чем может быть проблема, и найти хороший обходной путь.

С помощью setError(CharSequence error, Drawable icon) возможно, все будет исправлено, но было бы неплохо иметь возможность использовать графическую ошибку в разных версиях Android.

2 ответа

Временное решение!EditTextErrorFixed.java

Хотя это действительно ошибка SDK, мне удалось использовать методы отражения, чтобы заставить значок работать так, как задумано. Я проверил, что он работает как с 4.2, так и с 4.2.1, и убедился, что он работает на моем обновленном Galaxy Nexus.

Источник можно найти здесь.

На скриншоте видно, что значок внизу EditTextErrorFixed сохраняется, даже если фокус меняется. Кроме того, он включает в себя еще одно исправление, где, если пользователь нажимает Удалить на уже пустом EditText ошибка исчезает (еще одна ошибка?).

Демо-изображение

Для удобства вот 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://stackru.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
        }
    }
}

Я знаю, что здесь уже есть решение. Просто я пытаюсь избежать отражения любой ценой на Android. Если у вас все в порядке с отражением, попробуйте, но сначала попробуйте мое решение, приведенное ниже, так как это может решить проблему без подкласса и отражения.

Drawable d= getResources().getDrawable(R.drawable.ic_launcher);
            d.setBounds(0, 0, 
                    d.getIntrinsicWidth(), d.getIntrinsicHeight());

            et.setError("my error",d);
Другие вопросы по тегам