如何设置字体自定义字体的 Spinner 文本编程?

我有一个 ttf 字体文件在我的资产文件夹。我知道如何使用它的文本视图与:

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

我已经在自己的 xml 文件中定义了 look for my spinner text (通常在 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" />

我只是不能从代码中引用这个文本视图,我总是得到空指针异常。例如:

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

是否有可能选择我的外部字体,即使我的微调文本定义在它自己的 xml?

谢谢你。

编辑回答:

这种方法是有效的:

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

可能有必要加上

import android.view.ViewGroup;

导入到文件顶部的导入列表中。由于某些原因,当 Eclipse 不能识别代码中涉及的 ViewGroup 类时,它不会提出这个建议。

78738 次浏览

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

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

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

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

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.

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!! :-)

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 ]