Подтвердить что ты не робот

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

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

enter image description hereenter image description here

В Galaxy Nexus определенно отсутствует значок.

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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
        }
    }
}

Ответ 2

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

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

            et.setError("my error",d);