How to set font custom font to Spinner text programmatically?

AndroidFontsSpinnerAndroid SpinnerAndroid Fonts

Android Problem Overview


I have a ttf font file in my assets folder. I know how to use it for textviews with:

Typeface externalFont=Typeface.createFromAsset(getAssets(), "fonts/HelveticaNeueLTCom-Lt.ttf");
textview1.setTypeface(externalFont);

I have defined look for my spinner text in it's own xml file (as usuall in android):

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@+android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:textColor="#ffffff"
android:gravity="center" 
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee" />

I just can't reference this textview from code, i always get null pointer exceptions. E.g. i tried:

TextView spinner_text=(TextView)findViewById(R.id.text1);
spinner_text.setTypeface(externalFont);

Is it possible to select my external font even for my spinner text defined in it's own xml?

Thank you.

EDIT with answer:

This works:

String [] items = new String[2];
    items[0]="Something1";
    items[1]="Something2";
        	 
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
	                R.layout.spinaca, items) {
		 
         public View getView(int position, View convertView, ViewGroup parent) {
                 View v = super.getView(position, convertView, parent);
                 
                 Typeface externalFont=Typeface.createFromAsset(getAssets(), "fonts/HelveticaNeueLTCom-Lt.ttf");
                 ((TextView) v).setTypeface(externalFont);
                 
                 return v;
         }

		 
         public View getDropDownView(int position,  View convertView,  ViewGroup parent) {
                  View v =super.getDropDownView(position, convertView, parent);
                 
                 Typeface externalFont=Typeface.createFromAsset(getAssets(), "fonts/HelveticaNeueLTCom-Lt.ttf");
                 ((TextView) v).setTypeface(externalFont);
                 v.setBackgroundColor(Color.GREEN);
                 
                 return v;
         }
 };
	 	                
	                
	 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 		     				     
	 spinner.setAdapter(adapter);

It may be necessary to add

import android.view.ViewGroup;

To your list of imports at the top of your file. For some reason Eclipse doesn't make this suggestion when it doesn't recognize the ViewGroup class involved in the code.

Android Solutions


Solution 1 - Android

This is what worked for me (using ideas both from CommonsWare's and gsanllorente's answers):

private static class MySpinnerAdapter extends ArrayAdapter<String> {
    // Initialise custom font, for example:
    Typeface font = Typeface.createFromAsset(getContext().getAssets(),
                        "fonts/Blambot.otf");

    // (In reality I used a manager which caches the Typeface objects)
    // Typeface font = FontManager.getInstance().getFont(getContext(), BLAMBOT);

    private MySpinnerAdapter(Context context, int resource, List<String> items) {
        super(context, resource, items);
    }

    // Affects default (closed) state of the spinner
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView view = (TextView) super.getView(position, convertView, parent);
        view.setTypeface(font);
        return view;
    }

    // Affects opened state of the spinner
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        TextView view = (TextView) super.getDropDownView(position, convertView, parent);
        view.setTypeface(font);
        return view;
    }
}

If you, like me, originally populated the Spinner using ArrayAdapter.createFromResource() and an array resource (as in Spinner documentation), then you'd use MySpinnerAdapter like this:

MySpinnerAdapter<String> adapter = new MySpinnerAdapter(
        getContext(),
        R.layout.view_spinner_item,
        Arrays.asList(getResources().getStringArray(R.array.my_array))
);
spinner.setAdapter(adapter);

Solution 2 - Android

You would apply the font through your own custom SpinnerAdapter, in getView() and getDropDownView().

Solution 3 - Android

If you implement your Adapter in another file, you can access the "getAssets()" function from the constructor of the Adapter, as you have the Context as a parameter.

public class YourItemAdapter extends ArrayAdapter<String> {
int recurso;
Typeface tf;

public YourItemAdapter(Context _context, int _resource,
		List<String> _items) {

	super(_context, _resource, _items);
	recurso=_resource;
	tf=Typeface.createFromAsset(_context.getAssets(),"font/digital-7.ttf");
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
	//You can use the new tf here.
    TextView spinner_text=(TextView)findViewById(R.id.text1);
	spinner_text.setTypeface(tf);
    }
}

Solution 4 - Android

Try this create custom custom_spinner.xml

<?xml version="1.0" encoding="utf-8"?>

<com.xxxx.xxxx.CheckedTextViewC
    
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/text1"
    style="?android:attr/spinnerDropDownItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textAlignment="center"
    android:paddingTop="5dp"
    android:paddingBottom="5dp"
    android:textSize="18sp"
    
    />

Create custom CheckedtextView like this

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

public class CheckedTextViewC extends CheckedTextView {

	public CheckedTextViewC(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}
	public CheckedTextViewC(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	public CheckedTextViewC(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	public void setTypeface(Typeface tf, int style) {
		if(!this.isInEditMode()){
	    Typeface normalTypeface = Typeface.createFromAsset(getContext().getAssets(), "font/Roboto-Light.ttf");
	    Typeface boldTypeface = Typeface.createFromAsset(getContext().getAssets(), "font/Roboto-Light.ttf");

	    if (style == Typeface.BOLD) {
	        super.setTypeface(boldTypeface/*, -1*/);
	    } else {
	        super.setTypeface(normalTypeface/*, -1*/);
	    }
	    }
		
	}
}

implemente the new layout

adapter= new ArrayAdapter <String>(Menu.this,R.layout.custom_spinner, list);

Solution 5 - Android

This is the continuation of my previous answer: https://stackoverflow.com/a/51100507/787399

> For the compatibility reasons, you can use the styles and customized > classes against the widgets in Android. Although above Android level > 15, new /res/font resource folders were introduced: > > Font Resources in Android

Step 1: declare item_spinner.xml

<?xml version="1.0" encoding="utf-8"?>
<com.my_package.custom_views.FontTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_spinner"
    style="@style/App_TextViewStyleSmall"
    android:layout_gravity="start|bottom"
    android:layout_marginLeft="@dimen/dp_5"
    android:layout_marginStart="@dimen/dp_5"
    android:ellipsize="marquee"
    android:gravity="start|bottom"
    android:padding="@dimen/dp_10"
    android:singleLine="true"
    android:textAlignment="inherit" />
    <!--declared in layout: item_spinner.xml-->
    <!-- removed attributes:  android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:textColor="@color/text_grey_light"
               android:textSize="@dimen/sp_14" -->
    <!--style="?android:attr/spinnerItemStyle"-->

step 2: declare item_spinner_dropdown.xml:

<?xml version="1.0" encoding="utf-8"?>
<com.my_package.custom_views.FontTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_spinner"
    style="@style/App_TextViewStyleSmall"
    android:layout_gravity="start|bottom"
    android:layout_marginLeft="@dimen/dp_5"
    android:layout_marginStart="@dimen/dp_5"
    android:ellipsize="marquee"
    android:gravity="start|bottom"
    android:padding="@dimen/dp_10"
    android:singleLine="true" />
    <!--declared in layout: item_spinner_dropdown.xml -->
    <!--removed: ?android:attr/dropdownListPreferredItemHeight-->
    <!--style="?android:attr/spinnerDropDownItemStyle"-->

Step 3: Use spinner in layout:

<LinearLayout
            android:id="@+id/ll_my_spinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/fet_bus_entity"
            android:layout_marginTop="@dimen/dp_12"
            android:orientation="horizontal">

            <com.my_package.custom_views.FontTextView
                style="@style/App_TextViewStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="start|bottom"
                android:gravity="start|bottom"
                android:text="@string/are_you_a" />

            <Spinner
                android:id="@+id/sp_my_spinner"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/dp_5"
                android:layout_marginStart="@dimen/dp_5"
                android:layout_gravity="end|bottom"
                android:spinnerMode="dropdown" />
        </LinearLayout>

[Note: id of the FontTextView is same in both the layouts, spinner item and drop down item]

Step 4: use it in the Activity/Fragment:

private void initSpinnerBusinessType(View rootView) {
        String[] ar_dd_bus_type = getResources().getStringArray(R.array.ar_dd_bus_type);
        List<String> lst_bus_type = Arrays.asList(ar_dd_bus_type);
        ArrayList<String> ar_bus_type = new ArrayList<>(lst_bus_type);
        //==

        ArrayAdapter<String> adapter = new ArrayAdapter<>(activity, R.layout.item_spinner, R.id.tv_spinner, ar_bus_type);
        adapter.setDropDownViewResource(R.layout
                .item_spinner_dropdown);
        //=========
        Spinner sp_my_spinner= rootView.findViewById(R.id.sp_my_spinner);
        sp_my_spinner.setAdapter(adapter);
    }

[ for further guidance see my other post: https://stackoverflow.com/a/51077569/787399 and https://stackoverflow.com/a/22164007/787399 ]

Solution 6 - Android

Please follow basic customization of FontTextView, FontEditView, FontRadioButton, FontCheckBox and FontButton.

[ For the exact answer, after seeing this guide, please see: https://stackoverflow.com/a/51113022/787399 ]

Use custom FontTextView, in ArrayAdapter item layout, like this:

public class FontEditText extends AppCompatEditText {

//    private String FONT = "fonts/roboto_regular.ttf";

    public FontEditText(Context context) {
        super(context, null);
//        setFontFromAsset(context, null, R.style.DefaultFontTextView);
//        FONT = getContext().getString(R.string.font_roboto_regular);
    }

    public FontEditText(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setFontFromAsset(context, attrs, R.attr.fetFontStyle);
    }

    public FontEditText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setFontFromAsset(context, attrs, defStyleAttr);
    }

    private void setFontFromAsset(Context context, AttributeSet attrs, int defStyle) {
        BaseActivity activity = (BaseActivity)((MyApplication) context.getApplicationContext()).getCurrentActivity();
        FontAndLocaleManager fontAndLocaleManager = activity.getFontAndLocaleManager();
        fontAndLocaleManager.setFontFromAsset(this, R.styleable.FontEditText, R.styleable.FontEditText_fetFontFace, attrs, defStyle);
    }
}

use the code:

public void setFontFromAsset(View view, int[] resViewStyleable, int resStyleableViewFontFace, AttributeSet attrs, int defStyle) {
        String strFont = null;
        Typeface tfFontFace = null;
        String strButton = FontButton.class.getCanonicalName(),
                strTextView = FontTextView.class.getCanonicalName(),
                strEditText = FontEditText.class.getCanonicalName(),
                strView = view.getClass().getCanonicalName();
        try {
            if (view.isInEditMode()) {
                return;
            }
            //R.string.font_roboto_regular
            strFont = context.getString(R.string.font_roboto_regular);
            tfFontFace = Typeface.createFromAsset(context.getAssets(), strFont);

            //AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes
            //R.styleable.FontButton
            TypedArray a = context.obtainStyledAttributes(attrs, resViewStyleable, defStyle, 0);
            //R.styleable.FontButton_btFontFace
            String derivedFont = a.getString(resStyleableViewFontFace);

            a.recycle();

            //==
            try {
                if (derivedFont != null) {
                    Typeface derivedFontFace = Typeface.createFromAsset(context.getAssets(), derivedFont);
                    if (strView.equals(strButton)) {
                        ((FontButton) view).setTypeface(derivedFontFace);
                    } else if (strView.equals(strTextView)) {
                        ((FontTextView) view).setTypeface(derivedFontFace);
                    } else if (strView.equals(strEditText)) {
                        ((FontEditText) view).setTypeface(derivedFontFace);
                    }
                    return;
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (strFont != null && tfFontFace != null) {
                if (strView.equals(strButton)) {
                    ((FontButton) view).setTypeface(tfFontFace);
                } else if (strView.equals(strTextView)) {
                    ((FontTextView) view).setTypeface(tfFontFace);
                } else if (strView.equals(strEditText)) {
                    ((FontEditText) view).setTypeface(tfFontFace);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

Describe style and attributes in respective xmls:

<!--FontTextView-->
    <declare-styleable name="FontTextViewStyle">
        <!-- Style of the FontTextView. -->
        <attr name="ftvFontStyle" format="reference"/>

    </declare-styleable>
    <declare-styleable name="FontTextView">
        <!-- Font face of FontTextView. -->
        <attr name="ftvFontFace" format="reference"/>
    </declare-styleable>

and

<!--FontTextView-->
<style name="StyledFontTextView" parent="@android:style/Theme.Light">
<item name="ftvFontStyle">@style/DefaultFontTextView</item>
</style>

<style name="DefaultFontTextView">
<item name="ftvFontFace">@string/font_roboto_regular</item>
</style>

define some more styles:

<style name="App_TextViewStyle" parent="@android:style/Widget.TextView">
        <item name="android:textColor">@color/text_grey</item>
        <item name="android:textSize">@dimen/sp_20</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>
    <style name="App_TextViewStyleMedium" parent="@android:style/Widget.TextView">
        <item name="android:textColor">@color/text_hint</item>
        <item name="android:textSize">@dimen/sp_18</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>
    <style name="App_TextViewStyleSmall" parent="@android:style/Widget.TextView">
        <item name="android:textColor">@color/text_grey_light</item>
        <item name="android:textSize">@dimen/sp_14</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

mention fonts in your strings.xml:

...
<string name="font_roboto_regular">fonts/roboto_regular.ttf</string>
...

and use in the layouts saving some code and time:

<com.mypackage.custom_views.FontTextView
                style="@style/App_TextViewStyleMedium"
                android:layout_gravity="start|bottom"
                android:gravity="start|bottom"
                app:fetFontFace="@string/font_roboto_regular"
                android:text="@string/are_you_a" />

At Android level 16 and above, all this is simplified, because now you can keep TTF and other font resources in /res/font folder, rather than in assets. That removes most of the custom classes, styles and attributes, see:

Font Resources in Android

Happy Coding with style!! :-)

Solution 7 - Android

Guys I found an awesome solution, I wrap orignal adapter by helper like

Use this class SpinnerViewHelper and happy progamming with Android

new SpinnerViewHelper((Spinner)view.findViewById(R.id.labelSurveyNumber),(parent, v, position, id) -> UrduFontHelper.set(v));

Lambda expression is used.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDixieFlatlineView Question on Stackoverflow
Solution 1 - AndroidJonikView Answer on Stackoverflow
Solution 2 - AndroidCommonsWareView Answer on Stackoverflow
Solution 3 - AndroidgsanllorenteView Answer on Stackoverflow
Solution 4 - Androidjoe1327View Answer on Stackoverflow
Solution 5 - AndroidAbhinav SaxenaView Answer on Stackoverflow
Solution 6 - AndroidAbhinav SaxenaView Answer on Stackoverflow
Solution 7 - AndroidQamar4PView Answer on Stackoverflow