Android中的密码提示字体


255

当EditText处于密码模式时,提示似乎以不同的字体显示(Courrier?)。如何避免这种情况?我希望提示以与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" />

1
请注意,并非所有设备都以这种方式运行。“ HTC One X @ 4.1.1”可以(等宽)。“ Samsung GT-7510 @ 4.0.4”没有。(相同的字体)
Loda

1
LeWa OS 4.2.2上的行为相同。太不一致API ..
RUX

棒棒糖中仍然存在
Mightian

您可以在这里查看我的答案希望它能起作用。
Dmila Ram

Answers:


394

对我来说,更改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中,还应设置字体和密码方法:

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

这种方法给了我想要的提示字体,并给了我想要的带有密码点的行为。

希望有帮助!


3
太好了,这是一些奇怪的行为,您不会期望默认!
Sander Versluys

15
password.setTransformationMethod(new PasswordTransformationMethod());必要吗?似乎对我来说没有问题。
loeschg 2012年

1
我不需要使用setTransformationMethod()任何一个。但是,此方法有一些副作用,使其不受欢迎,因为与默认textPassword行为相比,它会导致非标准行为。有关更完整的解决方案,请参见以下帮助器类:stackoverflow.com/a/17582092/231078

10
更好的是,在此页面上的答案中查看这个出色的简单解决方案:stackoverflow.com/a/18073897
MarcinKoziński2014年

16
请注意,使用第一种解决方案是个坏主意-向他们建议,已启用自动建议功能的用户将开始在其他应用中看到密码,因为未将EditText声明为inputType="textPassword"
Elad Nava 2014年

193

我从《对话指南》中找到了这个有用的技巧

提示:默认情况下,当您将EditText元素设置为使用“ textPassword”输入类型时,字体系列设置为等宽字体,因此您应将其字体系列更改为“ sans-serif”,以便两个文本字段都使用匹配的字体样式。


例如

android:fontFamily="sans-serif"

21
这应该是公认的答案。它更简单,来自文档。
MarcinKoziński2014年

29
很好,除了它仅适用于API级别16及以上
Ben Clayton 2014年

6
请注意,虽然xml属性仅适用于API级别16及更高级别,但不会在较旧的设备上导致崩溃,但它们只会被忽略。
亚当·约翰斯

如果多次单击“显示/隐藏密码”,它将不起作用
Ali Habbash

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 );

我只是使用XML中的textPassword进行了尝试,就像您在.java文件中所做的那样,它工作得很好。对我来说,它似乎不需要改造
Joe Plante

2
提醒:在通过代码更改InputType之后,调用setTypeface()。如果InputType包含xx_VARIATION_PASSWORD,则不需要setTransformationMethod;
洛达(Loda)2013年

21

setTransformationMethod方法为我破坏了android:imeOption,并允许在密码字段中输入回车符。相反,我正在这样做:

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

并且未在XML中设置android:password =“ true”。


是的,这在6.0.1中对我也有效,选择的答案没有
Nactus

5

提供的答案manisha确实有效,但是与默认值相比,它使密码字段处于非标准状态。也就是说,默认字体也会应用于密码字段,包括点替换和在用点替换之前(以及当它是“可见密码”字段时出现的)预览字符。

要解决此问题并使其变得1)外观和行为与默认textPassword输入类型完全相同,但是2)允许提示文本以默认(非等宽字体)字体显示,您需要TextWatcher在字段上设置一个可以切换fontface正确来回之间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)static方法。其他一切都是自动的(如果不需要视图,则包括跳过解决方法!):

    final EditText txtPassword = (EditText) view.findViewById(R.id.txt_password);
    PasswordFontfaceWatcher.register(txtPassword);

1
辛苦了 一个小小的更改:如果在上设置了字体EditText(例如,使提示文本为Roboto Light),则Typeface.DEFAULT稍后进行设置将覆盖此字体。我先打电话给我field.getTypeface(),然后在以后需要重置为“默认”字体时使用该字体。
Christopher Orr 2013年

好吧,调用field.getTypeface()似乎并不是100%可靠的(通常您会得到等宽字体),但是通过创建一个Typeface Typeface.create()然后进行设置似乎效果很好。
Christopher Orr 2013年

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-lightView我的应用程序中所有字体的默认字体=>之后setTypeface(Typeface.DEFAULT),该EditText字体在某些设备中仍然看起来有所不同

3)使用 android:fontFamily="sans-serif"

我的解决方案

缓存字体,setInputType然后再使用它

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

测试
某些设备字体字体问题

  • 小米A2(8.0.1)
  • 像素XL(8.1.0)
  • 索尼Xperia Z5 Au(SOV32)(6.0)
  • 箭NX(F-04G)(6.0.1)
  • 京瓷(S2)(7.0)

某些设备没有字体问题

  • 三星S4(SC-04E)(5.0.1)
  • 三星Galaxy Node 5(5.1.1)
  • 三星S7 Edge(SM-G935F)(7.0)

什么是设备(名称和操作系统)?
CoolMind

1
@CoolMind感谢您的建议,我在当前设备上更新了设备面部字体问题和设备未面部字体问题
Phan Van Linh

谢谢您的大量测试!我来自stackoverflow.com/a/52178340/2914140。在三星S4上,我使用了setTransformationMethod方法(没有遇到问题)。
CoolMind

正如我在回答中提到的那样,setTransformationMethod可以正常工作,但键盘显示效果不佳。但是,如果您对此付诸表决,它仍然可以奏效,因为这只是一个小问题
Phan Van Linh

4

对于大多数情况,其他答案是正确的解决方案。

但是,如果您使用自定义EditText子类(例如,默认情况下应用自定义字体),则存在一个细微问题。如果您在子类的构造函数中设置了自定义字体,则如果设置,它仍将被系统覆盖inputType="textPassword"

在这种情况下,请onAttachedToWindowsuper.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

我知道这可能是较老的版本,但是当我使用InputTypeapp: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输入类型也很高兴获得自定义字体样式。

但是,以下提到的崩溃发生在具有27.1.1支持库的所有API级别中。

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似乎在构造函数调用后覆盖了自定义字体。在另一个答案中提供了一种解决方法。
Cory Petosky

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); 


0

您也可以使用

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

和...一起

<android.support.v7.widget.AppCompatEditText/>

0

我使用此解决方案根据提示可见性切换字体。它类似于Joe的答案,但是扩展了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);
    }

}

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);

这并没有修改我的提示字体
Rafael RuizMuñoz18年

0

也许很奇怪,但我对此进行了试验,发现:

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

更改了提示字体大小,而不是字体本身!这仍然是不希望的效果。奇怪的是,反向操作:

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

保持相同的字体大小。


0

我找到了解决这个问题的肯定方法

最好的方法,您好,我找到了解决此问题的可靠方法

最好的方法是创建一个自定义editText并将typeface的值保存为temp,然后将该方法应用于InputType更改,最后,将temp type face的值重新设置为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);
        }
    }

}

-1

这如何使输入的密码具有未转换为*和默认字体!!的提示。

在XML上:

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

活动中:

inputPassword.setTypeface(Typeface.DEFAULT);

感谢:mango和rjrjr的见解:D。


-2

类似于上述内容,但请确保这些字段在xml中不具有粗体样式,因为即使使用上述修复程序,它们也永远看起来不会相同!


2
不要说“之上” ...事情会随着时间而改变:-)
ZaBlanc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.