Шрифт подсказки пароля в Android

255

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

Мой текущий xml:

<EditText 
android:hint="@string/edt_password_hint"
android:layout_width="fill_parent"
android:layout_height="wrap_content" 
android:password="true"
android:singleLine="true" />
hpique
источник
1
Обратите внимание, что не все устройства ведут себя таким образом. «HTC One X @ 4.1.1» делает (моноширинный). "Samsung GT-7510 @ 4.0.4" нет. (тот же шрифт)
Loda
1
Такое же поведение на LeWa OS 4.2.2. Слишком непоследовательный API ..
ruX
все еще существует в
леденце
Вы можете проверить мой ответ здесь, надеюсь, что это работает.
Дмила Рам

Ответы:

395

Изменение шрифта в xml также не сработало для текста подсказки. Я нашел два разных решения, второе из которых имеет лучшее поведение для меня:

1) Удалите android:inputType="textPassword"из вашего XML-файла и вместо этого установите его в Java:

EditText password = (EditText) findViewById(R.id.password_text);
password.setTransformationMethod(new PasswordTransformationMethod());

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

2) Оставьте android:inputType="textPassword"в своем XML. В Java ТАКЖЕ установить гарнитуру и passwordMethod:

EditText password = (EditText) findViewById(R.id.register_password_text);
password.setTypeface(Typeface.DEFAULT);
password.setTransformationMethod(new PasswordTransformationMethod());

Этот подход дал мне шрифт подсказки, который я хотел И дал мне поведение, которое я хочу с точками пароля.

Надеюсь, это поможет!

Маниша
источник
3
Отлично, это странное поведение, вы не ожидаете от дефолта!
Сандер Верслуйс
15
Это password.setTransformationMethod(new PasswordTransformationMethod());необходимо? Кажется, работает нормально для меня без.
loeschg
1
Мне не нужно было использовать setTransformationMethod()либо. Однако у этого подхода есть некоторые побочные эффекты, которые делают его нежелательным, поскольку он приводит к нестандартному поведению по сравнению с поведением по умолчанию textPassword. Для более полного решения см. Вспомогательный класс по адресу: stackoverflow.com/a/17582092/231078
Джо,
10
Еще лучше, посмотрите на это замечательное простое решение в ответе прямо на этой странице: stackoverflow.com/a/18073897
Marcin Koziński
16
Помните, что использование первого решения - плохая идея - пользователи, у которых включена функция автоматического предложения, начнут видеть свой пароль в других предложенных им приложениях, поскольку EditText не был объявлен какinputType="textPassword"
Elad Nava
193

Я нашел этот полезный совет в Руководстве по диалогам

Совет: по умолчанию, когда вы устанавливаете элемент EditText для использования типа ввода «textPassword», семейство шрифтов устанавливается на моноширинный, поэтому вы должны изменить его семейство шрифтов на «sans-serif», чтобы оба текстовых поля использовали соответствующий шрифт стиль.


Например

android:fontFamily="sans-serif"
aysonje
источник
21
Это должен быть принятый ответ. Это проще, и это из документов.
Марцин Козиньски,
29
Это хорошо, за исключением того, что он работает только на уровне API 16 и выше
Бен Клэйтон
6
Обратите внимание, что хотя он работает только на уровне API 16 и выше, атрибуты xml не вызывают сбои на старых устройствах, они просто игнорируются.
Адам Джонс
Это не будет работать, если вы нажмете показать / скрыть пароль несколько раз
Али Хаббаш
32

Это то, что я сделал, чтобы исправить эту проблему. По какой-то причине мне не пришлось устанавливать метод преобразования, так что это может быть лучшим решением:

В моем XML:

<EditText
    android:id="@+id/password_edit_field"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:hint="Password"
    android:inputType="textPassword" />

По моему Activity:

EditText password = (EditText) findViewById( R.id.password_edit_field );
password.setTypeface( Typeface.DEFAULT );
Джеймс МакКракен
источник
Я только что попробовал это с textPassword в XML и как вы делали в файле .java, и это работало просто отлично. Для меня это, казалось, не нуждалось в преобразовании
Джо Планте
2
Напоминание: вызовите setTypeface () ПОСЛЕ того, как вы измените InputType по коду. setTransformationMethod не требуется, если InputType include xx_VARIATION_PASSWORD;
Лода
21

Подход setTransformationMethod ломает для меня android: imeOption и позволяет вводить возврат каретки в поле пароля. Вместо этого я делаю это:

setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
setTypeface(Typeface.DEFAULT);

И я не устанавливаю Android: пароль = "истина" в XML.

rjrjr
источник
да, это работало для меня в 6.0.1, а выбранный ответ
Nactus
5

Ответ, предоставленный manisha, работает, но он оставляет поле пароля в нестандартном состоянии по сравнению со значением по умолчанию. Таким образом, шрифт по умолчанию затем применяется также к полю пароля, включая как замены точек, так и символы предварительного просмотра, которые появляются перед заменой на точки (а также когда это поле «видимый пароль»).

Чтобы это исправить и сделать так, чтобы 1) выглядел и действовал точно так же, как textPasswordтип ввода по умолчанию , но также 2) позволял тексту подсказки отображаться шрифтом по умолчанию (не моноширинный), вам нужно иметь TextWatcherполе on, которое может переключать Шрифт правильно и обратно между Typeface.DEFAULTи в Typeface.MONOSPACEзависимости от того, является ли он пустым или нет. Я создал вспомогательный класс, который можно использовать для достижения этой цели:

import android.graphics.Typeface;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;

/**
 * This class watches the text input in a password field in order to toggle the field's font so that the hint text
 * appears in a normal font and the password appears as monospace.
 *
 * <p />
 * Works around an issue with the Hint typeface.
 *
 * @author jhansche
 * @see <a
 * href="http://stackoverflow.com/questions/3406534/password-hint-font-in-android">http://stackoverflow.com/questions/3406534/password-hint-font-in-android</a>
 */
public class PasswordFontfaceWatcher implements TextWatcher {
    private static final int TEXT_VARIATION_PASSWORD =
            (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
    private TextView mView;

    /**
     * Register a new watcher for this {@code TextView} to alter the fontface based on the field's contents.
     *
     * <p />
     * This is only necessary for a textPassword field that has a non-empty hint text. A view not meeting these
     * conditions will incur no side effects.
     *
     * @param view
     */
    public static void register(TextView view) {
        final CharSequence hint = view.getHint();
        final int inputType = view.getInputType();
        final boolean isPassword = ((inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION))
                == TEXT_VARIATION_PASSWORD);

        if (isPassword && hint != null && !"".equals(hint)) {
            PasswordFontfaceWatcher obj = new PasswordFontfaceWatcher(view);
            view.addTextChangedListener(obj);

            if (view.length() > 0) {
                obj.setMonospaceFont();
            } else {
                obj.setDefaultFont();
            }
        }
    }

    public PasswordFontfaceWatcher(TextView view) {
        mView = view;
    }

    public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
        // Not needed
    }

    public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
        if (s.length() == 0 && after > 0) {
            // Input field went from empty to non-empty
            setMonospaceFont();
        }
    }

    public void afterTextChanged(final Editable s) {
        if (s.length() == 0) {
            // Input field went from non-empty to empty
            setDefaultFont();
        }
    }

    public void setDefaultFont() {
        mView.setTypeface(Typeface.DEFAULT);
    }

    public void setMonospaceFont() {
        mView.setTypeface(Typeface.MONOSPACE);
    }
}

Затем, чтобы использовать его, все, что вам нужно сделать, это вызвать register(View)статический метод. Все остальное происходит автоматически (включая пропуск обходного пути, если представление не требует этого!):

    final EditText txtPassword = (EditText) view.findViewById(R.id.txt_password);
    PasswordFontfaceWatcher.register(txtPassword);
Джо
источник
1
Хорошая работа. Одно небольшое изменение: если вы установите шрифт на EditText(например, сделав текст подсказки Roboto Light), то настройка Typeface.DEFAULTпозже отменит это. Я вызываю field.getTypeface()сразу и использую эту гарнитуру всякий раз, когда мне нужно позже вернуться к шрифту «по умолчанию».
Кристофер Орр
Что ж, звонки field.getTypeface()не кажутся надежными на 100% (так как часто вы просто возвращаете моноширинный шрифт), но создаете гарнитуру с помощью Typeface.create()и затем настройку, которая, кажется, работает хорошо.
Кристофер Орр
5

Есть много способов решения этой проблемы, но у каждого есть свои плюсы и минусы. Вот мое тестирование

Я сталкиваюсь с этой проблемой шрифтов только на каком-то устройстве (список в конце моего ответа), когда разрешить ввод пароля

edtPassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);

Если я использую android:inputType="textPassword", этой проблемы не случилось

Что-то я пробовал

1) Используйте setTransformationMethodвместоinputType

edtPassword.setTransformationMethod(PasswordTransformationMethod.getInstance());
  • Шрифт будет работать хорошо
  • Клавиатура отображается не очень хорошо (она отображает только текст, но не отображает число поверх текста)

2) Использование Typeface.DEFAULT

setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
setTypeface(Typeface.DEFAULT);
  • Клавиатура хорошо отображается ,
  • Шрифт может работать не очень хорошо . Пример sans-serif-light- это шрифт по умолчанию для всех Viewв моем приложении => после setTypeface(Typeface.DEFAULT), EditTextшрифт по-прежнему выглядит по- другому на некоторых устройствах

3) Использование android:fontFamily="sans-serif"

  • Для некоторых устройств это будет CRASH , проверьте мой ответ здесь https://stackoverflow.com/a/52421199/5381331 . А также шрифт по-прежнему выглядит по- другому

МОЕ РЕШЕНИЕ

кэшируйте шрифт перед setInputTypeтем, как использовать его снова

Typeface cache = edtPassword.getTypeface();
edtPassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
edtPassword.setTypeface(cache);

Тестирование
Некоторое устройство сталкивается с проблемой шрифта

  • Xiaomi A2 (8.0.1)
  • Пиксель XL (8.1.0)
  • Sony Xperia Z5 Au (SOV32) (6,0)
  • Стрелка NX (F-04G) (6.0.1)
  • Kyocera (S2) (7,0)

Некоторые устройства не сталкиваются с проблемой шрифтов

  • Samsung S4 (SC-04E) (5.0.1)
  • Samsung Galaxy Node 5 (5.1.1)
  • Samsung S7 Edge (SM-G935F) (7,0)
Фан Ван Линь
источник
Какое устройство (имя и ОС)?
CoolMind
1
@CoolMind спасибо за ваше предложение, у меня есть проблема с шрифтом на устройстве, а на моем устройстве нет проблемы со шрифтом
Phan Van Linh
Спасибо за большое тестирование! Я пришел с нее из stackoverflow.com/a/52178340/2914140 . На Samsung S4 я использовал setTransformationMethodметод (где не сталкивался с проблемой).
CoolMind
Как я упоминаю в своем ответе, setTransformationMethodбудет работать, но клавиатура не будет отображаться хорошо. Тем не менее, если вы согласны с этим, то это все еще хорошо, потому что это просто небольшая проблема
Phan Van Linh
4

Другие ответы являются правильным решением для большинства случаев.

Однако, если вы используете пользовательский EditTextподкласс, скажем, для применения пользовательского шрифта по умолчанию, возникает небольшая проблема. Если вы установите собственный шрифт в конструкторе вашего подкласса, он все равно будет перезаписан системой, если вы установите inputType="textPassword".

В этом случае переместите ваш стиль на onAttachedToWindowпосле super.onAttachedToWindowвызова.

Пример реализации:

package net.petosky.android.ui;

import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.EditText;

/**
 * An EditText that applies a custom font.
 *
 * @author cory@petosky.net
 */
public class EditTextWithCustomFont extends EditText {

    private static Typeface customTypeface;

    public EditTextWithCustomFont(Context context) {
        super(context);
    }

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

    public EditTextWithCustomFont(
            Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * Load and store the custom typeface for this app.
     *
     * You should have a font file in: project-root/assets/fonts/
     */
    private static Typeface getTypeface(Context context) {
        if (customTypeface == null) {
            customTypeface = Typeface.createFromAsset(
                    context.getAssets(), "fonts/my_font.ttf");
        }
        return customTypeface;
    }

    /**
     * Set a custom font for our EditText.
     *
     * We do this in onAttachedToWindow instead of the constructor to support
     * password input types. Internally in TextView, setting the password
     * input type overwrites the specified typeface with the system default
     * monospace.
     */
    @Override protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        // Our fonts aren't present in developer tools, like live UI
        // preview in AndroidStudio.
        if (!isInEditMode()) {
            setTypeface(getTypeface(getContext()));
        }
    }
}
Кори Петоски
источник
3

Я знаю, что это может быть более старый, но я столкнулся с чем-то связанным с этой проблемой, когда я использовал InputTypeи app:passwordToggleEnabled="true"вместе.

Итак, пишите это, так как это может помочь кому-то здесь.

Я хочу использовать пользовательский шрифт в поле пароля вместе с app:passwordToggleEnabledопцией для моего поля ввода пароля. Но в 27.1.1 (при написании этой) библиотеки поддержки она вылетала.

Таким образом, код был как ниже,

<android.support.design.widget.TextInputLayout
        android:id="@+id/input_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/_10dp"
        android:layout_marginTop="@dimen/_32dp"
        android:hint="@string/current_password"
        android:textColorHint="@color/hint_text_color"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:passwordToggleEnabled="true"
        app:passwordToggleTint="@color/black">


        <EditText
            android:id="@+id/password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="start|left"
            android:maxLines="1"
            android:textAlignment="viewStart"
            android:textColor="@color/black"
            android:textColorHint="@color/camel"
            android:textSize="@dimen/txt_16sp"
            app:font_style="regular"
            app:drawableEnd="@drawable/ic_remove_eye" />

    </android.support.design.widget.TextInputLayout>

Выше код не inputTypeопределен в XML

EditText password = (EditText) findViewById(R.id.password);
password.setTransformationMethod(new PasswordTransformationMethod());

И в Java, setTransformationMethodпоможет мне приобрести свойства типа textPasswordввода, а также я рад, что мой собственный стиль шрифта.

Но нижеупомянутый сбой произошел на всех уровнях API с библиотекой поддержки 27.1.1.

java.lang.NullPointerException: попытка вызвать виртуальный метод 'void android.support.design.widget.CheckableImageButton.setChecked (boolean)' для ссылки на пустой объект

Это было сбой из-за onRestoreInstanceStateвнутреннего TextInputLayoutкласса.

Воспроизвести шаги. Переключите видимость пароля, сверните приложение и откройте его из последних приложений. Ой, хо разбился!

Все, что мне нужно, это опция переключения пароля по умолчанию (с помощью библиотеки поддержки) и пользовательский шрифт в поле ввода пароля.

Через некоторое время разобрался, сделав, как показано ниже,

<android.support.design.widget.TextInputLayout
        android:id="@+id/input_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/_10dp"
        android:layout_marginTop="@dimen/_32dp"
        android:hint="@string/current_password"
        android:textColorHint="@color/hint_text_color"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:passwordToggleEnabled="true"
        app:passwordToggleTint="@color/black">


        <EditText
            android:id="@+id/password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="start|left"
            android:maxLines="1"
            android:textAlignment="viewStart"
            android:textColor="@color/black"
            android:textColorHint="@color/camel"
            android:textSize="@dimen/txt_16sp"
            app:font_style="regular"
            app:drawableEnd="@drawable/ic_remove_eye"
            android:inputType="textPassword" />

    </android.support.design.widget.TextInputLayout>

В XML добавлено android:inputType="textPassword"

TextInputLayout inputPassword = findViewById(R.id.input_password);
EditText password = findViewById(R.id.password);
EditText userName = findViewById(R.id.user_name);
// Get the typeface of user name or other edit text
Typeface typeface = userName.getTypeface();
if (typeface != null)
   inputLayout.setTypeface(typeface); // set to password text input layout

В приведенном выше коде Java,

Я получил пользовательский шрифт от имени пользователя EditTextи применил его к TextInputLayoutполю пароля. Теперь вам не нужно явно устанавливать гарнитуру для пароля, так EditTextкак он получит TextInputLayoutсвойство.

Также я удалил password.setTransformationMethod(new PasswordTransformationMethod());

Таким образом, passwordToggleEnabledработает, пользовательский шрифт также применяется и до свидания до сбоя. Надеюсь, что эта проблема будет исправлена ​​в следующих выпусках поддержки.

Кавин Прабху
источник
2

Вы также можете использовать собственный виджет. Это очень просто и не загромождает ваш код действия / фрагмента.

Вот код:

public class PasswordEditText extends EditText {

  public PasswordEditText(Context context) {
    super(context);
    init();
  }

  public PasswordEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();

  }

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

  private void init() {
    setTypeface(Typeface.DEFAULT);
  }
}

И ваш XML будет выглядеть так:

<com.sample.PasswordEditText
  android:id="@+id/password_edit_field"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:hint="Password"
  android:inputType="textPassword"
  android:password="true" />
Альдо Борреро
источник
По моему опыту это не работает - TextViewкажется, внутренне перезаписывают пользовательский шрифт после вызова конструктора. Предусмотрен обходной путь в другом ответе.
Кори Петоски
2

использовать библиотеку каллиграфии .

тогда это все еще не обновит поля пароля с правильным шрифтом. так что делайте это в коде, а не в XML:

Typeface typeface_temp = editText.getTypeface();
editText.setInputType(inputType); /*whatever inputType you want like "TYPE_TEXT_FLAG_NO_SUGGESTIONS"*/
//font is now messed up ..set it back with the below call
editText.setTypeface(typeface_temp); 
j2emanue
источник
0

Недавно я добавил возможность изменения вкл / выкл монопространства для расширения EditText специально для паролей, это может помочь некоторым людям. Он не использует, android:fontFamilyпоэтому совместим <16.

scottyab
источник
0

Вы также можете использовать

<android.support.design.widget.TextInputLayout/>

вместе с

<android.support.v7.widget.AppCompatEditText/>
DoruChidean
источник
0

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

public class PasswordEditText extends android.support.v7.widget.AppCompatEditText {

    public PasswordEditText(Context context) {
        super(context);
    }

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

    public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        if (text.length() > 0) setTypeface(Typeface.MONOSPACE);
        else setTypeface(Typeface.DEFAULT);
    }

}
KTCO
источник
0

Если вы используете библиотеку каллиграфии в сочетании с TextInputLayout и EditText, следующий код работает хорошо.

    EditText password = (EditText) findViewById(R.id.password);
    TextInputLayout passwordLayout = (TextInputLayout) findViewById(R.id.passwordLayout);

    Typeface typeface_temp = password.getTypeface();
    password.setInputType(InputType.TYPE_CLASS_TEXT |
            InputType.TYPE_TEXT_VARIATION_PASSWORD); 

    password.setTypeface(typeface_temp);
    passwordLayout.setTypeface(typeface_temp);
Филипп Хельмайр
источник
Это не изменило мою подсказку шрифта
Рафаэль Руис Муньос
0

Странный случай, возможно, но я экспериментировал с этим и обнаружил, что:

password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
password.setTransformationMethod(new PasswordTransformationMethod());

изменил размер шрифта подсказки вместо самого шрифта! Это все еще нежелательный эффект. Как ни странно, обратная операция:

password.setTransformationMethod(new PasswordTransformationMethod());
password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);

Сохраняет одинаковый размер шрифта.

MPelletier
источник
0

Я нашел верное решение этой проблемы

Лучший способ Привет, я нашел верное решение этой проблемы

Лучший способ - создать собственный editText и сохранить значение гарнитуры как темп, а затем применить метод к изменениям InputType. Наконец, мы возвращаем значение шрифта типа temp к editText. вот так :

public class AppCompatPasswordEditText extends AppCompatEditText {


    public AppCompatPasswordEditText(Context context) {
        super(context);
    }

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

    public AppCompatPasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        // Our fonts aren't present in developer tools, like live UI
        // preview in AndroidStudio.
        Typeface cache = getTypeface();

        if (!isInEditMode() && cache != null) {
            setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
            setTypeface(cache);
        }
    }

}
Mr.Hosseini
источник
-1

Это как сделать ввод пароля с подсказкой, которая не конвертируется в * и шрифтом по умолчанию !!

По XML:

android:inputType="textPassword"
android:gravity="center"
android:ellipsize="start"
android:hint="Input Password !."

На активность:

inputPassword.setTypeface(Typeface.DEFAULT);

спасибо: манго и Rjrjr за понимание: D.

Bhimbim
источник
-2

как и выше, но убедитесь, что поля не выделены жирным шрифтом в xml, так как они никогда не будут выглядеть одинаково даже с вышеуказанным исправлением!

Дори
источник
2
Не говорите «выше» ... все меняется со временем :-)
ZaBlanc