Ошибка ОС 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, но этот очень широко доступен)
- Открыть настройки
- Выберите "Добавить аккаунт" (это в "Аккаунтах и синхронизации" на старых устройствах)
- Выберите "Google" в качестве типа учетной записи
- Выберите "Существующий" (после нажатия "Далее" и "Вход" на старых устройствах)
- Оставив "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);