【问题标题】:Password hint font in AndroidAndroid中的密码提示字体
【发布时间】:2011-03-25 07:22:11
【问题描述】:

当 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" />

【问题讨论】:

  • 请注意,并非所有设备都以这种方式运行。 “HTC One X @ 4.1.1”可以(等宽)。 “Samsung GT-7510 @4.0.4”没有。 (相同字体)
  • 在 LeWa OS 4.2.2 上的行为相同。 API 太不一致..
  • 仍然存在于棒棒糖中
  • 你可以查看我的回答here希望它有效。

标签: android fonts passwords android-edittext


【解决方案1】:

更改 xml 中的字体对我来说也不适用于提示文本。我找到了两种不同的解决方案,其中第二种对我来说效果更好:

1) 从您的 xml 文件中删除 android:inputType="textPassword",然后在 java 中设置它:

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

使用这种方法,提示字体看起来不错,但是当您在该编辑字段中输入时,您不会在纯文本中看到每个字符,然后才会变成密码点。另外全屏输入时,不会出现圆点,而是明文密码。

2) 在您的 xml 中保留 android:inputType="textPassword"。在Java中,ALSO设置字体和密码方法:

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

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

希望有帮助!

【讨论】:

  • 太好了,这是一些奇怪的行为,默认情况下你不会想到!
  • password.setTransformationMethod(new PasswordTransformationMethod()); 有必要吗?如果没有,我似乎可以正常工作。
  • 我也不需要使用setTransformationMethod()。但是,这种方法有一些副作用,使其不受欢迎,因为与默认的 textPassword 行为相比,它会导致非标准行为。如需更完整的解决方案,请参阅帮助程序类:stackoverflow.com/a/17582092/231078
  • 更好的是,在此页面上的答案中查看这个很棒的简单解决方案:stackoverflow.com/a/18073897
  • 请注意,使用第一个解决方案是个坏主意 - 启用自动建议的用户将开始在其他应用程序中看到他们的密码,向他们建议,因为 EditText 未声明为 @987654330 @
【解决方案2】:

我从Dialogs Guide 发现了这个有用的提示

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


例如

android:fontFamily="sans-serif"

【讨论】:

  • 这应该是公认的答案。它更简单,并且来自文档。
  • 很好,只是它只适用于API级别16及以上
  • 请注意,虽然它仅适用于 API 级别 16 及更高级别,但 xml 属性不会导致旧设备上的崩溃,它们只是被忽略。
  • 多次点击显示/隐藏密码无效
【解决方案3】:

这就是我为解决这个问题所做的。出于某种原因,我不必设置转换方法,所以这可能是一个更好的解决方案:

在我的 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 文件中所做的那样,它工作得很好。对我来说,它似乎不需要转型
  • 提醒:通过代码更改 InputType 后调用 setTypeface()。如果 InputType 包含 xx_VARIATION_PASSWORD,则不需要 setTransformationMethod;
【解决方案4】:

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

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

并且我没有在 XML 中设置 android:password="true"。

【讨论】:

  • yap,这在 6.0.1 中也适用于我,选择的答案没有
【解决方案5】:

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

要解决此问题并使其 1) 看起来和行为与默认的 textPassword 输入类型完全相同,而且 2) 允许提示文本以默认(非等宽)字体出现,您需要有一个 @ 987654322@ 在字段上可以根据是否为空在Typeface.DEFAULTTypeface.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);

【讨论】:

  • 干得好。一个小改动:如果你在EditText 上设置了一种字体(例如,使提示文本 Roboto Light),那么稍后设置Typeface.DEFAULT 将覆盖它。我会提前致电field.getTypeface(),并在以后需要重置为“默认”字体时使用该字体。
  • 好吧,调用 field.getTypeface() 似乎不是 100% 可靠的(因为通常你会得到等宽字体),但是通过 Typeface.create() 创建一个字体然后设置似乎工作得很好。
【解决方案6】:

有很多方法可以解决这个问题,但每种方法都有利有弊。这是我的测试

当通过

启用输入密码时,我只在某些设备中面对这个字体问题(在我的答案末尾列出)
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"

我的解决方案

缓存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 谢谢你的建议,我已经更新了设备的字体问题和设备不面对字体问题基于我当前的设备
  • 感谢您的大型测试!我来自stackoverflow.com/a/52178340/2914140。在三星 S4 上,我使用了setTransformationMethod 方法(没有遇到问题)。
  • 正如我在回答中提到的,setTransformationMethod 可以工作,但键盘无法正常显示。但是,如果你接受它,它仍然可以,因为它只是一个小问题
【解决方案7】:

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

但是,如果您使用自定义 EditText 子类来默认应用自定义字体,则会出现一个微妙的问题。如果你在子类的构造函数中设置了自定义字体,设置inputType="textPassword",它仍然会被系统覆盖。

在这种情况下,在调用 super.onAttachedToWindow 之后将样式移至 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()));
        }
    }
}

【讨论】:

    【解决方案8】:

    我知道这可能是较旧的,但是当我一起使用 InputTypeapp:passwordToggleEnabled="true"together 时,我遇到了与此问题相关的问题。

    所以,写这个,因为它可以帮助这里的人。

    我想对密码字段使用自定义字体以及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>
    

    以上代码没有在 XML 中定义 inputType

    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 正在工作,自定义字体也被应用,并且再见了崩溃。希望这个问题将在即将发布的支持版本中得到解决。

    【讨论】:

      【解决方案9】:

      您还可以使用自定义小部件。它非常简单,不会弄乱您的 Activity/Fragment 代码。

      代码如下:

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

      使用calligraphy library

      那么它仍然不会使用正确的字体更新密码字段。所以在代码中而不是在 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); 
      

      【讨论】:

        【解决方案11】:

        我最近添加了将切换等宽空间打开/关闭更改为extension of EditText 的功能,专门用于密码,它可能对某些人有所帮助。它不使用android:fontFamily,因此兼容

        【讨论】:

          【解决方案12】:

          你也可以使用

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

          一起

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

          【讨论】:

            【解决方案13】:

            我使用此解决方案根据提示可见性切换字体。它类似于 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);
                }
            
            }
            

            【讨论】:

              【解决方案14】:

              如果您将calligraphy library 与 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);
              

              【讨论】:

              • 这并没有修改我的提示字体
              【解决方案15】:

              也许是一个奇怪的案例,但我对此进行了实验并发现:

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

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

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

              保持相同的字体大小。

              【讨论】:

                【解决方案16】:

                我找到了解决这个问题的可靠方法

                打招呼的最佳方式,我找到了解决此问题的可靠方法

                最好的方法是创建一个自定义的editText并将字体的值保存为临时,然后将该方法应用于InputType更改,最后我们将临时类型的值设置回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);
                        }
                    }
                
                }
                

                【讨论】:

                  【解决方案17】:

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

                  关于 XML:

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

                  在活动中:

                  inputPassword.setTypeface(Typeface.DEFAULT);
                  

                  感谢:mango 和 rjrjr 的洞察力:D。

                  【讨论】:

                    【解决方案18】:

                    与上述类似,但请确保字段在 xml 中没有粗体样式,因为即使经过上述修复,它们看起来也不会相同!

                    【讨论】:

                    • 不要说“以上”...事情会随着时间而改变 :-)
                    猜你喜欢
                    • 2014-07-27
                    • 2019-12-26
                    • 2013-05-04
                    • 2017-11-13
                    • 2012-10-07
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多