32

Someone tried to change the font of the floating label? I changed the source of EditText but the font of the floating label did not change, I am very grateful to those who help me

Code:

               <android.support.design.widget.TextInputLayout
                    android:id="@+id/tilTextoDescricao"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_toRightOf="@id/tilValorUnidade"
                    android:layout_marginTop="10dp">

                    <EditText
                        android:id="@+id/etTextoDescricao"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="5dp"
                        android:hint="Descrição"
                        android:textSize="15dp"
                        android:inputType="text" />

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

----------------- 

   etTextoDescricao= (EditText) findViewById(R.id.etTextoDescricao);
  etTextoDescricao.setTypeface(CustomTypeface.getTypefaceMediumDefault(this));

enter image description here

azizbekian
  • 53,978
  • 11
  • 145
  • 225
user2350939
  • 359
  • 1
  • 3
  • 9

12 Answers12

34

As of Design Library v23, you can use TextInputLayout#setTypeface().

This will set the typeface on both the expanded and floating hint.

Here is the feature request where it was discussed on b.android.com.

EDIT: The error view typeface was not being set, but is now fixed in v25.1.0.

Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
Austyn Mahoney
  • 11,078
  • 7
  • 59
  • 85
  • 4
    I did this and it worked for everything but the error view. I think the textappearance overwrites it, so that's probably a bug of some sort. To target the error view in specific, you can use the android-given ID to reference it like this: **((TextView)inputLayout.findViewById(R.id.textinput_error)).setTypeface(customFont);** – Justin Liu Jan 27 '17 at 08:08
  • @JustinLiu Your issue was fixed in Support Library v25.1.0 - https://code.google.com/p/android/issues/detail?id=227803 – Austyn Mahoney Jan 30 '17 at 23:12
21

Unfortunately, you'll have to use reflection to handle this.

The floating label is drawn by CollapsingTextHelper, which is an internal, package-private class and isn't setup to handle spans. So, using something like a custom TypefaceSpan won't work in this case.

Because this uses reflection, it isn't guaranteed to work in the future.

Implementation

final Typeface tf = Typeface.createFromAsset(getAssets(), "your_custom_font.ttf");
final TextInputLayout til = (TextInputLayout) findViewById(R.id.yourTextInputLayout);
til.getEditText().setTypeface(tf);
try {
    // Retrieve the CollapsingTextHelper Field
    final Field cthf = til.getClass().getDeclaredField("mCollapsingTextHelper");
    cthf.setAccessible(true);

    // Retrieve an instance of CollapsingTextHelper and its TextPaint
    final Object cth = cthf.get(til);
    final Field tpf = cth.getClass().getDeclaredField("mTextPaint");
    tpf.setAccessible(true);

    // Apply your Typeface to the CollapsingTextHelper TextPaint
    ((TextPaint) tpf.get(cth)).setTypeface(tf);
} catch (Exception ignored) {
    // Nothing to do
}

Error view

If you needed to change the font of the error, you could do one of two things:

  1. Use Reflection grab the error TextView and apply the Typeface much like before
  2. Use a custom span. Unlike the floating label, the error view used by TextInputLayout is just a TextView, so it's able to handle spans.

Using reflection

final Field errorField = til.getClass().getDeclaredField("mErrorView");
errorField.setAccessible(true);
((TextView) errorField.get(til)).setTypeface(tf);

Using a custom span

final SpannableString ss = new SpannableString("Error");
ss.setSpan(new FontSpan(tf), 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
til.setError(ss);

private static final class FontSpan extends MetricAffectingSpan {

    private final Typeface mNewFont;

    private FontSpan(Typeface newFont) {
        mNewFont = newFont;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setTypeface(mNewFont);
    }

    @Override
    public void updateMeasureState(TextPaint paint) {
        paint.setTypeface(mNewFont);
    }

}

Results

results

The font I'm using is Smoothie Shoppe.

adneal
  • 29,668
  • 10
  • 113
  • 145
  • How i can use this in single class, my issue is this i having so many layout then all the time i have to use this code in all the classes that's why i am asking.Is it possible? – Aman Jham Aug 06 '15 at 10:09
  • Terrible that you have to do it this way, but it'll works for now. However, ((TextView) errorField.get(til)) return null for me :( – Tobbbe Sep 24 '15 at 07:41
  • 7
    It seems that you can now use `setTypeface(Typeface typeface)` on the TextInputLayout. :) – StingRay5 Oct 27 '15 at 15:58
  • 2
    I want to change only floating label font. Is it possible? – LMaker Aug 25 '20 at 16:32
19

I'm using new MaterialComponents theme and none of the answers helped me.

Had to play with styles and themes on my own. Will post a chunk of styles here in case somebody faces the same issue.

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
  ...
  <item name="textInputStyle">@style/CustomFontTextInputLayout</item>
</style>  

<!-- region TextInputLayout & TextInputEditText styles -->
<style name="TextInputLayout.OutlineBox.CustomFont" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
  <item name="android:theme">@style/ThemeOverlay.TextInputEditText.OutlinedBox.CustomFont</item>
</style>

<style name="ThemeOverlay.TextInputEditText.OutlinedBox.CustomFont" parent="ThemeOverlay.MaterialComponents.TextInputEditText.OutlinedBox">
  <item name="editTextStyle">@style/TextInputEditText.OutlinedBox.CustomFont</item>
</style>

<style name="TextInputEditText.OutlinedBox.CustomFont" parent="Widget.MaterialComponents.TextInputEditText.OutlinedBox">
  <item name="android:fontFamily">@font/my_font</item>
</style>

<style name="CustomFontTextInputLayout" parent="Widget.Design.TextInputLayout">
  <item name="hintTextAppearance">@style/TextInputLayoutHintText</item>
  <item name="helperTextTextAppearance">@style/TextInputLayoutHelperText</item>
  <item name="errorTextAppearance">@style/TextInputLayoutErrorText</item>
</style>

<style name="TextInputLayoutHintText" parent="TextAppearance.Design.Hint">
  <item name="android:fontFamily">@font/my_font</item>
</style>

<style name="TextInputLayoutHelperText" parent="TextAppearance.Design.HelperText">
  <item name="android:fontFamily">@font/my_font</item>
</style>

<style name="TextInputLayoutErrorText" parent="TextAppearance.Design.Error">
  <item name="android:fontFamily">@font/my_font</item>
</style>
<!-- endregion -->

Then in xml layout:

<android.support.design.widget.TextInputLayout
    style="@style/TextInputLayout.OutlineBox.CustomFont"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/first_name"/>
</android.support.design.widget.TextInputLayout>

Here's the result:

enter image description here

azizbekian
  • 53,978
  • 11
  • 145
  • 225
  • Did not work for me for hint in password fields, because of issue described [here](https://github.com/chrisjenx/Calligraphy/issues/186#issuecomment-138376055). Had to set typeface in the code. – Vadim Kotov Apr 03 '19 at 11:25
  • it works for font change, but the form box style was gone. – aijogja Dec 24 '20 at 13:06
9

i just found a simple solution and it's worked for me:

in this way you can set the typeface to hint of any edit text:

in layout.xml :

 <android.support.design.widget.TextInputLayout
            android:id="@+id/text_input1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <EditText
                android:id="@+id/edt_user"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/username"/>
        </android.support.design.widget.TextInputLayout>

and in java class :

public class MainActivity extends AppCompatActivity {

EditText editText;
TextInputLayout textInputLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Typeface font_yekan= Typeface.createFromAsset(getAssets(), "fonts/byekan.ttf");
        textInputLayout= (TextInputLayout) findViewById(R.id.text_input1);
    textInputLayout.setTypeface(font_yekan);
      }
 }
imansdn
  • 341
  • 2
  • 7
  • 2
    Weird, this should have worked for me. I used a custom text input layout and only changed the typeface while initializing using the setTypeface() and still the error view has the older one. This is strange since it's there in the code that error view also takes typeface in the setTypeface(). Any clue what I might be missing? – AA_PV Jan 02 '17 at 19:25
7

Here is a custom class implementation for adneal's answer.

public class CustomTextInputLayout extends TextInputLayout {

    public CustomTextInputLayout(Context context) {
        super(context);
        initFont(context);
    }

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

    private void initFont(Context context) {
        final Typeface typeface = Typeface.createFromAsset(
                context.getAssets(), "fonts/YOUR_CUSTOM_FONT.ttf");

        EditText editText = getEditText();
        if (editText != null) {
            editText.setTypeface(typeface);
        }
        try {
            // Retrieve the CollapsingTextHelper Field
            final Field cthf = TextInputLayout.class.getDeclaredField("mCollapsingTextHelper");
            cthf.setAccessible(true);

            // Retrieve an instance of CollapsingTextHelper and its TextPaint
            final Object cth = cthf.get(this);
            final Field tpf = cth.getClass().getDeclaredField("mTextPaint");
            tpf.setAccessible(true);

            // Apply your Typeface to the CollapsingTextHelper TextPaint
            ((TextPaint) tpf.get(cth)).setTypeface(typeface);
        } catch (Exception ignored) {
            // Nothing to do
        }
    }
}

In your XML files now you need to use CustomTextInputLayout instead of TextInputLayout and it will work out of the box.

<your.package.CustomTextInputLayout
    android:id="@+id/textInputLayout_email"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <AutoCompleteTextView
        android:id="@+id/editText_email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/hint_email"
        android:inputType="textEmailAddress" />

Thanks adneal for the answer.

Community
  • 1
  • 1
Aleksandar Ilic
  • 1,339
  • 14
  • 19
5
final Typeface tf = Typeface.createFromAsset(getAssets(), "your_custom_font.ttf");
final TextInputLayout til = (TextInputLayout) findViewById(R.id.yourTextInputLayout);
til.getEditText().setTypeface(tf);
til.setTypeface(tf);
Tunaki
  • 116,530
  • 39
  • 281
  • 370
Ali
  • 111
  • 4
  • 5
  • Please explain something about your approach – etalon11 Jan 30 '16 at 18:39
  • 1
    @etalon11,A textview or edit text will be wrapped inside a `TextInputLayout` and applying a type face for the `TextInputLayout` will eventually apply the attributes to it children. I believe that this will work. – Satty Aug 12 '16 at 07:08
  • TextInputLayout member mEditText which getEditText() returns is different from mErrorView which is a TextView. This shouldn't working, please check. – AA_PV Jan 02 '17 at 19:24
1

There is a simpler way,

Create a new directory in your 'res' folder named 'font' and put a font in there. Then open your 'styles' file and create a new style :

<style name="customfontstyle" parent="@android:style/TextAppearance.Small">
        <item name="android:fontFamily">@font/poppins_regular</item>
    </style>

You can add more properties as well, such as textColor, textSize etc..

Then in your XML:

<android.support.design.widget.TextInputLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:hintTextAppearance="@style/customfontstyle"
       >

        <android.support.design.widget.TextInputEditText
            android:layout_width="220dp"
            android:layout_height="wrap_content"
            android:id="@+id/edit_phone_number"
            android:hint="@string/phone_number_label"

            android:inputType="number"
            />
    </android.support.design.widget.TextInputLayout>

I checked it and it works.

Danish Ajaib
  • 85
  • 1
  • 2
  • 8
1

I was looking for this, I found this way, using the support library:

Typeface typeface = ResourcesCompat.getFont(context, R.font.myfont);

and set this typeface to yout TextInpuLayout.

For me works like charm, I hope it helps others =]

Source: Documentation

Lucas Orso
  • 39
  • 5
1

Use can use style.xml like below:

Style file:

<style name="TextInputLayoutErrorStyle" parent="TextAppearance.Design.Error">
    <item name="fontFamily">@font/iran_sans_medium</item>
    <item name="android:fontFamily">@font/iran_sans_medium</item>
</style>

<style name="TextInputLayoutHintStyle" parent="TextAppearance.Design.Hint">
    <item name="fontFamily">@font/iran_sans_medium</item>
    <item name="android:fontFamily">@font/iran_sans_medium</item>
</style>

<style name="TextInputLayoutHelperStyle" parent="TextAppearance.Design.HelperText">
    <item name="fontFamily">@font/iran_sans_medium</item>
    <item name="android:fontFamily">@font/iran_sans_medium</item>
</style>

<style name="TextInputLayoutOutlinedBoxStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
    <item name="helperTextTextAppearance">@style/TextInputLayoutHelperStyle</item>
    <item name="errorTextAppearance">@style/TextInputLayoutErrorStyle</item>
    <item name="hintTextAppearance">@style/TextInputLayoutHintStyle</item>
</style>

Layout file:

<com.google.android.material.textfield.TextInputLayout
            android:layout_width="match_parent"
            android:layout_centerInParent="true"
            android:hint="@string/cardname_hint"
            android:layout_marginStart="30dp"
            android:layout_marginEnd="30dp"
            card_view:helperText="@string/cardname_helper"
            style="@style/TextInputLayoutOutlinedBoxStyle"
            android:layout_height="wrap_content">

            <com.google.android.material.textfield.TextInputEditText
                android:layout_width="match_parent"
                android:fontFamily="@font/iran_sans_medium"
                android:textColor="@color/colorTextPrimary"
                android:layout_height="wrap_content" />

</com.google.android.material.textfield.TextInputLayout>
Ehsan Mashhadi
  • 1,449
  • 12
  • 22
0

fixing a problem in @adneal answer: if setErrorEnabled is not set true, mErrorView would be null and if you set it false at any point the font would change back to default. so to fix it:

in you custom TextInputLayout override setErrorEnabled

@Override
public void setErrorEnabled(boolean enabled) {

    super.setErrorEnabled(enabled);

    if (enabled) {

        try {

            Field cthf = TextInputLayout.class.getDeclaredField("mErrorView");
            cthf.setAccessible(true);

            TextView error = (TextView) cthf.get(this);

            if (error != null)
                error.setTypeface(tf);


        } catch (Exception e) {

        }
    }
}
Ashkan Ghodrat
  • 2,960
  • 2
  • 30
  • 34
0

This is how i achieve this

edit_login_emailOrPhone.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(hasFocus)
            {
                textInputLayout_login_emailOrPhone.setTypeface(APSApplication.getInstance().getFonts().getTypefaceSemiBold());
            }else
            {
                textInputLayout_login_emailOrPhone.setTypeface(APSApplication.getInstance().getFonts().getTypefaceRegular());
            }
        }
    });
zohaib khaliq
  • 647
  • 10
  • 16
0

In case you too met an exotic requirement to set custom font ONLY to the floating label, and anything else didn't work for you as well, try this. This worked for me, at least for material lib ver. 1.3.0-alpha03.

@SuppressLint("RestrictedApi")
fun setHintFontFamily(view: TextInputLayout, fontRes: Int) {
    val font = ResourcesCompat.getFont(view.context, fontRes)!!

    try {
        val collapsingTextHelperField =
            view::class.java.getDeclaredField("collapsingTextHelper").apply {
                isAccessible = true
            }
        val collapsingTextHelper = collapsingTextHelperField.get(view) as CollapsingTextHelper

        collapsingTextHelper.collapsedTypeface = font
    } catch (e: Exception) {
    }
}

First we get the CollapsingTextHelper as in some other answers, but then we use its property collapsedTypeface that seems to do exactly what we need -- apply a font only to the floating label. Please note that this property's visibility is restricted to library group (that's why I used @SuppressLint). So the implementation details might change in the future.